diff options
Diffstat (limited to 'source/compiler')
-rw-r--r-- | source/compiler/aslcompile.c | 1 | ||||
-rw-r--r-- | source/compiler/aslcompiler.h | 10 | ||||
-rw-r--r-- | source/compiler/aslcompiler.l | 2 | ||||
-rw-r--r-- | source/compiler/aslerror.c | 165 | ||||
-rw-r--r-- | source/compiler/aslglobal.h | 3 | ||||
-rw-r--r-- | source/compiler/aslhelp.c | 1 | ||||
-rw-r--r-- | source/compiler/aslmessages.c | 3 | ||||
-rw-r--r-- | source/compiler/aslmessages.h | 1 | ||||
-rw-r--r-- | source/compiler/asloptions.c | 16 | ||||
-rw-r--r-- | source/compiler/aslparseop.c | 16 | ||||
-rw-r--r-- | source/compiler/aslrules.y | 1 | ||||
-rw-r--r-- | source/compiler/asltokens.y | 1 | ||||
-rw-r--r-- | source/compiler/asltransform.c | 31 | ||||
-rw-r--r-- | source/compiler/asltypes.h | 9 | ||||
-rw-r--r-- | source/compiler/aslutils.c | 67 | ||||
-rw-r--r-- | source/compiler/dtcompile.c | 21 | ||||
-rw-r--r-- | source/compiler/dtcompiler.h | 1 | ||||
-rw-r--r-- | source/compiler/dttemplate.h | 9 | ||||
-rw-r--r-- | source/compiler/dtutils.c | 2 | ||||
-rw-r--r-- | source/compiler/prmacros.c | 2 |
20 files changed, 313 insertions, 49 deletions
diff --git a/source/compiler/aslcompile.c b/source/compiler/aslcompile.c index 181fc364c745..385684401392 100644 --- a/source/compiler/aslcompile.c +++ b/source/compiler/aslcompile.c @@ -815,6 +815,7 @@ CmCleanupAndExit ( BOOLEAN DeleteAmlFile = FALSE; + AslCheckExpectedExceptions (); AePrintErrorLog (ASL_FILE_STDERR); if (Gbl_DebugFlag) { diff --git a/source/compiler/aslcompiler.h b/source/compiler/aslcompiler.h index c3794246ec94..fdf4dbf7de52 100644 --- a/source/compiler/aslcompiler.h +++ b/source/compiler/aslcompiler.h @@ -413,12 +413,20 @@ AslError ( ACPI_PARSE_OBJECT *Op, char *ExtraMessage); +void +AslCheckExpectedExceptions ( + void); + +ACPI_STATUS +AslExpectException ( + char *MessageIdString); + ACPI_STATUS AslDisableException ( char *MessageIdString); BOOLEAN -AslIsExceptionDisabled ( +AslIsExceptionIgnored ( UINT8 Level, UINT16 MessageId); diff --git a/source/compiler/aslcompiler.l b/source/compiler/aslcompiler.l index 4b36058b6ea7..b49233be7f14 100644 --- a/source/compiler/aslcompiler.l +++ b/source/compiler/aslcompiler.l @@ -809,7 +809,7 @@ NamePathTail [.]{NameSeg} "__FILE__" { count (0); return (PARSEOP___FILE__); } "__LINE__" { count (0); return (PARSEOP___LINE__); } "__PATH__" { count (0); return (PARSEOP___PATH__); } - +"__METHOD__" { count (0); return (PARSEOP___METHOD__); } {NameSeg} { char *s; count (0); diff --git a/source/compiler/aslerror.c b/source/compiler/aslerror.c index b6f7ee7dd9c2..ec91ca3e7d06 100644 --- a/source/compiler/aslerror.c +++ b/source/compiler/aslerror.c @@ -160,6 +160,16 @@ static void AeAddToErrorLog ( ASL_ERROR_MSG *Enode); +static BOOLEAN +AslIsExceptionExpected ( + UINT8 Level, + UINT16 MessageId); + +static BOOLEAN +AslIsExceptionDisabled ( + UINT8 Level, + UINT16 MessageId); + /******************************************************************************* * @@ -806,6 +816,115 @@ AslCommonError ( return; } +/******************************************************************************* + * + * FUNCTION: AslIsExceptionIgnored + * + * PARAMETERS: Level - Seriousness (Warning/error, etc.) + * MessageId - Index into global message buffer + * + * RETURN: BOOLEAN + * + * DESCRIPTION: Check if a particular exception is ignored. In this case it + * means that the exception is (expected or disabled. + * + ******************************************************************************/ + +BOOLEAN +AslIsExceptionIgnored ( + UINT8 Level, + UINT16 MessageId) +{ + BOOLEAN ExceptionIgnored; + + + /* Note: this allows exception to be disabled and expected */ + + ExceptionIgnored = AslIsExceptionDisabled (Level, MessageId); + ExceptionIgnored |= AslIsExceptionExpected (Level, MessageId); + + return (Gbl_AllExceptionsDisabled || ExceptionIgnored); +} + + +/******************************************************************************* + * + * FUNCTION: AslCheckExpectException + * + * PARAMETERS: none + * + * RETURN: none + * + * DESCRIPTION: Check the global expected messages table and raise an error + * for each message that has not been received. + * + ******************************************************************************/ + +void +AslCheckExpectedExceptions ( + void) +{ + UINT8 i; + + for (i = 0; i < Gbl_ExpectedMessagesIndex; ++i) + { + if (!Gbl_ExpectedMessages[i].MessageReceived) + { + AslError (ASL_ERROR, ASL_MSG_EXCEPTION_NOT_RECEIVED, NULL, + Gbl_ExpectedMessages[i].MessageIdStr); + } + } +} + + +/******************************************************************************* + * + * FUNCTION: AslExpectException + * + * PARAMETERS: MessageIdString - ID of excepted exception during compile + * + * RETURN: Status + * + * DESCRIPTION: Enter a message ID into the global expected messages table + * If these messages are not raised during the compilation, throw + * an error. + * + ******************************************************************************/ + +ACPI_STATUS +AslExpectException ( + char *MessageIdString) +{ + UINT32 MessageId; + + + /* Convert argument to an integer and validate it */ + + MessageId = (UINT32) strtoul (MessageIdString, NULL, 0); + + if (MessageId > 6999) + { + printf ("\"%s\" is not a valid warning/remark/erro ID\n", + MessageIdString); + return (AE_BAD_PARAMETER); + } + + /* Insert value into the global expected message array */ + + if (Gbl_ExpectedMessagesIndex >= ASL_MAX_EXPECTED_MESSAGES) + { + printf ("Too many messages have been registered as expected (max %u)\n", + ASL_MAX_DISABLED_MESSAGES); + return (AE_LIMIT); + } + + Gbl_ExpectedMessages[Gbl_ExpectedMessagesIndex].MessageId = MessageId; + Gbl_ExpectedMessages[Gbl_ExpectedMessagesIndex].MessageIdStr = MessageIdString; + Gbl_ExpectedMessages[Gbl_ExpectedMessagesIndex].MessageReceived = FALSE; + Gbl_ExpectedMessagesIndex++; + return (AE_OK); +} + /******************************************************************************* * @@ -866,7 +985,48 @@ AslDisableException ( * ******************************************************************************/ -BOOLEAN +static BOOLEAN +AslIsExceptionExpected ( + UINT8 Level, + UINT16 MessageId) +{ + UINT32 EncodedMessageId; + UINT32 i; + + + /* + * Mark this exception as received + */ + EncodedMessageId = AeBuildFullExceptionCode (Level, MessageId); + for (i = 0; i < Gbl_ExpectedMessagesIndex; i++) + { + /* Simple implementation via fixed array */ + + if (EncodedMessageId == Gbl_ExpectedMessages[i].MessageId) + { + return (Gbl_ExpectedMessages[i].MessageReceived = TRUE); + } + } + + return (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: AslIsExceptionDisabled + * + * PARAMETERS: Level - Seriousness (Warning/error, etc.) + * MessageId - Index into global message buffer + * + * RETURN: TRUE if exception/message should be ignored + * + * DESCRIPTION: Check if the user has specified options such that this + * exception should be ignored + * + ******************************************************************************/ + +static BOOLEAN AslIsExceptionDisabled ( UINT8 Level, UINT16 MessageId) @@ -940,8 +1100,7 @@ AslError ( /* Check if user wants to ignore this exception */ - if (Gbl_AllExceptionsDisabled || - AslIsExceptionDisabled (Level, MessageId)) + if (AslIsExceptionIgnored (Level, MessageId)) { return; } diff --git a/source/compiler/aslglobal.h b/source/compiler/aslglobal.h index 0c58041ffb18..169b25e745ec 100644 --- a/source/compiler/aslglobal.h +++ b/source/compiler/aslglobal.h @@ -252,6 +252,7 @@ extern int AslCompilerdebug; #define ASL_DEFAULT_LINE_BUFFER_SIZE (1024 * 32) /* 32K */ #define ASL_MSG_BUFFER_SIZE (1024 * 32) /* 32k */ #define ASL_MAX_DISABLED_MESSAGES 32 +#define ASL_MAX_EXPECTED_MESSAGES 32 #define HEX_TABLE_LINE_SIZE 8 #define HEX_LISTING_LINE_SIZE 8 @@ -396,6 +397,7 @@ ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_CurrentHexColumn, 0); ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_CurrentAmlOffset, 0); ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_CurrentLine, 0); ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_DisabledMessagesIndex, 0); +ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_ExpectedMessagesIndex, 0); ASL_EXTERN UINT8 ASL_INIT_GLOBAL (Gbl_HexBytesWereWritten, FALSE); ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_NumNamespaceObjects, 0); ASL_EXTERN UINT32 ASL_INIT_GLOBAL (Gbl_ReservedMethods, 0); @@ -438,6 +440,7 @@ ASL_EXTERN char MsgBuffer[ASL_MSG_BUFFER_SIZE]; ASL_EXTERN char StringBuffer[ASL_MSG_BUFFER_SIZE]; ASL_EXTERN char StringBuffer2[ASL_MSG_BUFFER_SIZE]; ASL_EXTERN UINT32 Gbl_DisabledMessages[ASL_MAX_DISABLED_MESSAGES]; +ASL_EXTERN ASL_EXPECTED_MESSAGE Gbl_ExpectedMessages[ASL_MAX_EXPECTED_MESSAGES]; #endif /* __ASLGLOBAL_H */ diff --git a/source/compiler/aslhelp.c b/source/compiler/aslhelp.c index 2b0dc7632e83..18eab858c213 100644 --- a/source/compiler/aslhelp.c +++ b/source/compiler/aslhelp.c @@ -205,6 +205,7 @@ Usage ( ACPI_OPTION ("-vi", "Less verbose errors and warnings for use with IDEs"); ACPI_OPTION ("-vr", "Disable remarks"); ACPI_OPTION ("-vw <messageid>", "Disable specific warning or remark"); + ACPI_OPTION ("-vx <messageid>", "Expect a specific warning, remark, or error"); ACPI_OPTION ("-w <1|2|3>", "Set warning reporting level"); ACPI_OPTION ("-we", "Report warnings as errors"); diff --git a/source/compiler/aslmessages.c b/source/compiler/aslmessages.c index eb3d23dd9dfa..b87d54991f7b 100644 --- a/source/compiler/aslmessages.c +++ b/source/compiler/aslmessages.c @@ -348,7 +348,8 @@ const char *AslCompilerMsgs [] = /* ASL_MSG_ARG_AS_LOCAL_NOT_USED */ "Method Argument (as a local) is set but never used", /* ASL_MSG_ARG_NOT_USED */ "Method Argument is never used", /* ASL_MSG_CONSTANT_REQUIRED */ "Non-reducible expression", -/* ASL_MSG_CROSS_TABLE_SCOPE */ "Illegal open scope on external object from within DSDT" +/* ASL_MSG_CROSS_TABLE_SCOPE */ "Illegal open scope on external object from within DSDT", +/* ASL_MSG_EXCEPTION_NOT_RECEIVED */ "Expected remark, warning, or error did not occur. Message ID:" }; /* Table compiler */ diff --git a/source/compiler/aslmessages.h b/source/compiler/aslmessages.h index 86fb16317d1b..68216e5c0756 100644 --- a/source/compiler/aslmessages.h +++ b/source/compiler/aslmessages.h @@ -351,6 +351,7 @@ typedef enum ASL_MSG_ARG_NOT_USED, ASL_MSG_CONSTANT_REQUIRED, ASL_MSG_CROSS_TABLE_SCOPE, + ASL_MSG_EXCEPTION_NOT_RECEIVED, /* These messages are used by the Data Table compiler only */ diff --git a/source/compiler/asloptions.c b/source/compiler/asloptions.c index 2dcd49402e04..6d39f6d25492 100644 --- a/source/compiler/asloptions.c +++ b/source/compiler/asloptions.c @@ -954,6 +954,22 @@ AslDoOptions ( } break; + case 'x': + + /* Get the required argument */ + + if (AcpiGetoptArgument (argc, argv)) + { + return (-1); + } + + Status = AslExpectException (AcpiGbl_Optarg); + if (ACPI_FAILURE (Status)) + { + return (-1); + } + break; + default: printf ("Unknown option: -v%s\n", AcpiGbl_Optarg); diff --git a/source/compiler/aslparseop.c b/source/compiler/aslparseop.c index 4e6e5a16276c..41badcee5211 100644 --- a/source/compiler/aslparseop.c +++ b/source/compiler/aslparseop.c @@ -685,10 +685,10 @@ TrCreateNullTargetOp ( * DESCRIPTION: Create a leaf op (no children or peers) for one of the * special constants - __LINE__, __FILE__, and __DATE__. * - * Note: An implemenation of __FUNC__ cannot happen here because we don't - * have a full parse tree at this time and cannot find the parent control - * method. If it is ever needed, __FUNC__ must be implemented later, after - * the parse tree has been fully constructed. + * Note: The fullimplemenation of __METHOD__ cannot happen here because we + * don't have a full parse tree at this time and cannot find the parent + * control method. __METHOD__ must be implemented later, after the parse + * tree has been fully constructed. * ******************************************************************************/ @@ -711,6 +711,14 @@ TrCreateConstantLeafOp ( Op->Asl.Value.Integer = Op->Asl.LineNumber; break; + case PARSEOP___METHOD__: + + /* Will become a string literal later */ + + Op = TrAllocateOp (PARSEOP___METHOD__); + Op->Asl.Value.String = NULL; + break; + case PARSEOP___PATH__: Op = TrAllocateOp (PARSEOP_STRING_LITERAL); diff --git a/source/compiler/aslrules.y b/source/compiler/aslrules.y index eb7850697b41..f26ea874b3ab 100644 --- a/source/compiler/aslrules.y +++ b/source/compiler/aslrules.y @@ -592,6 +592,7 @@ ConstExprTerm | PARSEOP___FILE__ {$$ = TrCreateConstantLeafOp (PARSEOP___FILE__);} | PARSEOP___LINE__ {$$ = TrCreateConstantLeafOp (PARSEOP___LINE__);} | PARSEOP___PATH__ {$$ = TrCreateConstantLeafOp (PARSEOP___PATH__);} + | PARSEOP___METHOD__ {$$ = TrCreateConstantLeafOp (PARSEOP___METHOD__);} ; Integer diff --git a/source/compiler/asltokens.y b/source/compiler/asltokens.y index e6e9006d0475..38c55c186bbd 100644 --- a/source/compiler/asltokens.y +++ b/source/compiler/asltokens.y @@ -637,3 +637,4 @@ NoEcho(' %token <i> PARSEOP___FILE__ %token <i> PARSEOP___LINE__ %token <i> PARSEOP___PATH__ +%token <i> PARSEOP___METHOD__ diff --git a/source/compiler/asltransform.c b/source/compiler/asltransform.c index d3ed53a14dcd..daaca947ff45 100644 --- a/source/compiler/asltransform.c +++ b/source/compiler/asltransform.c @@ -430,6 +430,8 @@ static void TrTransformSubtree ( ACPI_PARSE_OBJECT *Op) { + ACPI_PARSE_OBJECT *MethodOp; + if (Op->Asl.AmlOpcode == AML_RAW_DATA_BYTE) { @@ -465,6 +467,35 @@ TrTransformSubtree ( break; + case PARSEOP___METHOD__: + + /* Transform to a string op containing the parent method name */ + + Op->Asl.ParseOpcode = PARSEOP_STRING_LITERAL; + UtSetParseOpName (Op); + + /* Find the parent control method op */ + + MethodOp = Op; + while (MethodOp) + { + if (MethodOp->Asl.ParseOpcode == PARSEOP_METHOD) + { + /* First child contains the method name */ + + MethodOp = MethodOp->Asl.Child; + Op->Asl.Value.String = MethodOp->Asl.Value.String; + return; + } + + MethodOp = MethodOp->Asl.Parent; + } + + /* At the root, invocation not within a control method */ + + Op->Asl.Value.String = "\\"; + break; + default: /* Nothing to do here for other opcodes */ diff --git a/source/compiler/asltypes.h b/source/compiler/asltypes.h index 4c2a27729fd1..e4250871fd12 100644 --- a/source/compiler/asltypes.h +++ b/source/compiler/asltypes.h @@ -355,6 +355,15 @@ typedef struct asl_error_msg } ASL_ERROR_MSG; +/* An entry in the expected messages array */ +typedef struct asl_expected_message +{ + UINT32 MessageId; + char *MessageIdStr; + BOOLEAN MessageReceived; + +} ASL_EXPECTED_MESSAGE; + /* An entry in the listing file stack (for include files) */ diff --git a/source/compiler/aslutils.c b/source/compiler/aslutils.c index fd91baeb20e5..c5ff42c0156c 100644 --- a/source/compiler/aslutils.c +++ b/source/compiler/aslutils.c @@ -174,6 +174,12 @@ UtAttachNameseg ( ACPI_PARSE_OBJECT *Op, char *Name); +static void +UtReallocLineBuffers ( + char **Buffer, + UINT32 OldSize, + UINT32 NewSize); + /******************************************************************************* * @@ -733,43 +739,48 @@ UtExpandLineBuffers ( Gbl_LineBufferSize, NewSize); } - Gbl_CurrentLineBuffer = realloc (Gbl_CurrentLineBuffer, NewSize); + UtReallocLineBuffers (&Gbl_CurrentLineBuffer, Gbl_LineBufferSize, NewSize); + UtReallocLineBuffers (&Gbl_MainTokenBuffer, Gbl_LineBufferSize, NewSize); + UtReallocLineBuffers (&Gbl_MacroTokenBuffer, Gbl_LineBufferSize, NewSize); + UtReallocLineBuffers (&Gbl_ExpressionTokenBuffer, Gbl_LineBufferSize, NewSize); + Gbl_LineBufPtr = Gbl_CurrentLineBuffer; - if (!Gbl_CurrentLineBuffer) - { - goto ErrorExit; - } + Gbl_LineBufferSize = NewSize; +} - Gbl_MainTokenBuffer = realloc (Gbl_MainTokenBuffer, NewSize); - if (!Gbl_MainTokenBuffer) - { - goto ErrorExit; - } - Gbl_MacroTokenBuffer = realloc (Gbl_MacroTokenBuffer, NewSize); - if (!Gbl_MacroTokenBuffer) - { - goto ErrorExit; - } +/****************************************************************************** + * + * FUNCTION: UtReallocLineBuffers + * + * PARAMETERS: Buffer - Buffer to realloc + * OldSize - Old size of Buffer + * NewSize - New size of Buffer + * + * RETURN: none + * + * DESCRIPTION: Reallocate and initialize Buffer + * + *****************************************************************************/ + +static void +UtReallocLineBuffers ( + char **Buffer, + UINT32 OldSize, + UINT32 NewSize) +{ - Gbl_ExpressionTokenBuffer = realloc (Gbl_ExpressionTokenBuffer, NewSize); - if (!Gbl_ExpressionTokenBuffer) + *Buffer = realloc (*Buffer, NewSize); + if (*Buffer) { - goto ErrorExit; + memset (*Buffer + OldSize, 0, NewSize - OldSize); + return; } - Gbl_LineBufferSize = NewSize; - return; - - - /* On error above, simply issue error messages and abort, cannot continue */ - -ErrorExit: printf ("Could not increase line buffer size from %u to %u\n", - Gbl_LineBufferSize, Gbl_LineBufferSize * 2); + OldSize, NewSize); - AslError (ASL_ERROR, ASL_MSG_BUFFER_ALLOCATION, - NULL, NULL); + AslError (ASL_ERROR, ASL_MSG_BUFFER_ALLOCATION, NULL, NULL); AslAbort (); } diff --git a/source/compiler/dtcompile.c b/source/compiler/dtcompile.c index 45274168c543..e74fed517315 100644 --- a/source/compiler/dtcompile.c +++ b/source/compiler/dtcompile.c @@ -486,18 +486,21 @@ DtCompileDataTable ( } else if (TableData->TableInfo) { - /* Simple table, just walk the info table */ + /* Simple table, just walk the info table, unless its empty */ - Subtable = NULL; - Status = DtCompileTable (FieldList, TableData->TableInfo, - &Subtable, TRUE); - if (ACPI_FAILURE (Status)) + if (FieldList && *FieldList) { - return (Status); - } + Subtable = NULL; + Status = DtCompileTable (FieldList, TableData->TableInfo, + &Subtable, TRUE); + if (ACPI_FAILURE (Status)) + { + return (Status); + } - DtInsertSubtable (Gbl_RootTable, Subtable); - DtPopSubtable (); + DtInsertSubtable (Gbl_RootTable, Subtable); + DtPopSubtable (); + } } else { diff --git a/source/compiler/dtcompiler.h b/source/compiler/dtcompiler.h index 61b40b4a93ef..1e81c5800c5c 100644 --- a/source/compiler/dtcompiler.h +++ b/source/compiler/dtcompiler.h @@ -726,6 +726,7 @@ extern const unsigned char TemplateRasf[]; extern const unsigned char TemplateRsdt[]; extern const unsigned char TemplateS3pt[]; extern const unsigned char TemplateSbst[]; +extern const unsigned char TemplateSdei[]; extern const unsigned char TemplateSlic[]; extern const unsigned char TemplateSlit[]; extern const unsigned char TemplateSpcr[]; diff --git a/source/compiler/dttemplate.h b/source/compiler/dttemplate.h index bb4dded4e634..8d27359d9ad0 100644 --- a/source/compiler/dttemplate.h +++ b/source/compiler/dttemplate.h @@ -1178,6 +1178,15 @@ const unsigned char TemplateSbst[] = 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 /* 00000028 "........" */ }; +const unsigned char TemplateSdei[] = +{ + 0x53,0x44,0x45,0x49,0x3e,0x00,0x00,0x00, /* 00000000 "SDEI>..." */ + 0x01,0x59,0x41,0x52,0x4d,0x20,0x20,0x20, /* 00000008 ".mARM " */ + 0x54,0x45,0x4D,0x50,0x4C,0x41,0x54,0x45, /* 00000010 "TEMPLATE" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x30,0x09,0x16,0x20 /* 00000028 "0.. " */ +}; + const unsigned char TemplateSlic[] = { 0x53,0x4C,0x49,0x43,0x76,0x01,0x00,0x00, /* 00000000 "SLICv..." */ diff --git a/source/compiler/dtutils.c b/source/compiler/dtutils.c index 8807217510b8..6edcf637c3fd 100644 --- a/source/compiler/dtutils.c +++ b/source/compiler/dtutils.c @@ -190,7 +190,7 @@ DtError ( /* Check if user wants to ignore this exception */ - if (AslIsExceptionDisabled (Level, MessageId)) + if (AslIsExceptionIgnored (Level, MessageId)) { return; } diff --git a/source/compiler/prmacros.c b/source/compiler/prmacros.c index 55aab4668124..675d4522cb93 100644 --- a/source/compiler/prmacros.c +++ b/source/compiler/prmacros.c @@ -483,7 +483,7 @@ PrAddMacro ( { /* Search the macro arg list for matching arg */ - for (i = 0; Args[i].Name && (i < PR_MAX_MACRO_ARGS); i++) + for (i = 0; ((i < PR_MAX_MACRO_ARGS) && Args[i].Name); i++) { /* * Save argument offset within macro body. This is the mechanism |