aslmethod.c revision 1.1.1.14 1 /******************************************************************************
2 *
3 * Module Name: aslmethod.c - Control method analysis walk
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2020, 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 "acnamesp.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 static void
58 MtCheckNamedObjectInMethod (
59 ACPI_PARSE_OBJECT *Op,
60 ASL_METHOD_INFO *MethodInfo);
61
62 static void
63 MtCheckStaticOperationRegionInMethod (
64 ACPI_PARSE_OBJECT *Op);
65
66
67 /*******************************************************************************
68 *
69 * FUNCTION: MtMethodAnalysisWalkBegin
70 *
71 * PARAMETERS: ASL_WALK_CALLBACK
72 *
73 * RETURN: Status
74 *
75 * DESCRIPTION: Descending callback for the analysis walk. Check methods for:
76 * 1) Initialized local variables
77 * 2) Valid arguments
78 * 3) Return types
79 *
80 ******************************************************************************/
81
82 ACPI_STATUS
83 MtMethodAnalysisWalkBegin (
84 ACPI_PARSE_OBJECT *Op,
85 UINT32 Level,
86 void *Context)
87 {
88 ASL_ANALYSIS_WALK_INFO *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context;
89 ASL_METHOD_INFO *MethodInfo = WalkInfo->MethodStack;
90 ACPI_PARSE_OBJECT *Next;
91 UINT32 RegisterNumber;
92 UINT32 i;
93 char LocalName[] = "Local0";
94 char ArgName[] = "Arg0";
95 ACPI_PARSE_OBJECT *ArgNode;
96 ACPI_PARSE_OBJECT *NextType;
97 UINT8 ActualArgs = 0;
98 BOOLEAN HidExists;
99 BOOLEAN AdrExists;
100
101
102 /* Build cross-reference output file if requested */
103
104 if (AslGbl_CrossReferenceOutput)
105 {
106 OtXrefWalkPart1 (Op, Level, MethodInfo);
107 }
108
109 switch (Op->Asl.ParseOpcode)
110 {
111 case PARSEOP_METHOD:
112
113 AslGbl_TotalMethods++;
114
115 /* Create and init method info */
116
117 MethodInfo = UtLocalCalloc (sizeof (ASL_METHOD_INFO));
118 MethodInfo->Next = WalkInfo->MethodStack;
119 MethodInfo->Op = Op;
120
121 WalkInfo->MethodStack = MethodInfo;
122
123 /*
124 * Special handling for _PSx methods. Dependency rules (same scope):
125 *
126 * 1) _PS0 - One of these must exist: _PS1, _PS2, _PS3
127 * 2) _PS1/_PS2/_PS3: A _PS0 must exist
128 */
129 if (ACPI_COMPARE_NAMESEG (METHOD_NAME__PS0, Op->Asl.NameSeg))
130 {
131 /* For _PS0, one of _PS1/_PS2/_PS3 must exist */
132
133 if ((!ApFindNameInScope (METHOD_NAME__PS1, Op)) &&
134 (!ApFindNameInScope (METHOD_NAME__PS2, Op)) &&
135 (!ApFindNameInScope (METHOD_NAME__PS3, Op)))
136 {
137 AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
138 "_PS0 requires one of _PS1/_PS2/_PS3 in same scope");
139 }
140 }
141 else if (
142 ACPI_COMPARE_NAMESEG (METHOD_NAME__PS1, Op->Asl.NameSeg) ||
143 ACPI_COMPARE_NAMESEG (METHOD_NAME__PS2, Op->Asl.NameSeg) ||
144 ACPI_COMPARE_NAMESEG (METHOD_NAME__PS3, Op->Asl.NameSeg))
145 {
146 /* For _PS1/_PS2/_PS3, a _PS0 must exist */
147
148 if (!ApFindNameInScope (METHOD_NAME__PS0, Op))
149 {
150 sprintf (AslGbl_MsgBuffer,
151 "%4.4s requires _PS0 in same scope", Op->Asl.NameSeg);
152
153 AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
154 AslGbl_MsgBuffer);
155 }
156 }
157
158 /* Get the name node */
159
160 Next = Op->Asl.Child;
161
162 /* Get the NumArguments node */
163
164 Next = Next->Asl.Next;
165 MethodInfo->NumArguments = (UINT8)
166 (((UINT8) Next->Asl.Value.Integer) & 0x07);
167
168 /* Get the SerializeRule and SyncLevel nodes, ignored here */
169
170 Next = Next->Asl.Next;
171 MethodInfo->ShouldBeSerialized = (UINT8) Next->Asl.Value.Integer;
172
173 Next = Next->Asl.Next;
174 ArgNode = Next;
175
176 /* Get the ReturnType node */
177
178 Next = Next->Asl.Next;
179
180 NextType = Next->Asl.Child;
181
182 MethodInfo->ValidReturnTypes = MtProcessTypeOp (NextType);
183
184 /* Get the ParameterType node */
185
186 Next = Next->Asl.Next;
187
188 NextType = Next->Asl.Child;
189 if (!NextType)
190 {
191 /*
192 * The optional parameter types list was omitted at the source
193 * level. Use the Argument count parameter instead.
194 */
195 ActualArgs = MethodInfo->NumArguments;
196 }
197 else
198 {
199 ActualArgs = MtProcessParameterTypeList (NextType,
200 MethodInfo->ValidArgTypes);
201 }
202
203 if ((MethodInfo->NumArguments) &&
204 (MethodInfo->NumArguments != ActualArgs))
205 {
206 sprintf (AslGbl_MsgBuffer,
207 "Length = %u", ActualArgs);
208 AslError (ASL_ERROR, ASL_MSG_ARG_COUNT_MISMATCH,
209 Op->Asl.Child->Asl.Next, AslGbl_MsgBuffer);
210 }
211
212 /* Allow numarguments == 0 for Function() */
213
214 if ((!MethodInfo->NumArguments) && (ActualArgs))
215 {
216 MethodInfo->NumArguments = ActualArgs;
217 ArgNode->Asl.Value.Integer |= ActualArgs;
218 }
219
220 /*
221 * Actual arguments are initialized at method entry.
222 * All other ArgX "registers" can be used as locals, so we
223 * track their initialization.
224 */
225 for (i = 0; i < MethodInfo->NumArguments; i++)
226 {
227 MethodInfo->ArgInitialized[i] = TRUE;
228 }
229 break;
230
231 case PARSEOP_METHODCALL:
232
233 /* Check for a recursive method call */
234
235 if (MethodInfo &&
236 (Op->Asl.Node == MethodInfo->Op->Asl.Node))
237 {
238 if (MethodInfo->CreatesNamedObjects)
239 {
240 /*
241 * This is an error, as it will fail at runtime on all ACPI
242 * implementations. Any named object declarations will be
243 * executed twice, causing failure the second time. Note,
244 * this is independent of whether the method is declared
245 * Serialized, because the same thread is attempting to
246 * reenter the method, and this will always succeed.
247 */
248 AslDualParseOpError (ASL_ERROR, ASL_MSG_ILLEGAL_RECURSION, Op,
249 Op->Asl.Value.String, ASL_MSG_FOUND_HERE, MethodInfo->Op,
250 MethodInfo->Op->Asl.ExternalName);
251 }
252 else
253 {
254 /* Method does not create objects, issue a remark */
255
256 AslError (ASL_REMARK, ASL_MSG_RECURSION, Op, Op->Asl.ExternalName);
257 }
258 }
259 break;
260
261 case PARSEOP_LOCAL0:
262 case PARSEOP_LOCAL1:
263 case PARSEOP_LOCAL2:
264 case PARSEOP_LOCAL3:
265 case PARSEOP_LOCAL4:
266 case PARSEOP_LOCAL5:
267 case PARSEOP_LOCAL6:
268 case PARSEOP_LOCAL7:
269
270 if (!MethodInfo)
271 {
272 /*
273 * Local was used outside a control method, or there was an error
274 * in the method declaration.
275 */
276 AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD,
277 Op, Op->Asl.ExternalName);
278 return (AE_ERROR);
279 }
280
281 RegisterNumber = (Op->Asl.AmlOpcode & 0x0007);
282
283 /*
284 * If the local is being used as a target, mark the local
285 * initialized
286 */
287 if (Op->Asl.CompileFlags & OP_IS_TARGET)
288 {
289 MethodInfo->LocalInitialized[RegisterNumber] = TRUE;
290 }
291
292 /*
293 * Otherwise, this is a reference, check if the local
294 * has been previously initialized.
295 *
296 * The only operator that accepts an uninitialized value is ObjectType()
297 */
298 else if ((!MethodInfo->LocalInitialized[RegisterNumber]) &&
299 (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE))
300 {
301 LocalName[strlen (LocalName) -1] = (char) (RegisterNumber + 0x30);
302 AslError (ASL_ERROR, ASL_MSG_LOCAL_INIT, Op, LocalName);
303 }
304 break;
305
306 case PARSEOP_ARG0:
307 case PARSEOP_ARG1:
308 case PARSEOP_ARG2:
309 case PARSEOP_ARG3:
310 case PARSEOP_ARG4:
311 case PARSEOP_ARG5:
312 case PARSEOP_ARG6:
313
314 if (!MethodInfo)
315 {
316 /*
317 * Arg was used outside a control method, or there was an error
318 * in the method declaration.
319 */
320 AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD,
321 Op, Op->Asl.ExternalName);
322 return (AE_ERROR);
323 }
324
325 RegisterNumber = (Op->Asl.AmlOpcode & 0x000F) - 8;
326 ArgName[strlen (ArgName) -1] = (char) (RegisterNumber + 0x30);
327
328 /*
329 * If the Arg is being used as a target, mark the local
330 * initialized
331 */
332 if (Op->Asl.CompileFlags & OP_IS_TARGET)
333 {
334 MethodInfo->ArgInitialized[RegisterNumber] = TRUE;
335 }
336
337 /*
338 * Otherwise, this is a reference, check if the Arg
339 * has been previously initialized.
340 *
341 * The only operator that accepts an uninitialized value is ObjectType()
342 */
343 else if ((!MethodInfo->ArgInitialized[RegisterNumber]) &&
344 (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE))
345 {
346 AslError (ASL_ERROR, ASL_MSG_ARG_INIT, Op, ArgName);
347 }
348
349 /* Flag this arg if it is not a "real" argument to the method */
350
351 if (RegisterNumber >= MethodInfo->NumArguments)
352 {
353 AslError (ASL_REMARK, ASL_MSG_NOT_PARAMETER, Op, ArgName);
354 }
355 break;
356
357 case PARSEOP_RETURN:
358
359 if (!MethodInfo)
360 {
361 /*
362 * Probably was an error in the method declaration,
363 * no additional error here
364 */
365 ACPI_WARNING ((AE_INFO, "%p, No parent method", Op));
366 return (AE_ERROR);
367 }
368
369 /*
370 * A child indicates a possible return value. A simple Return or
371 * Return() is marked with OP_IS_NULL_RETURN by the parser so
372 * that it is not counted as a "real" return-with-value, although
373 * the AML code that is actually emitted is Return(0). The AML
374 * definition of Return has a required parameter, so we are
375 * forced to convert a null return to Return(0).
376 */
377 if ((Op->Asl.Child) &&
378 (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) &&
379 (!(Op->Asl.Child->Asl.CompileFlags & OP_IS_NULL_RETURN)))
380 {
381 MethodInfo->NumReturnWithValue++;
382 }
383 else
384 {
385 MethodInfo->NumReturnNoValue++;
386 }
387 break;
388
389 case PARSEOP_BREAK:
390 case PARSEOP_CONTINUE:
391
392 Next = Op->Asl.Parent;
393 while (Next)
394 {
395 if (Next->Asl.ParseOpcode == PARSEOP_WHILE)
396 {
397 break;
398 }
399 Next = Next->Asl.Parent;
400 }
401
402 if (!Next)
403 {
404 AslError (ASL_ERROR, ASL_MSG_NO_WHILE, Op, NULL);
405 }
406 break;
407
408 case PARSEOP_STALL:
409
410 /* We can range check if the argument is an integer */
411
412 if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) &&
413 (Op->Asl.Child->Asl.Value.Integer > ACPI_UINT8_MAX))
414 {
415 AslError (ASL_ERROR, ASL_MSG_INVALID_TIME, Op, NULL);
416 }
417 break;
418
419 case PARSEOP_DEVICE:
420
421 /* Check usage of _HID and _ADR objects */
422
423 HidExists = ApFindNameInDeviceTree (METHOD_NAME__HID, Op);
424 AdrExists = ApFindNameInDeviceTree (METHOD_NAME__ADR, Op);
425
426 if (!HidExists && !AdrExists)
427 {
428 AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
429 "Device object requires a _HID or _ADR in same scope");
430 }
431 else if (HidExists && AdrExists)
432 {
433 /*
434 * According to the ACPI spec, "A device object must contain
435 * either an _HID object or an _ADR object, but should not contain
436 * both".
437 */
438 AslError (ASL_WARNING, ASL_MSG_MULTIPLE_TYPES, Op,
439 "Device object requires either a _HID or _ADR, but not both");
440 }
441 break;
442
443 case PARSEOP_EVENT:
444 case PARSEOP_MUTEX:
445 case PARSEOP_OPERATIONREGION:
446 case PARSEOP_POWERRESOURCE:
447 case PARSEOP_PROCESSOR:
448 case PARSEOP_THERMALZONE:
449
450 /*
451 * The first operand is a name to be created in the namespace.
452 * Check against the reserved list.
453 */
454 i = ApCheckForPredefinedName (Op, Op->Asl.NameSeg);
455 if (i < ACPI_VALID_RESERVED_NAME_MAX)
456 {
457 AslError (ASL_ERROR, ASL_MSG_RESERVED_USE,
458 Op, Op->Asl.ExternalName);
459 }
460
461 MtCheckStaticOperationRegionInMethod (Op);
462 break;
463
464 case PARSEOP_NAME:
465
466 /* Typecheck any predefined names statically defined with Name() */
467
468 ApCheckForPredefinedObject (Op, Op->Asl.NameSeg);
469
470 /* Special typechecking for _HID */
471
472 if (ACPI_COMPARE_NAMESEG (METHOD_NAME__HID, Op->Asl.NameSeg))
473 {
474 Next = Op->Asl.Child->Asl.Next;
475 AnCheckId (Next, ASL_TYPE_HID);
476 }
477
478 /* Special typechecking for _CID */
479
480 else if (ACPI_COMPARE_NAMESEG (METHOD_NAME__CID, Op->Asl.NameSeg))
481 {
482 Next = Op->Asl.Child->Asl.Next;
483
484 if ((Next->Asl.ParseOpcode == PARSEOP_PACKAGE) ||
485 (Next->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE))
486 {
487 Next = Next->Asl.Child;
488 while (Next)
489 {
490 AnCheckId (Next, ASL_TYPE_CID);
491 Next = Next->Asl.Next;
492 }
493 }
494 else
495 {
496 AnCheckId (Next, ASL_TYPE_CID);
497 }
498 }
499
500 break;
501
502 default:
503
504 break;
505 }
506
507 /* Check for named object creation within a non-serialized method */
508
509 MtCheckNamedObjectInMethod (Op, MethodInfo);
510 return (AE_OK);
511 }
512
513
514 /*******************************************************************************
515 *
516 * FUNCTION: MtProcessTypeOp
517 *
518 * PARAMETERS: Op - Op representing a btype
519 *
520 * RETURN: Btype represented by Op
521 *
522 * DESCRIPTION: Process a parse object that represents single parameter type or
523 * a return type in method, function, and external declarations.
524 *
525 ******************************************************************************/
526
527 UINT32
528 MtProcessTypeOp (
529 ACPI_PARSE_OBJECT *TypeOp)
530 {
531 UINT32 Btype = ACPI_BTYPE_ANY;
532
533
534 while (TypeOp)
535 {
536 Btype |= AnMapObjTypeToBtype (TypeOp);
537 TypeOp->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
538 TypeOp = TypeOp->Asl.Next;
539 }
540
541 return (Btype);
542 }
543
544
545 /*******************************************************************************
546 *
547 * FUNCTION: MtProcessParameterTypeList
548 *
549 * PARAMETERS: Op - Op representing a btype
550 *
551 * RETURN: Btype represented by Op
552 *
553 * DESCRIPTION: Process a parse object that represents a parameter type list in
554 * method, function, and external declarations.
555 *
556 ******************************************************************************/
557
558 UINT8
559 MtProcessParameterTypeList (
560 ACPI_PARSE_OBJECT *ParamTypeOp,
561 UINT32 *TypeList)
562 {
563 UINT8 ParameterCount = 0;
564
565
566 while (ParamTypeOp)
567 {
568 TypeList[ParameterCount] =
569 MtProcessTypeOp (ParamTypeOp->Asl.Child);
570
571 ParameterCount++;
572 ParamTypeOp = ParamTypeOp->Asl.Next;
573 }
574
575 return (ParameterCount);
576 }
577
578
579 /*******************************************************************************
580 *
581 * FUNCTION: MtCheckNamedObjectInMethod
582 *
583 * PARAMETERS: Op - Current parser op
584 * MethodInfo - Info for method being parsed
585 *
586 * RETURN: None
587 *
588 * DESCRIPTION: Detect if a non-serialized method is creating a named object,
589 * which could possibly cause problems if two threads execute
590 * the method concurrently. Emit a remark in this case.
591 *
592 ******************************************************************************/
593
594 static void
595 MtCheckNamedObjectInMethod (
596 ACPI_PARSE_OBJECT *Op,
597 ASL_METHOD_INFO *MethodInfo)
598 {
599 const ACPI_OPCODE_INFO *OpInfo;
600 char *ExternalPath;
601
602
603 /* We don't care about actual method declarations or scopes */
604
605 if ((Op->Asl.AmlOpcode == AML_METHOD_OP) ||
606 (Op->Asl.AmlOpcode == AML_SCOPE_OP))
607 {
608 return;
609 }
610
611 /* Determine if we are creating a named object within a method */
612
613 if (!MethodInfo)
614 {
615 return;
616 }
617
618 OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
619 if (OpInfo->Class == AML_CLASS_NAMED_OBJECT)
620 {
621 /*
622 * 1) Mark the method as a method that creates named objects.
623 *
624 * 2) Issue a remark indicating the inefficiency of creating named
625 * objects within a method (Except for compiler-emitted temporary
626 * variables).
627 *
628 * 3) If the method is non-serialized, emit a remark that the method
629 * should be serialized.
630 *
631 * Reason: If a thread blocks within the method for any reason, and
632 * another thread enters the method, the method will fail because
633 * an attempt will be made to create the same object twice.
634 */
635 ExternalPath = AcpiNsGetNormalizedPathname (MethodInfo->Op->Asl.Node, TRUE);
636
637 /* No error for compiler temp variables (name starts with "_T_") */
638
639 if ((Op->Asl.NameSeg[0] != '_') &&
640 (Op->Asl.NameSeg[1] != 'T') &&
641 (Op->Asl.NameSeg[2] != '_'))
642 {
643 AslError (ASL_REMARK, ASL_MSG_NAMED_OBJECT_CREATION, Op,
644 ExternalPath);
645 }
646
647 MethodInfo->CreatesNamedObjects = TRUE;
648 if (!MethodInfo->ShouldBeSerialized)
649 {
650 AslError (ASL_REMARK, ASL_MSG_SERIALIZED_REQUIRED, MethodInfo->Op,
651 ExternalPath);
652
653 /* Emit message only ONCE per method */
654
655 MethodInfo->ShouldBeSerialized = TRUE;
656 }
657
658 if (ExternalPath)
659 {
660 ACPI_FREE (ExternalPath);
661 }
662 }
663 }
664
665
666 /*******************************************************************************
667 *
668 * FUNCTION: MtCheckStaticOperationRegionInMethod
669 *
670 * PARAMETERS: Op - Current parser op
671 *
672 * RETURN: None
673 *
674 * DESCRIPTION: Warns if an Operation Region with static address or length
675 * is declared inside a control method
676 *
677 ******************************************************************************/
678
679 static void
680 MtCheckStaticOperationRegionInMethod(
681 ACPI_PARSE_OBJECT* Op)
682 {
683 ACPI_PARSE_OBJECT* AddressOp;
684 ACPI_PARSE_OBJECT* LengthOp;
685
686
687 if (Op->Asl.ParseOpcode != PARSEOP_OPERATIONREGION)
688 {
689 return;
690 }
691
692 /*
693 * OperationRegion should have 4 arguments defined. At this point, we
694 * assume that the parse tree is well-formed.
695 */
696 AddressOp = Op->Asl.Child->Asl.Next->Asl.Next;
697 LengthOp = Op->Asl.Child->Asl.Next->Asl.Next->Asl.Next;
698
699 if (UtGetParentMethodOp (Op) &&
700 AddressOp->Asl.ParseOpcode == PARSEOP_INTEGER &&
701 LengthOp->Asl.ParseOpcode == PARSEOP_INTEGER)
702 {
703 /*
704 * At this point, a static operation region declared inside of a
705 * control method has been found. Throw a warning because this is
706 * highly inefficient.
707 */
708 AslError(ASL_WARNING, ASL_MSG_STATIC_OPREGION_IN_METHOD, Op, NULL);
709 }
710
711 return;
712 }
713
714
715 /*******************************************************************************
716 *
717 * FUNCTION: MtMethodAnalysisWalkEnd
718 *
719 * PARAMETERS: ASL_WALK_CALLBACK
720 *
721 * RETURN: Status
722 *
723 * DESCRIPTION: Ascending callback for analysis walk. Complete method
724 * return analysis.
725 *
726 ******************************************************************************/
727
728 ACPI_STATUS
729 MtMethodAnalysisWalkEnd (
730 ACPI_PARSE_OBJECT *Op,
731 UINT32 Level,
732 void *Context)
733 {
734 ASL_ANALYSIS_WALK_INFO *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context;
735 ASL_METHOD_INFO *MethodInfo = WalkInfo->MethodStack;
736 char *ExternalPath;
737
738
739 switch (Op->Asl.ParseOpcode)
740 {
741 case PARSEOP_METHOD:
742 case PARSEOP_RETURN:
743
744 if (!MethodInfo)
745 {
746 printf ("No method info for method! [%s]\n", Op->Asl.Namepath);
747 AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, Op,
748 "No method info for this method");
749
750 CmCleanupAndExit ();
751 return (AE_AML_INTERNAL);
752 }
753 break;
754
755 default:
756
757 break;
758 }
759
760 switch (Op->Asl.ParseOpcode)
761 {
762 case PARSEOP_METHOD:
763
764 WalkInfo->MethodStack = MethodInfo->Next;
765
766 /*
767 * Check if there is no return statement at the end of the
768 * method AND we can actually get there -- i.e., the execution
769 * of the method can possibly terminate without a return statement.
770 */
771 if ((!AnLastStatementIsReturn (Op)) &&
772 (!(Op->Asl.CompileFlags & OP_HAS_NO_EXIT)))
773 {
774 /*
775 * No return statement, and execution can possibly exit
776 * via this path. This is equivalent to Return ()
777 */
778 MethodInfo->NumReturnNoValue++;
779 }
780
781 /*
782 * Check for case where some return statements have a return value
783 * and some do not. Exit without a return statement is a return with
784 * no value
785 */
786 if (MethodInfo->NumReturnNoValue &&
787 MethodInfo->NumReturnWithValue)
788 {
789 ExternalPath = AcpiNsGetNormalizedPathname (Op->Asl.Node, TRUE);
790
791 AslError (ASL_WARNING, ASL_MSG_RETURN_TYPES, Op,
792 ExternalPath);
793
794 if (ExternalPath)
795 {
796 ACPI_FREE (ExternalPath);
797 }
798 }
799
800 /*
801 * If there are any RETURN() statements with no value, or there is a
802 * control path that allows the method to exit without a return value,
803 * we mark the method as a method that does not return a value. This
804 * knowledge can be used to check method invocations that expect a
805 * returned value.
806 */
807 if (MethodInfo->NumReturnNoValue)
808 {
809 if (MethodInfo->NumReturnWithValue)
810 {
811 Op->Asl.CompileFlags |= OP_METHOD_SOME_NO_RETVAL;
812 }
813 else
814 {
815 Op->Asl.CompileFlags |= OP_METHOD_NO_RETVAL;
816 }
817 }
818
819 /*
820 * Check predefined method names for correct return behavior
821 * and correct number of arguments. Also, some special checks
822 * For GPE and _REG methods.
823 */
824 if (ApCheckForPredefinedMethod (Op, MethodInfo))
825 {
826 /* Special check for two names like _L01 and _E01 in same scope */
827
828 ApCheckForGpeNameConflict (Op);
829
830 /*
831 * Special check for _REG: Must have an operation region definition
832 * within the same scope!
833 */
834 ApCheckRegMethod (Op);
835 }
836
837 ACPI_FREE (MethodInfo);
838 break;
839
840 case PARSEOP_NAME:
841
842 /* Special check for two names like _L01 and _E01 in same scope */
843
844 ApCheckForGpeNameConflict (Op);
845 break;
846
847 case PARSEOP_RETURN:
848
849 /*
850 * If the parent is a predefined method name, attempt to typecheck
851 * the return value. Only static types can be validated.
852 */
853 ApCheckPredefinedReturnValue (Op, MethodInfo);
854
855 /*
856 * The parent block does not "exit" and continue execution -- the
857 * method is terminated here with the Return() statement.
858 */
859 Op->Asl.Parent->Asl.CompileFlags |= OP_HAS_NO_EXIT;
860
861 /* Used in the "typing" pass later */
862
863 Op->Asl.ParentMethod = MethodInfo->Op;
864
865 /*
866 * If there is a peer node after the return statement, then this
867 * node is unreachable code -- i.e., it won't be executed because of
868 * the preceding Return() statement.
869 */
870 if (Op->Asl.Next)
871 {
872 AslError (ASL_WARNING, ASL_MSG_UNREACHABLE_CODE,
873 Op->Asl.Next, NULL);
874 }
875 break;
876
877 case PARSEOP_IF:
878
879 if ((Op->Asl.CompileFlags & OP_HAS_NO_EXIT) &&
880 (Op->Asl.Next) &&
881 (Op->Asl.Next->Asl.ParseOpcode == PARSEOP_ELSE))
882 {
883 /*
884 * This IF has a corresponding ELSE. The IF block has no exit,
885 * (it contains an unconditional Return)
886 * mark the ELSE block to remember this fact.
887 */
888 Op->Asl.Next->Asl.CompileFlags |= OP_IF_HAS_NO_EXIT;
889 }
890 break;
891
892 case PARSEOP_ELSE:
893
894 if ((Op->Asl.CompileFlags & OP_HAS_NO_EXIT) &&
895 (Op->Asl.CompileFlags & OP_IF_HAS_NO_EXIT))
896 {
897 /*
898 * This ELSE block has no exit and the corresponding IF block
899 * has no exit either. Therefore, the parent node has no exit.
900 */
901 Op->Asl.Parent->Asl.CompileFlags |= OP_HAS_NO_EXIT;
902 }
903 break;
904
905
906 default:
907
908 if ((Op->Asl.CompileFlags & OP_HAS_NO_EXIT) &&
909 (Op->Asl.Parent))
910 {
911 /* If this node has no exit, then the parent has no exit either */
912
913 Op->Asl.Parent->Asl.CompileFlags |= OP_HAS_NO_EXIT;
914 }
915 break;
916 }
917
918 return (AE_OK);
919 }
920