1 /****************************************************************************** 2 * 3 * Module Name: asltree - parse tree management 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2016, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44 #include "aslcompiler.h" 45 #include "aslcompiler.y.h" 46 #include "acapps.h" 47 #include <time.h> 48 49 #define _COMPONENT ACPI_COMPILER 50 ACPI_MODULE_NAME ("asltree") 51 52 /* Local prototypes */ 53 54 static ACPI_PARSE_OBJECT * 55 TrGetNextNode ( 56 void); 57 58 59 /******************************************************************************* 60 * 61 * FUNCTION: TrGetNextNode 62 * 63 * PARAMETERS: None 64 * 65 * RETURN: New parse node. Aborts on allocation failure 66 * 67 * DESCRIPTION: Allocate a new parse node for the parse tree. Bypass the local 68 * dynamic memory manager for performance reasons (This has a 69 * major impact on the speed of the compiler.) 70 * 71 ******************************************************************************/ 72 73 static ACPI_PARSE_OBJECT * 74 TrGetNextNode ( 75 void) 76 { 77 ASL_CACHE_INFO *Cache; 78 79 80 if (Gbl_ParseOpCacheNext >= Gbl_ParseOpCacheLast) 81 { 82 /* Allocate a new buffer */ 83 84 Cache = UtLocalCalloc (sizeof (Cache->Next) + 85 (sizeof (ACPI_PARSE_OBJECT) * ASL_PARSEOP_CACHE_SIZE)); 86 87 /* Link new cache buffer to head of list */ 88 89 Cache->Next = Gbl_ParseOpCacheList; 90 Gbl_ParseOpCacheList = Cache; 91 92 /* Setup cache management pointers */ 93 94 Gbl_ParseOpCacheNext = ACPI_CAST_PTR (ACPI_PARSE_OBJECT, Cache->Buffer); 95 Gbl_ParseOpCacheLast = Gbl_ParseOpCacheNext + ASL_PARSEOP_CACHE_SIZE; 96 } 97 98 Gbl_ParseOpCount++; 99 return (Gbl_ParseOpCacheNext++); 100 } 101 102 103 /******************************************************************************* 104 * 105 * FUNCTION: TrAllocateNode 106 * 107 * PARAMETERS: ParseOpcode - Opcode to be assigned to the node 108 * 109 * RETURN: New parse node. Aborts on allocation failure 110 * 111 * DESCRIPTION: Allocate and initialize a new parse node for the parse tree 112 * 113 ******************************************************************************/ 114 115 ACPI_PARSE_OBJECT * 116 TrAllocateNode ( 117 UINT32 ParseOpcode) 118 { 119 ACPI_PARSE_OBJECT *Op; 120 121 122 Op = TrGetNextNode (); 123 124 Op->Asl.ParseOpcode = (UINT16) ParseOpcode; 125 Op->Asl.Filename = Gbl_Files[ASL_FILE_INPUT].Filename; 126 Op->Asl.LineNumber = Gbl_CurrentLineNumber; 127 Op->Asl.LogicalLineNumber = Gbl_LogicalLineNumber; 128 Op->Asl.LogicalByteOffset = Gbl_CurrentLineOffset; 129 Op->Asl.Column = Gbl_CurrentColumn; 130 131 UtSetParseOpName (Op); 132 return (Op); 133 } 134 135 136 /******************************************************************************* 137 * 138 * FUNCTION: TrReleaseNode 139 * 140 * PARAMETERS: Op - Op to be released 141 * 142 * RETURN: None 143 * 144 * DESCRIPTION: "release" a node. In truth, nothing is done since the node 145 * is part of a larger buffer 146 * 147 ******************************************************************************/ 148 149 void 150 TrReleaseNode ( 151 ACPI_PARSE_OBJECT *Op) 152 { 153 154 return; 155 } 156 157 158 /******************************************************************************* 159 * 160 * FUNCTION: TrSetCurrentFilename 161 * 162 * PARAMETERS: Op - An existing parse node 163 * 164 * RETURN: None 165 * 166 * DESCRIPTION: Save the include file filename. Used for debug output only. 167 * 168 ******************************************************************************/ 169 170 void 171 TrSetCurrentFilename ( 172 ACPI_PARSE_OBJECT *Op) 173 { 174 Op->Asl.Filename = Gbl_PreviousIncludeFilename; 175 } 176 177 178 /******************************************************************************* 179 * 180 * FUNCTION: TrUpdateNode 181 * 182 * PARAMETERS: ParseOpcode - New opcode to be assigned to the node 183 * Op - An existing parse node 184 * 185 * RETURN: The updated node 186 * 187 * DESCRIPTION: Change the parse opcode assigned to a node. Usually used to 188 * change an opcode to DEFAULT_ARG so that the node is ignored 189 * during the code generation. Also used to set generic integers 190 * to a specific size (8, 16, 32, or 64 bits) 191 * 192 ******************************************************************************/ 193 194 ACPI_PARSE_OBJECT * 195 TrUpdateNode ( 196 UINT32 ParseOpcode, 197 ACPI_PARSE_OBJECT *Op) 198 { 199 200 if (!Op) 201 { 202 return (NULL); 203 } 204 205 DbgPrint (ASL_PARSE_OUTPUT, 206 "\nUpdateNode: Old - %s, New - %s\n", 207 UtGetOpName (Op->Asl.ParseOpcode), 208 UtGetOpName (ParseOpcode)); 209 210 /* Assign new opcode and name */ 211 212 if (Op->Asl.ParseOpcode == PARSEOP_ONES) 213 { 214 switch (ParseOpcode) 215 { 216 case PARSEOP_BYTECONST: 217 218 Op->Asl.Value.Integer = ACPI_UINT8_MAX; 219 break; 220 221 case PARSEOP_WORDCONST: 222 223 Op->Asl.Value.Integer = ACPI_UINT16_MAX; 224 break; 225 226 case PARSEOP_DWORDCONST: 227 228 Op->Asl.Value.Integer = ACPI_UINT32_MAX; 229 break; 230 231 /* Don't need to do the QWORD case */ 232 233 default: 234 235 /* Don't care about others */ 236 break; 237 } 238 } 239 240 Op->Asl.ParseOpcode = (UINT16) ParseOpcode; 241 UtSetParseOpName (Op); 242 243 /* 244 * For the BYTE, WORD, and DWORD constants, make sure that the integer 245 * that was passed in will actually fit into the data type 246 */ 247 switch (ParseOpcode) 248 { 249 case PARSEOP_BYTECONST: 250 251 UtCheckIntegerRange (Op, 0x00, ACPI_UINT8_MAX); 252 Op->Asl.Value.Integer &= ACPI_UINT8_MAX; 253 break; 254 255 case PARSEOP_WORDCONST: 256 257 UtCheckIntegerRange (Op, 0x00, ACPI_UINT16_MAX); 258 Op->Asl.Value.Integer &= ACPI_UINT16_MAX; 259 break; 260 261 case PARSEOP_DWORDCONST: 262 263 UtCheckIntegerRange (Op, 0x00, ACPI_UINT32_MAX); 264 Op->Asl.Value.Integer &= ACPI_UINT32_MAX; 265 break; 266 267 default: 268 269 /* Don't care about others, don't need to check QWORD */ 270 271 break; 272 } 273 274 return (Op); 275 } 276 277 278 /******************************************************************************* 279 * 280 * FUNCTION: TrPrintNodeCompileFlags 281 * 282 * PARAMETERS: Flags - Flags word to be decoded 283 * 284 * RETURN: None 285 * 286 * DESCRIPTION: Decode a flags word to text. Displays all flags that are set. 287 * 288 ******************************************************************************/ 289 290 void 291 TrPrintNodeCompileFlags ( 292 UINT32 Flags) 293 { 294 UINT32 i; 295 UINT32 FlagBit = 1; 296 char *FlagName = NULL; 297 298 299 for (i = 0; i < 32; i++) 300 { 301 switch (Flags & FlagBit) 302 { 303 case NODE_VISITED: 304 305 FlagName = "NODE_VISITED"; 306 break; 307 308 case NODE_AML_PACKAGE: 309 310 FlagName = "NODE_AML_PACKAGE"; 311 break; 312 313 case NODE_IS_TARGET: 314 315 FlagName = "NODE_IS_TARGET"; 316 break; 317 318 case NODE_IS_RESOURCE_DESC: 319 320 FlagName = "NODE_IS_RESOURCE_DESC"; 321 break; 322 323 case NODE_IS_RESOURCE_FIELD: 324 325 FlagName = "NODE_IS_RESOURCE_FIELD"; 326 break; 327 328 case NODE_HAS_NO_EXIT: 329 330 FlagName = "NODE_HAS_NO_EXIT"; 331 break; 332 333 case NODE_IF_HAS_NO_EXIT: 334 335 FlagName = "NODE_IF_HAS_NO_EXIT"; 336 break; 337 338 case NODE_NAME_INTERNALIZED: 339 340 FlagName = "NODE_NAME_INTERNALIZED"; 341 break; 342 343 case NODE_METHOD_NO_RETVAL: 344 345 FlagName = "NODE_METHOD_NO_RETVAL"; 346 break; 347 348 case NODE_METHOD_SOME_NO_RETVAL: 349 350 FlagName = "NODE_METHOD_SOME_NO_RETVAL"; 351 break; 352 353 case NODE_RESULT_NOT_USED: 354 355 FlagName = "NODE_RESULT_NOT_USED"; 356 break; 357 358 case NODE_METHOD_TYPED: 359 360 FlagName = "NODE_METHOD_TYPED"; 361 break; 362 363 case NODE_COULD_NOT_REDUCE: 364 365 FlagName = "NODE_COULD_NOT_REDUCE"; 366 break; 367 368 case NODE_COMPILE_TIME_CONST: 369 370 FlagName = "NODE_COMPILE_TIME_CONST"; 371 break; 372 373 case NODE_IS_TERM_ARG: 374 375 FlagName = "NODE_IS_TERM_ARG"; 376 break; 377 378 case NODE_WAS_ONES_OP: 379 380 FlagName = "NODE_WAS_ONES_OP"; 381 break; 382 383 case NODE_IS_NAME_DECLARATION: 384 385 FlagName = "NODE_IS_NAME_DECLARATION"; 386 break; 387 388 case NODE_COMPILER_EMITTED: 389 390 FlagName = "NODE_COMPILER_EMITTED"; 391 break; 392 393 case NODE_IS_DUPLICATE: 394 395 FlagName = "NODE_IS_DUPLICATE"; 396 break; 397 398 case NODE_IS_RESOURCE_DATA: 399 400 FlagName = "NODE_IS_RESOURCE_DATA"; 401 break; 402 403 case NODE_IS_NULL_RETURN: 404 405 FlagName = "NODE_IS_NULL_RETURN"; 406 break; 407 408 default: 409 break; 410 } 411 412 if (FlagName) 413 { 414 DbgPrint (ASL_PARSE_OUTPUT, " %s", FlagName); 415 FlagName = NULL; 416 } 417 418 FlagBit <<= 1; 419 } 420 } 421 422 423 /******************************************************************************* 424 * 425 * FUNCTION: TrSetNodeFlags 426 * 427 * PARAMETERS: Op - An existing parse node 428 * Flags - New flags word 429 * 430 * RETURN: The updated parser op 431 * 432 * DESCRIPTION: Set bits in the node flags word. Will not clear bits, only set 433 * 434 ******************************************************************************/ 435 436 ACPI_PARSE_OBJECT * 437 TrSetNodeFlags ( 438 ACPI_PARSE_OBJECT *Op, 439 UINT32 Flags) 440 { 441 442 if (!Op) 443 { 444 return (NULL); 445 } 446 447 DbgPrint (ASL_PARSE_OUTPUT, 448 "\nSetNodeFlags: %s Op %p, %8.8X", Op->Asl.ParseOpName, Op, Flags); 449 450 TrPrintNodeCompileFlags (Flags); 451 DbgPrint (ASL_PARSE_OUTPUT, "\n\n"); 452 453 Op->Asl.CompileFlags |= Flags; 454 return (Op); 455 } 456 457 458 /******************************************************************************* 459 * 460 * FUNCTION: TrSetNodeAmlLength 461 * 462 * PARAMETERS: Op - An existing parse node 463 * Length - AML Length 464 * 465 * RETURN: The updated parser op 466 * 467 * DESCRIPTION: Set the AML Length in a node. Used by the parser to indicate 468 * the presence of a node that must be reduced to a fixed length 469 * constant. 470 * 471 ******************************************************************************/ 472 473 ACPI_PARSE_OBJECT * 474 TrSetNodeAmlLength ( 475 ACPI_PARSE_OBJECT *Op, 476 UINT32 Length) 477 { 478 479 DbgPrint (ASL_PARSE_OUTPUT, 480 "\nSetNodeAmlLength: Op %p, %8.8X\n", Op, Length); 481 482 if (!Op) 483 { 484 return (NULL); 485 } 486 487 Op->Asl.AmlLength = Length; 488 return (Op); 489 } 490 491 492 /******************************************************************************* 493 * 494 * FUNCTION: TrSetEndLineNumber 495 * 496 * PARAMETERS: Op - An existing parse node 497 * 498 * RETURN: None. 499 * 500 * DESCRIPTION: Set the ending line numbers (file line and logical line) of a 501 * parse node to the current line numbers. 502 * 503 ******************************************************************************/ 504 505 void 506 TrSetEndLineNumber ( 507 ACPI_PARSE_OBJECT *Op) 508 { 509 510 /* If the end line # is already set, just return */ 511 512 if (Op->Asl.EndLine) 513 { 514 return; 515 } 516 517 Op->Asl.EndLine = Gbl_CurrentLineNumber; 518 Op->Asl.EndLogicalLine = Gbl_LogicalLineNumber; 519 } 520 521 522 /******************************************************************************* 523 * 524 * FUNCTION: TrCreateAssignmentNode 525 * 526 * PARAMETERS: Target - Assignment target 527 * Source - Assignment source 528 * 529 * RETURN: Pointer to the new node. Aborts on allocation failure 530 * 531 * DESCRIPTION: Implements the C-style '=' operator. It changes the parse 532 * tree if possible to utilize the last argument of the math 533 * operators which is a target operand -- thus saving invocation 534 * of and additional Store() operator. An optimization. 535 * 536 ******************************************************************************/ 537 538 ACPI_PARSE_OBJECT * 539 TrCreateAssignmentNode ( 540 ACPI_PARSE_OBJECT *Target, 541 ACPI_PARSE_OBJECT *Source) 542 { 543 ACPI_PARSE_OBJECT *TargetOp; 544 ACPI_PARSE_OBJECT *SourceOp1; 545 ACPI_PARSE_OBJECT *SourceOp2; 546 ACPI_PARSE_OBJECT *Operator; 547 548 549 DbgPrint (ASL_PARSE_OUTPUT, 550 "\nTrCreateAssignmentNode Line [%u to %u] Source %s Target %s\n", 551 Source->Asl.LineNumber, Source->Asl.EndLine, 552 UtGetOpName (Source->Asl.ParseOpcode), 553 UtGetOpName (Target->Asl.ParseOpcode)); 554 555 TrSetNodeFlags (Target, NODE_IS_TARGET); 556 557 switch (Source->Asl.ParseOpcode) 558 { 559 /* 560 * Only these operators can be optimized because they have 561 * a target operand 562 */ 563 case PARSEOP_ADD: 564 case PARSEOP_AND: 565 case PARSEOP_DIVIDE: 566 case PARSEOP_INDEX: 567 case PARSEOP_MOD: 568 case PARSEOP_MULTIPLY: 569 case PARSEOP_NOT: 570 case PARSEOP_OR: 571 case PARSEOP_SHIFTLEFT: 572 case PARSEOP_SHIFTRIGHT: 573 case PARSEOP_SUBTRACT: 574 case PARSEOP_XOR: 575 576 break; 577 578 /* Otherwise, just create a normal Store operator */ 579 580 default: 581 582 goto CannotOptimize; 583 } 584 585 /* 586 * Transform the parse tree such that the target is moved to the 587 * last operand of the operator 588 */ 589 SourceOp1 = Source->Asl.Child; 590 SourceOp2 = SourceOp1->Asl.Next; 591 592 /* NOT only has one operand, but has a target */ 593 594 if (Source->Asl.ParseOpcode == PARSEOP_NOT) 595 { 596 SourceOp2 = SourceOp1; 597 } 598 599 /* DIVIDE has an extra target operand (remainder) */ 600 601 if (Source->Asl.ParseOpcode == PARSEOP_DIVIDE) 602 { 603 SourceOp2 = SourceOp2->Asl.Next; 604 } 605 606 TargetOp = SourceOp2->Asl.Next; 607 608 /* 609 * Can't perform this optimization if there already is a target 610 * for the operator (ZERO is a "no target" placeholder). 611 */ 612 if (TargetOp->Asl.ParseOpcode != PARSEOP_ZERO) 613 { 614 goto CannotOptimize; 615 } 616 617 /* Link in the target as the final operand */ 618 619 SourceOp2->Asl.Next = Target; 620 Target->Asl.Parent = Source; 621 622 return (Source); 623 624 625 CannotOptimize: 626 627 Operator = TrAllocateNode (PARSEOP_STORE); 628 TrLinkChildren (Operator, 2, Source, Target); 629 630 /* Set the appropriate line numbers for the new node */ 631 632 Operator->Asl.LineNumber = Target->Asl.LineNumber; 633 Operator->Asl.LogicalLineNumber = Target->Asl.LogicalLineNumber; 634 Operator->Asl.LogicalByteOffset = Target->Asl.LogicalByteOffset; 635 Operator->Asl.Column = Target->Asl.Column; 636 637 return (Operator); 638 } 639 640 641 /******************************************************************************* 642 * 643 * FUNCTION: TrCreateLeafNode 644 * 645 * PARAMETERS: ParseOpcode - New opcode to be assigned to the node 646 * 647 * RETURN: Pointer to the new node. Aborts on allocation failure 648 * 649 * DESCRIPTION: Create a simple leaf node (no children or peers, and no value 650 * assigned to the node) 651 * 652 ******************************************************************************/ 653 654 ACPI_PARSE_OBJECT * 655 TrCreateLeafNode ( 656 UINT32 ParseOpcode) 657 { 658 ACPI_PARSE_OBJECT *Op; 659 660 661 Op = TrAllocateNode (ParseOpcode); 662 663 DbgPrint (ASL_PARSE_OUTPUT, 664 "\nCreateLeafNode Ln/Col %u/%u NewNode %p Op %s\n\n", 665 Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName (ParseOpcode)); 666 667 return (Op); 668 } 669 670 671 /******************************************************************************* 672 * 673 * FUNCTION: TrCreateNullTarget 674 * 675 * PARAMETERS: None 676 * 677 * RETURN: Pointer to the new node. Aborts on allocation failure 678 * 679 * DESCRIPTION: Create a "null" target node. This is defined by the ACPI 680 * specification to be a zero AML opcode, and indicates that 681 * no target has been specified for the parent operation 682 * 683 ******************************************************************************/ 684 685 ACPI_PARSE_OBJECT * 686 TrCreateNullTarget ( 687 void) 688 { 689 ACPI_PARSE_OBJECT *Op; 690 691 692 Op = TrAllocateNode (PARSEOP_ZERO); 693 Op->Asl.CompileFlags |= (NODE_IS_TARGET | NODE_COMPILE_TIME_CONST); 694 695 DbgPrint (ASL_PARSE_OUTPUT, 696 "\nCreateNullTarget Ln/Col %u/%u NewNode %p Op %s\n", 697 Op->Asl.LineNumber, Op->Asl.Column, Op, 698 UtGetOpName (Op->Asl.ParseOpcode)); 699 700 return (Op); 701 } 702 703 704 /******************************************************************************* 705 * 706 * FUNCTION: TrCreateConstantLeafNode 707 * 708 * PARAMETERS: ParseOpcode - The constant opcode 709 * 710 * RETURN: Pointer to the new node. Aborts on allocation failure 711 * 712 * DESCRIPTION: Create a leaf node (no children or peers) for one of the 713 * special constants - __LINE__, __FILE__, and __DATE__. 714 * 715 * Note: An implemenation of __FUNC__ cannot happen here because we don't 716 * have a full parse tree at this time and cannot find the parent control 717 * method. If it is ever needed, __FUNC__ must be implemented later, after 718 * the parse tree has been fully constructed. 719 * 720 ******************************************************************************/ 721 722 ACPI_PARSE_OBJECT * 723 TrCreateConstantLeafNode ( 724 UINT32 ParseOpcode) 725 { 726 ACPI_PARSE_OBJECT *Op = NULL; 727 time_t CurrentTime; 728 char *StaticTimeString; 729 char *TimeString; 730 char *Filename; 731 732 733 switch (ParseOpcode) 734 { 735 case PARSEOP___LINE__: 736 737 Op = TrAllocateNode (PARSEOP_INTEGER); 738 Op->Asl.Value.Integer = Op->Asl.LineNumber; 739 break; 740 741 case PARSEOP___PATH__: 742 743 Op = TrAllocateNode (PARSEOP_STRING_LITERAL); 744 745 /* Op.Asl.Filename contains the full pathname to the file */ 746 747 Op->Asl.Value.String = Op->Asl.Filename; 748 break; 749 750 case PARSEOP___FILE__: 751 752 Op = TrAllocateNode (PARSEOP_STRING_LITERAL); 753 754 /* Get the simple filename from the full path */ 755 756 FlSplitInputPathname (Op->Asl.Filename, NULL, &Filename); 757 Op->Asl.Value.String = Filename; 758 break; 759 760 case PARSEOP___DATE__: 761 762 Op = TrAllocateNode (PARSEOP_STRING_LITERAL); 763 764 /* Get a copy of the current time */ 765 766 CurrentTime = time (NULL); 767 StaticTimeString = ctime (&CurrentTime); 768 TimeString = UtLocalCalloc (strlen (StaticTimeString) + 1); 769 strcpy (TimeString, StaticTimeString); 770 771 TimeString[strlen(TimeString) -1] = 0; /* Remove trailing newline */ 772 Op->Asl.Value.String = TimeString; 773 break; 774 775 default: /* This would be an internal error */ 776 777 return (NULL); 778 } 779 780 DbgPrint (ASL_PARSE_OUTPUT, 781 "\nCreateConstantLeafNode Ln/Col %u/%u NewNode %p " 782 "Op %s Value %8.8X%8.8X \n", 783 Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName (ParseOpcode), 784 ACPI_FORMAT_UINT64 (Op->Asl.Value.Integer)); 785 return (Op); 786 } 787 788 789 /******************************************************************************* 790 * 791 * FUNCTION: TrCreateTargetOperand 792 * 793 * PARAMETERS: OriginalOp - Op to be copied 794 * 795 * RETURN: Pointer to the new node. Aborts on allocation failure 796 * 797 * DESCRIPTION: Copy an existing node (and subtree). Used in ASL+ (C-style) 798 * expressions where the target is the same as one of the 799 * operands. A new node and subtree must be created from the 800 * original so that the parse tree can be linked properly. 801 * 802 * NOTE: This code is specific to target operands that are the last 803 * operand in an ASL/AML operator. Meaning that the top-level 804 * parse Op in a possible subtree has a NULL Next pointer. 805 * This simplifies the recursion. 806 * 807 * Subtree example: 808 * DeRefOf (Local1) += 32 809 * 810 * This gets converted to: 811 * Add (DeRefOf (Local1), 32, DeRefOf (Local1)) 812 * 813 * Each DeRefOf has a single child, Local1. Even more complex 814 * subtrees can be created via the Index and DeRefOf operators. 815 * 816 ******************************************************************************/ 817 818 ACPI_PARSE_OBJECT * 819 TrCreateTargetOperand ( 820 ACPI_PARSE_OBJECT *OriginalOp, 821 ACPI_PARSE_OBJECT *ParentOp) 822 { 823 ACPI_PARSE_OBJECT *Op; 824 825 826 if (!OriginalOp) 827 { 828 return (NULL); 829 } 830 831 Op = TrGetNextNode (); 832 833 /* Copy the pertinent values (omit link pointer fields) */ 834 835 Op->Asl.Value = OriginalOp->Asl.Value; 836 Op->Asl.Filename = OriginalOp->Asl.Filename; 837 Op->Asl.LineNumber = OriginalOp->Asl.LineNumber; 838 Op->Asl.LogicalLineNumber = OriginalOp->Asl.LogicalLineNumber; 839 Op->Asl.LogicalByteOffset = OriginalOp->Asl.LogicalByteOffset; 840 Op->Asl.Column = OriginalOp->Asl.Column; 841 Op->Asl.Flags = OriginalOp->Asl.Flags; 842 Op->Asl.CompileFlags = OriginalOp->Asl.CompileFlags; 843 Op->Asl.AmlOpcode = OriginalOp->Asl.AmlOpcode; 844 Op->Asl.ParseOpcode = OriginalOp->Asl.ParseOpcode; 845 Op->Asl.Parent = ParentOp; 846 UtSetParseOpName (Op); 847 848 /* Copy a possible subtree below this node */ 849 850 if (OriginalOp->Asl.Child) 851 { 852 Op->Asl.Child = TrCreateTargetOperand (OriginalOp->Asl.Child, Op); 853 } 854 855 if (OriginalOp->Asl.Next) /* Null for top-level node */ 856 { 857 Op->Asl.Next = TrCreateTargetOperand (OriginalOp->Asl.Next, ParentOp); 858 } 859 860 return (Op); 861 } 862 863 864 /******************************************************************************* 865 * 866 * FUNCTION: TrCreateValuedLeafNode 867 * 868 * PARAMETERS: ParseOpcode - New opcode to be assigned to the node 869 * Value - Value to be assigned to the node 870 * 871 * RETURN: Pointer to the new node. Aborts on allocation failure 872 * 873 * DESCRIPTION: Create a leaf node (no children or peers) with a value 874 * assigned to it 875 * 876 ******************************************************************************/ 877 878 ACPI_PARSE_OBJECT * 879 TrCreateValuedLeafNode ( 880 UINT32 ParseOpcode, 881 UINT64 Value) 882 { 883 ACPI_PARSE_OBJECT *Op; 884 885 886 Op = TrAllocateNode (ParseOpcode); 887 888 DbgPrint (ASL_PARSE_OUTPUT, 889 "\nCreateValuedLeafNode Ln/Col %u/%u NewNode %p " 890 "Op %s Value %8.8X%8.8X ", 891 Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName(ParseOpcode), 892 ACPI_FORMAT_UINT64 (Value)); 893 Op->Asl.Value.Integer = Value; 894 895 switch (ParseOpcode) 896 { 897 case PARSEOP_STRING_LITERAL: 898 899 DbgPrint (ASL_PARSE_OUTPUT, "STRING->%s", Value); 900 break; 901 902 case PARSEOP_NAMESEG: 903 904 DbgPrint (ASL_PARSE_OUTPUT, "NAMESEG->%s", Value); 905 break; 906 907 case PARSEOP_NAMESTRING: 908 909 DbgPrint (ASL_PARSE_OUTPUT, "NAMESTRING->%s", Value); 910 break; 911 912 case PARSEOP_EISAID: 913 914 DbgPrint (ASL_PARSE_OUTPUT, "EISAID->%s", Value); 915 break; 916 917 case PARSEOP_METHOD: 918 919 DbgPrint (ASL_PARSE_OUTPUT, "METHOD"); 920 break; 921 922 case PARSEOP_INTEGER: 923 924 DbgPrint (ASL_PARSE_OUTPUT, "INTEGER->%8.8X%8.8X", 925 ACPI_FORMAT_UINT64 (Value)); 926 break; 927 928 default: 929 930 break; 931 } 932 933 DbgPrint (ASL_PARSE_OUTPUT, "\n\n"); 934 return (Op); 935 } 936 937 938 /******************************************************************************* 939 * 940 * FUNCTION: TrCreateNode 941 * 942 * PARAMETERS: ParseOpcode - Opcode to be assigned to the node 943 * NumChildren - Number of children to follow 944 * ... - A list of child nodes to link to the new 945 * node. NumChildren long. 946 * 947 * RETURN: Pointer to the new node. Aborts on allocation failure 948 * 949 * DESCRIPTION: Create a new parse node and link together a list of child 950 * nodes underneath the new node. 951 * 952 ******************************************************************************/ 953 954 ACPI_PARSE_OBJECT * 955 TrCreateNode ( 956 UINT32 ParseOpcode, 957 UINT32 NumChildren, 958 ...) 959 { 960 ACPI_PARSE_OBJECT *Op; 961 ACPI_PARSE_OBJECT *Child; 962 ACPI_PARSE_OBJECT *PrevChild; 963 va_list ap; 964 UINT32 i; 965 BOOLEAN FirstChild; 966 967 968 va_start (ap, NumChildren); 969 970 /* Allocate one new node */ 971 972 Op = TrAllocateNode (ParseOpcode); 973 974 DbgPrint (ASL_PARSE_OUTPUT, 975 "\nCreateNode Ln/Col %u/%u NewParent %p Child %u Op %s ", 976 Op->Asl.LineNumber, Op->Asl.Column, Op, 977 NumChildren, UtGetOpName(ParseOpcode)); 978 979 /* Some extra debug output based on the parse opcode */ 980 981 switch (ParseOpcode) 982 { 983 case PARSEOP_ASL_CODE: 984 985 RootNode = Op; 986 Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 987 DbgPrint (ASL_PARSE_OUTPUT, "ASLCODE (Tree Completed)->"); 988 break; 989 990 case PARSEOP_DEFINITION_BLOCK: 991 992 DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->"); 993 break; 994 995 case PARSEOP_OPERATIONREGION: 996 997 DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->"); 998 break; 999 1000 case PARSEOP_OR: 1001 1002 DbgPrint (ASL_PARSE_OUTPUT, "OR->"); 1003 break; 1004 1005 default: 1006 1007 /* Nothing to do for other opcodes */ 1008 1009 break; 1010 } 1011 1012 /* Link the new node to its children */ 1013 1014 PrevChild = NULL; 1015 FirstChild = TRUE; 1016 for (i = 0; i < NumChildren; i++) 1017 { 1018 /* Get the next child */ 1019 1020 Child = va_arg (ap, ACPI_PARSE_OBJECT *); 1021 DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child); 1022 1023 /* 1024 * If child is NULL, this means that an optional argument 1025 * was omitted. We must create a placeholder with a special 1026 * opcode (DEFAULT_ARG) so that the code generator will know 1027 * that it must emit the correct default for this argument 1028 */ 1029 if (!Child) 1030 { 1031 Child = TrAllocateNode (PARSEOP_DEFAULT_ARG); 1032 } 1033 1034 /* Link first child to parent */ 1035 1036 if (FirstChild) 1037 { 1038 FirstChild = FALSE; 1039 Op->Asl.Child = Child; 1040 } 1041 1042 /* Point all children to parent */ 1043 1044 Child->Asl.Parent = Op; 1045 1046 /* Link children in a peer list */ 1047 1048 if (PrevChild) 1049 { 1050 PrevChild->Asl.Next = Child; 1051 }; 1052 1053 /* 1054 * This child might be a list, point all nodes in the list 1055 * to the same parent 1056 */ 1057 while (Child->Asl.Next) 1058 { 1059 Child = Child->Asl.Next; 1060 Child->Asl.Parent = Op; 1061 } 1062 1063 PrevChild = Child; 1064 } 1065 va_end(ap); 1066 1067 DbgPrint (ASL_PARSE_OUTPUT, "\n"); 1068 return (Op); 1069 } 1070 1071 1072 /******************************************************************************* 1073 * 1074 * FUNCTION: TrLinkChildren 1075 * 1076 * PARAMETERS: Op - An existing parse node 1077 * NumChildren - Number of children to follow 1078 * ... - A list of child nodes to link to the new 1079 * node. NumChildren long. 1080 * 1081 * RETURN: The updated (linked) node 1082 * 1083 * DESCRIPTION: Link a group of nodes to an existing parse node 1084 * 1085 ******************************************************************************/ 1086 1087 ACPI_PARSE_OBJECT * 1088 TrLinkChildren ( 1089 ACPI_PARSE_OBJECT *Op, 1090 UINT32 NumChildren, 1091 ...) 1092 { 1093 ACPI_PARSE_OBJECT *Child; 1094 ACPI_PARSE_OBJECT *PrevChild; 1095 va_list ap; 1096 UINT32 i; 1097 BOOLEAN FirstChild; 1098 1099 1100 va_start (ap, NumChildren); 1101 1102 1103 TrSetEndLineNumber (Op); 1104 1105 DbgPrint (ASL_PARSE_OUTPUT, 1106 "\nLinkChildren Line [%u to %u] NewParent %p Child %u Op %s ", 1107 Op->Asl.LineNumber, Op->Asl.EndLine, 1108 Op, NumChildren, UtGetOpName(Op->Asl.ParseOpcode)); 1109 1110 switch (Op->Asl.ParseOpcode) 1111 { 1112 case PARSEOP_ASL_CODE: 1113 1114 RootNode = Op; 1115 Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 1116 DbgPrint (ASL_PARSE_OUTPUT, "ASLCODE (Tree Completed)->"); 1117 break; 1118 1119 case PARSEOP_DEFINITION_BLOCK: 1120 1121 DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->"); 1122 break; 1123 1124 case PARSEOP_OPERATIONREGION: 1125 1126 DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->"); 1127 break; 1128 1129 case PARSEOP_OR: 1130 1131 DbgPrint (ASL_PARSE_OUTPUT, "OR->"); 1132 break; 1133 1134 default: 1135 1136 /* Nothing to do for other opcodes */ 1137 1138 break; 1139 } 1140 1141 /* Link the new node to it's children */ 1142 1143 PrevChild = NULL; 1144 FirstChild = TRUE; 1145 for (i = 0; i < NumChildren; i++) 1146 { 1147 Child = va_arg (ap, ACPI_PARSE_OBJECT *); 1148 1149 if ((Child == PrevChild) && (Child != NULL)) 1150 { 1151 AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Child, 1152 "Child node list invalid"); 1153 va_end(ap); 1154 return (Op); 1155 } 1156 1157 DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child); 1158 1159 /* 1160 * If child is NULL, this means that an optional argument 1161 * was omitted. We must create a placeholder with a special 1162 * opcode (DEFAULT_ARG) so that the code generator will know 1163 * that it must emit the correct default for this argument 1164 */ 1165 if (!Child) 1166 { 1167 Child = TrAllocateNode (PARSEOP_DEFAULT_ARG); 1168 } 1169 1170 /* Link first child to parent */ 1171 1172 if (FirstChild) 1173 { 1174 FirstChild = FALSE; 1175 Op->Asl.Child = Child; 1176 } 1177 1178 /* Point all children to parent */ 1179 1180 Child->Asl.Parent = Op; 1181 1182 /* Link children in a peer list */ 1183 1184 if (PrevChild) 1185 { 1186 PrevChild->Asl.Next = Child; 1187 }; 1188 1189 /* 1190 * This child might be a list, point all nodes in the list 1191 * to the same parent 1192 */ 1193 while (Child->Asl.Next) 1194 { 1195 Child = Child->Asl.Next; 1196 Child->Asl.Parent = Op; 1197 } 1198 1199 PrevChild = Child; 1200 } 1201 1202 va_end(ap); 1203 DbgPrint (ASL_PARSE_OUTPUT, "\n\n"); 1204 return (Op); 1205 } 1206 1207 1208 /******************************************************************************* 1209 * 1210 * FUNCTION: TrLinkPeerNode 1211 * 1212 * PARAMETERS: Op1 - First peer 1213 * Op2 - Second peer 1214 * 1215 * RETURN: Op1 or the non-null node. 1216 * 1217 * DESCRIPTION: Link two nodes as peers. Handles cases where one peer is null. 1218 * 1219 ******************************************************************************/ 1220 1221 ACPI_PARSE_OBJECT * 1222 TrLinkPeerNode ( 1223 ACPI_PARSE_OBJECT *Op1, 1224 ACPI_PARSE_OBJECT *Op2) 1225 { 1226 ACPI_PARSE_OBJECT *Next; 1227 1228 1229 DbgPrint (ASL_PARSE_OUTPUT, 1230 "\nLinkPeerNode: 1=%p (%s), 2=%p (%s)\n", 1231 Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode) : NULL, 1232 Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode) : NULL); 1233 1234 1235 if ((!Op1) && (!Op2)) 1236 { 1237 DbgPrint (ASL_PARSE_OUTPUT, "\nTwo Null nodes!\n"); 1238 return (Op1); 1239 } 1240 1241 /* If one of the nodes is null, just return the non-null node */ 1242 1243 if (!Op2) 1244 { 1245 return (Op1); 1246 } 1247 1248 if (!Op1) 1249 { 1250 return (Op2); 1251 } 1252 1253 if (Op1 == Op2) 1254 { 1255 DbgPrint (ASL_DEBUG_OUTPUT, 1256 "\n************* Internal error, linking node to itself %p\n", 1257 Op1); 1258 AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op1, 1259 "Linking node to itself"); 1260 return (Op1); 1261 } 1262 1263 Op1->Asl.Parent = Op2->Asl.Parent; 1264 1265 /* 1266 * Op 1 may already have a peer list (such as an IF/ELSE pair), 1267 * so we must walk to the end of the list and attach the new 1268 * peer at the end 1269 */ 1270 Next = Op1; 1271 while (Next->Asl.Next) 1272 { 1273 Next = Next->Asl.Next; 1274 } 1275 1276 Next->Asl.Next = Op2; 1277 return (Op1); 1278 } 1279 1280 1281 /******************************************************************************* 1282 * 1283 * FUNCTION: TrLinkPeerNodes 1284 * 1285 * PARAMETERS: NumPeers - The number of nodes in the list to follow 1286 * ... - A list of nodes to link together as peers 1287 * 1288 * RETURN: The first node in the list (head of the peer list) 1289 * 1290 * DESCRIPTION: Link together an arbitrary number of peer nodes. 1291 * 1292 ******************************************************************************/ 1293 1294 ACPI_PARSE_OBJECT * 1295 TrLinkPeerNodes ( 1296 UINT32 NumPeers, 1297 ...) 1298 { 1299 ACPI_PARSE_OBJECT *This; 1300 ACPI_PARSE_OBJECT *Next; 1301 va_list ap; 1302 UINT32 i; 1303 ACPI_PARSE_OBJECT *Start; 1304 1305 1306 DbgPrint (ASL_PARSE_OUTPUT, 1307 "\nLinkPeerNodes: (%u) ", NumPeers); 1308 1309 va_start (ap, NumPeers); 1310 This = va_arg (ap, ACPI_PARSE_OBJECT *); 1311 Start = This; 1312 1313 /* 1314 * Link all peers 1315 */ 1316 for (i = 0; i < (NumPeers -1); i++) 1317 { 1318 DbgPrint (ASL_PARSE_OUTPUT, "%u=%p ", (i+1), This); 1319 1320 while (This->Asl.Next) 1321 { 1322 This = This->Asl.Next; 1323 } 1324 1325 /* Get another peer node */ 1326 1327 Next = va_arg (ap, ACPI_PARSE_OBJECT *); 1328 if (!Next) 1329 { 1330 Next = TrAllocateNode (PARSEOP_DEFAULT_ARG); 1331 } 1332 1333 /* link new node to the current node */ 1334 1335 This->Asl.Next = Next; 1336 This = Next; 1337 } 1338 va_end (ap); 1339 1340 DbgPrint (ASL_PARSE_OUTPUT,"\n"); 1341 return (Start); 1342 } 1343 1344 1345 /******************************************************************************* 1346 * 1347 * FUNCTION: TrLinkChildNode 1348 * 1349 * PARAMETERS: Op1 - Parent node 1350 * Op2 - Op to become a child 1351 * 1352 * RETURN: The parent node 1353 * 1354 * DESCRIPTION: Link two nodes together as a parent and child 1355 * 1356 ******************************************************************************/ 1357 1358 ACPI_PARSE_OBJECT * 1359 TrLinkChildNode ( 1360 ACPI_PARSE_OBJECT *Op1, 1361 ACPI_PARSE_OBJECT *Op2) 1362 { 1363 ACPI_PARSE_OBJECT *Next; 1364 1365 1366 DbgPrint (ASL_PARSE_OUTPUT, 1367 "\nLinkChildNode: Parent=%p (%s), Child=%p (%s)\n", 1368 Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode): NULL, 1369 Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode): NULL); 1370 1371 if (!Op1 || !Op2) 1372 { 1373 return (Op1); 1374 } 1375 1376 Op1->Asl.Child = Op2; 1377 1378 /* Set the child and all peers of the child to point to the parent */ 1379 1380 Next = Op2; 1381 while (Next) 1382 { 1383 Next->Asl.Parent = Op1; 1384 Next = Next->Asl.Next; 1385 } 1386 1387 return (Op1); 1388 } 1389 1390 1391 /******************************************************************************* 1392 * 1393 * FUNCTION: TrWalkParseTree 1394 * 1395 * PARAMETERS: Visitation - Type of walk 1396 * DescendingCallback - Called during tree descent 1397 * AscendingCallback - Called during tree ascent 1398 * Context - To be passed to the callbacks 1399 * 1400 * RETURN: Status from callback(s) 1401 * 1402 * DESCRIPTION: Walk the entire parse tree. 1403 * 1404 ******************************************************************************/ 1405 1406 ACPI_STATUS 1407 TrWalkParseTree ( 1408 ACPI_PARSE_OBJECT *Op, 1409 UINT32 Visitation, 1410 ASL_WALK_CALLBACK DescendingCallback, 1411 ASL_WALK_CALLBACK AscendingCallback, 1412 void *Context) 1413 { 1414 UINT32 Level; 1415 BOOLEAN NodePreviouslyVisited; 1416 ACPI_PARSE_OBJECT *StartOp = Op; 1417 ACPI_STATUS Status; 1418 1419 1420 if (!RootNode) 1421 { 1422 return (AE_OK); 1423 } 1424 1425 Level = 0; 1426 NodePreviouslyVisited = FALSE; 1427 1428 switch (Visitation) 1429 { 1430 case ASL_WALK_VISIT_DOWNWARD: 1431 1432 while (Op) 1433 { 1434 if (!NodePreviouslyVisited) 1435 { 1436 /* Let the callback process the node. */ 1437 1438 Status = DescendingCallback (Op, Level, Context); 1439 if (ACPI_SUCCESS (Status)) 1440 { 1441 /* Visit children first, once */ 1442 1443 if (Op->Asl.Child) 1444 { 1445 Level++; 1446 Op = Op->Asl.Child; 1447 continue; 1448 } 1449 } 1450 else if (Status != AE_CTRL_DEPTH) 1451 { 1452 /* Exit immediately on any error */ 1453 1454 return (Status); 1455 } 1456 } 1457 1458 /* Terminate walk at start op */ 1459 1460 if (Op == StartOp) 1461 { 1462 break; 1463 } 1464 1465 /* No more children, visit peers */ 1466 1467 if (Op->Asl.Next) 1468 { 1469 Op = Op->Asl.Next; 1470 NodePreviouslyVisited = FALSE; 1471 } 1472 else 1473 { 1474 /* No children or peers, re-visit parent */ 1475 1476 if (Level != 0 ) 1477 { 1478 Level--; 1479 } 1480 Op = Op->Asl.Parent; 1481 NodePreviouslyVisited = TRUE; 1482 } 1483 } 1484 break; 1485 1486 case ASL_WALK_VISIT_UPWARD: 1487 1488 while (Op) 1489 { 1490 /* Visit leaf node (no children) or parent node on return trip */ 1491 1492 if ((!Op->Asl.Child) || 1493 (NodePreviouslyVisited)) 1494 { 1495 /* Let the callback process the node. */ 1496 1497 Status = AscendingCallback (Op, Level, Context); 1498 if (ACPI_FAILURE (Status)) 1499 { 1500 return (Status); 1501 } 1502 } 1503 else 1504 { 1505 /* Visit children first, once */ 1506 1507 Level++; 1508 Op = Op->Asl.Child; 1509 continue; 1510 } 1511 1512 /* Terminate walk at start op */ 1513 1514 if (Op == StartOp) 1515 { 1516 break; 1517 } 1518 1519 /* No more children, visit peers */ 1520 1521 if (Op->Asl.Next) 1522 { 1523 Op = Op->Asl.Next; 1524 NodePreviouslyVisited = FALSE; 1525 } 1526 else 1527 { 1528 /* No children or peers, re-visit parent */ 1529 1530 if (Level != 0 ) 1531 { 1532 Level--; 1533 } 1534 Op = Op->Asl.Parent; 1535 NodePreviouslyVisited = TRUE; 1536 } 1537 } 1538 break; 1539 1540 case ASL_WALK_VISIT_TWICE: 1541 1542 while (Op) 1543 { 1544 if (NodePreviouslyVisited) 1545 { 1546 Status = AscendingCallback (Op, Level, Context); 1547 if (ACPI_FAILURE (Status)) 1548 { 1549 return (Status); 1550 } 1551 } 1552 else 1553 { 1554 /* Let the callback process the node. */ 1555 1556 Status = DescendingCallback (Op, Level, Context); 1557 if (ACPI_SUCCESS (Status)) 1558 { 1559 /* Visit children first, once */ 1560 1561 if (Op->Asl.Child) 1562 { 1563 Level++; 1564 Op = Op->Asl.Child; 1565 continue; 1566 } 1567 } 1568 else if (Status != AE_CTRL_DEPTH) 1569 { 1570 /* Exit immediately on any error */ 1571 1572 return (Status); 1573 } 1574 } 1575 1576 /* Terminate walk at start op */ 1577 1578 if (Op == StartOp) 1579 { 1580 break; 1581 } 1582 1583 /* No more children, visit peers */ 1584 1585 if (Op->Asl.Next) 1586 { 1587 Op = Op->Asl.Next; 1588 NodePreviouslyVisited = FALSE; 1589 } 1590 else 1591 { 1592 /* No children or peers, re-visit parent */ 1593 1594 if (Level != 0 ) 1595 { 1596 Level--; 1597 } 1598 Op = Op->Asl.Parent; 1599 NodePreviouslyVisited = TRUE; 1600 } 1601 } 1602 break; 1603 1604 default: 1605 /* No other types supported */ 1606 break; 1607 } 1608 1609 /* If we get here, the walk completed with no errors */ 1610 1611 return (AE_OK); 1612 } 1613