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