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