Changeset 2769 for trunk/src/kmk/kmk_cc_exec.c
- Timestamp:
- Feb 1, 2015, 1:44:30 AM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/kmk_cc_exec.c
r2768 r2769 65 65 typedef KMKCCBLOCK *PKMKCCBLOCK; 66 66 67 /** Expansion instructions. */ 67 /** 68 * String expansion statistics. 69 */ 70 typedef struct KMKCCEXPSTATS 71 { 72 /** Max expanded size. */ 73 uint32_t cchMax; 74 /** Recent average size. */ 75 uint32_t cchAvg; 76 } KMKCCEXPSTATS; 77 typedef KMKCCEXPSTATS *PKMKCCEXPSTATS; 78 79 /** 80 * Expansion instructions. 81 */ 68 82 typedef enum KMKCCEXPINSTR 69 83 { … … 74 88 /** Insert an expanded variable value, the name is dynamic (sub prog). */ 75 89 kKmkCcExpInstr_DynamicVariable, 90 /** Insert an expanded variable value, which name we already know, doing 91 * search an replace on a string. */ 92 kKmkCcExpInstr_SearchAndReplacePlainVariable, 76 93 /** Insert the output of function that requires no argument expansion. */ 77 94 kKmkCcExpInstr_PlainFunction, 78 95 /** Insert the output of function that requires dynamic expansion of one ore 79 * more arguments. */96 * more arguments. (Dynamic is perhaps not such a great name, but whatever.) */ 80 97 kKmkCcExpInstr_DynamicFunction, 81 98 /** Jump to a new instruction block. */ … … 95 112 typedef KMKCCEXPCORE *PKMKCCEXPCORE; 96 113 114 /** 115 * String expansion sub program. 116 */ 97 117 typedef struct kmk_cc_exp_subprog 98 118 { 99 119 /** Pointer to the first instruction. */ 100 120 PKMKCCEXPCORE pFirstInstr; 101 /** Max expanded size. */ 102 uint32_t cbMax; 103 /** Recent average size. */ 104 uint32_t cbAvg; 121 /** Statistics. */ 122 KMKCCEXPSTATS Stats; 105 123 } KMKCCEXPSUBPROG; 106 124 typedef KMKCCEXPSUBPROG *PKMKCCEXPSUBPROG; 107 125 126 /** 127 * kKmkCcExpInstr_CopyString instruction format. 128 */ 108 129 typedef struct kmk_cc_exp_copy_string 109 130 { … … 117 138 typedef KMKCCEXPCOPYSTRING *PKMKCCEXPCOPYSTRING; 118 139 140 /** 141 * kKmkCcExpInstr_PlainVariable instruction format. 142 */ 119 143 typedef struct kmk_cc_exp_plain_variable 120 144 { 121 145 /** The core instruction. */ 122 146 KMKCCEXPCORE Core; 123 /** The variable strcache entry for this variable. */124 struct strcache2_entry const *pNameEntry;147 /** The name of the variable (points into variable_strcache). */ 148 const char *pszName; 125 149 } KMKCCEXPPLAINVAR; 126 150 typedef KMKCCEXPPLAINVAR *PKMKCCEXPPLAINVAR; 127 151 152 /** 153 * kKmkCcExpInstr_DynamicVariable instruction format. 154 */ 128 155 typedef struct kmk_cc_exp_dynamic_variable 129 156 { 130 157 /** The core instruction. */ 131 158 KMKCCEXPCORE Core; 132 /** Where to continue after this instruction. This is necessary since the 133 * subprogram is allocated after us in the instruction block. Since the sub 134 * program is of variable size, we don't even know if we're still in the same 135 * instruction block. So, we include a jump here. */ 159 /** Where to continue after this instruction. (This is necessary since the 160 * instructions of the subprogram are emitted after this instruction.) */ 136 161 PKMKCCEXPCORE pNext; 137 162 /** The subprogram that will give us the variable name. */ … … 140 165 typedef KMKCCEXPDYNVAR *PKMKCCEXPDYNVAR; 141 166 167 /** 168 * kKmkCcExpInstr_SearchAndReplacePlainVariable instruction format. 169 */ 170 typedef struct kmk_cc_exp_sr_plain_variable 171 { 172 /** The core instruction. */ 173 KMKCCEXPCORE Core; 174 /** Where to continue after this instruction. (This is necessary since the 175 * instruction contains string data of variable size.) */ 176 PKMKCCEXPCORE pNext; 177 /** The name of the variable (points into variable_strcache). */ 178 const char *pszName; 179 /** Search pattern. */ 180 const char *pszSearchPattern; 181 /** Replacement pattern. */ 182 const char *pszReplacePattern; 183 /** Offset into pszSearchPattern of the significant '%' char. */ 184 uint32_t offPctSearchPattern; 185 /** Offset into pszReplacePattern of the significant '%' char. */ 186 uint32_t offPctReplacePattern; 187 } KMKCCEXPSRPLAINVAR; 188 typedef KMKCCEXPSRPLAINVAR *PKMKCCEXPSRPLAINVAR; 189 190 /** 191 * Instruction format parts common to both kKmkCcExpInstr_PlainFunction and 192 * kKmkCcExpInstr_DynamicFunction. 193 */ 142 194 typedef struct kmk_cc_exp_function_core 143 195 { … … 146 198 /** Number of arguments. */ 147 199 uint32_t cArgs; 148 /** Where to continue after this instruction. This is necessary since the 149 * instruction is of variable size and we don't even know if we're still in the 150 * same instruction block. So, we include a jump here. */ 200 /** Where to continue after this instruction. (This is necessary since the 201 * instructions are of variable size and may be followed by string data.) */ 151 202 PKMKCCEXPCORE pNext; 152 203 /** … … 164 215 typedef KMKCCEXPFUNCCORE *PKMKCCEXPFUNCCORE; 165 216 217 /** 218 * Instruction format for kKmkCcExpInstr_PlainFunction. 219 */ 166 220 typedef struct kmk_cc_exp_plain_function 167 221 { … … 178 232 #define KMKCCEXPPLAINFUNC_SIZE(a_cArgs) (sizeof(KMKCCEXPFUNCCORE) + (a_cArgs + 1) * sizeof(const char *)) 179 233 234 /** 235 * Instruction format for kKmkCcExpInstr_DynamicFunction. 236 */ 180 237 typedef struct kmk_cc_exp_dyn_function 181 238 { … … 209 266 + (a_cArgs) * sizeof(((PKMKCCEXPDYNFUNC)(uintptr_t)42)->aArgs[0]) ) 210 267 268 /** 269 * Instruction format for kKmkCcExpInstr_Jump. 270 */ 211 271 typedef struct kmk_cc_exp_jump 212 272 { … … 227 287 /** List of blocks for this program (LIFO). */ 228 288 PKMKCCBLOCK pBlockTail; 229 /** Max expanded size. */ 230 uint32_t cbMax; 231 /** Recent average size. */ 232 uint32_t cbAvg; 289 /** Statistics. */ 290 KMKCCEXPSTATS Stats; 233 291 } KMKCCEXPPROG; 234 292 /** Pointer to a string expansion program. */ … … 245 303 *******************************************************************************/ 246 304 static int kmk_cc_exp_compile_subprog(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr, PKMKCCEXPSUBPROG pSubProg); 305 static char *kmk_exec_expand_subprog_to_tmp(PKMKCCEXPSUBPROG pSubProg, uint32_t *pcch); 247 306 248 307 … … 741 800 742 801 /** 743 * Emits a kKmkCcExpInstr_PlainVariable. 802 * Emits either a kKmkCcExpInstr_PlainVariable or 803 * kKmkCcExpInstr_SearchAndReplacePlainVariable instruction. 744 804 * 745 805 * @returns 0 on success, non-zero on failure. … … 750 810 * nothing will be emitted. 751 811 */ 752 static int kmk_cc_exp_emit_plain_variable (PKMKCCBLOCK *ppBlockTail, const char *pchName, uint32_t cchName)812 static int kmk_cc_exp_emit_plain_variable_maybe_sr(PKMKCCBLOCK *ppBlockTail, const char *pchName, uint32_t cchName) 753 813 { 754 814 if (cchName > 0) 755 815 { 756 PKMKCCEXPPLAINVAR pInstr = (PKMKCCEXPPLAINVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr)); 757 pInstr->Core.enmOpCode = kKmkCcExpInstr_PlainVariable; 758 pInstr->pNameEntry = strcache2_get_entry(&variable_strcache, strcache2_add(&variable_strcache, pchName, cchName)); 816 /* 817 * Hopefully, we're not expected to do any search and replace on the 818 * expanded variable string later... Requires both ':' and '='. 819 */ 820 const char *pchEqual; 821 const char *pchColon = (const char *)memchr(pchName, ':', cchName); 822 if ( pchColon == NULL 823 || (pchEqual = (const char *)memchr(pchColon + 1, ':', cchName - (pchColon - pchName - 1))) == NULL 824 || pchEqual == pchEqual + 1) 825 { 826 PKMKCCEXPPLAINVAR pInstr = (PKMKCCEXPPLAINVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr)); 827 pInstr->Core.enmOpCode = kKmkCcExpInstr_PlainVariable; 828 pInstr->pszName = strcache2_add(&variable_strcache, pchName, cchName); 829 } 830 else if (pchColon != pchName) 831 { 832 /* 833 * Okay, we need to do search and replace the variable value. 834 * This is performed by patsubst_expand_pat using '%' patterns. 835 */ 836 uint32_t cchName2 = (uint32_t)(pchColon - pchName); 837 uint32_t cchSearch = (uint32_t)(pchEqual - pchColon - 1); 838 uint32_t cchReplace = cchName - cchName2 - cchSearch - 2; 839 const char *pchPct; 840 char *psz; 841 PKMKCCEXPSRPLAINVAR pInstr; 842 843 pInstr = (PKMKCCEXPSRPLAINVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr)); 844 pInstr->Core.enmOpCode = kKmkCcExpInstr_SearchAndReplacePlainVariable; 845 pInstr->pszName = strcache2_add(&variable_strcache, pchName, cchName2); 846 847 /* Figure out the search pattern, unquoting percent chars.. */ 848 psz = (char *)kmk_cc_block_byte_alloc(ppBlockTail, cchSearch + 2); 849 psz[0] = '%'; 850 memcpy(psz + 1, pchColon + 1, cchSearch); 851 psz[1 + cchSearch] = '\0'; 852 pchPct = find_percent(psz + 1); /* also performs unquoting */ 853 if (pchPct) 854 { 855 pInstr->pszSearchPattern = psz + 1; 856 pInstr->offPctSearchPattern = (uint32_t)(pchPct - psz - 1); 857 } 858 else 859 { 860 pInstr->pszSearchPattern = psz; 861 pInstr->offPctSearchPattern = 0; 862 } 863 864 /* Figure out the replacement pattern, unquoting percent chars.. */ 865 if (cchReplace == 0) 866 { 867 pInstr->pszReplacePattern = "%"; 868 pInstr->offPctReplacePattern = 0; 869 } 870 else 871 { 872 psz = (char *)kmk_cc_block_byte_alloc(ppBlockTail, cchReplace + 2); 873 psz[0] = '%'; 874 memcpy(psz + 1, pchEqual + 1, cchReplace); 875 psz[1 + cchReplace] = '\0'; 876 pchPct = find_percent(psz + 1); /* also performs unquoting */ 877 if (pchPct) 878 { 879 pInstr->pszReplacePattern = psz + 1; 880 pInstr->offPctReplacePattern = (uint32_t)(pchPct - psz - 1); 881 } 882 else 883 { 884 pInstr->pszReplacePattern = psz; 885 pInstr->offPctReplacePattern = 0; 886 } 887 } 888 889 /* Note down where the next instruction is after realigning the allocator. */ 890 kmk_cc_block_realign(ppBlockTail); 891 pInstr->pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail); 892 } 759 893 } 760 894 return 0; … … 837 971 { 838 972 /* There are several alternative ways of finding the ending 839 parenthesis / braces. GNU make only consideres open & 840 close chars of the one we're processing, and it does not 841 matter whether the opening paren / braces are preceeded by 842 any dollar char. Simple and efficient. */ 973 parenthesis / braces. 974 975 GNU make does one thing for functions and variable containing 976 any '$' chars before the first closing char. While for 977 variables where a closing char comes before any '$' char, a 978 simplified approach is taken. This means that for example: 979 980 Given VAR=var, the expressions "$(var())" and 981 "$($(VAR)())" would be expanded differently. 982 In the first case the variable "var(" would be 983 used and in the second "var()". 984 985 This code will not duplicate this weird behavior, but work 986 the same regardless of whether there is a '$' char before 987 the first closing char. */ 843 988 make_function_ptr_t pfnFunction; 844 989 const char *pszFunction; … … 865 1010 cchName++; 866 1011 } 1012 867 1013 if ( cchName >= MIN_FUNCTION_LENGTH 868 1014 && cchName <= MAX_FUNCTION_LENGTH … … 1002 1148 } 1003 1149 if (cDollars == 0) 1004 rc = kmk_cc_exp_emit_plain_variable (ppBlockTail, pchStr, cchName);1150 rc = kmk_cc_exp_emit_plain_variable_maybe_sr(ppBlockTail, pchStr, cchName); 1005 1151 else 1006 1152 rc = kmk_cc_exp_emit_dyn_variable(ppBlockTail, pchStr, cchName); … … 1012 1158 { 1013 1159 /* Single character variable name. */ 1014 rc = kmk_cc_exp_emit_plain_variable (ppBlockTail, pchStr, 1);1160 rc = kmk_cc_exp_emit_plain_variable_maybe_sr(ppBlockTail, pchStr, 1); 1015 1161 pchStr++; 1016 1162 cchStr--; … … 1046 1192 1047 1193 /** 1194 * Initializes string expansion program statistics. 1195 * @param pStats Pointer to the statistics structure to init. 1196 */ 1197 static void kmk_cc_exp_stats_init(PKMKCCEXPSTATS pStats) 1198 { 1199 pStats->cchAvg = 0; 1200 pStats->cchMax = 0; 1201 } 1202 1203 1204 /** 1048 1205 * Compiles a string expansion sub program. 1049 1206 * … … 1064 1221 assert(cchStr); 1065 1222 pSubProg->pFirstInstr = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail); 1066 pSubProg->cbMax = 0; 1067 pSubProg->cbAvg = 0; 1223 kmk_cc_exp_stats_init(&pSubProg->Stats); 1068 1224 return kmk_cc_exp_compile_common(ppBlockTail, pchStr, cchStr); 1069 1225 } … … 1095 1251 pProg->pBlockTail = pBlock; 1096 1252 pProg->pFirstInstr = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(pBlock); 1097 pProg->cbMax = 0; 1098 pProg->cbAvg = 0; 1253 kmk_cc_exp_stats_init(&pProg->Stats); 1099 1254 1100 1255 /* … … 1145 1300 1146 1301 1302 #ifndef NDEBUG 1303 /** 1304 * Used to check that function arguments are left alone. 1305 * @returns Updated hash. 1306 * @param uHash The current hash value. 1307 * @param psz The string to hash. 1308 */ 1309 static uint32_t kmk_exec_debug_string_hash(uint32_t uHash, const char *psz) 1310 { 1311 unsigned char ch; 1312 while ((ch = *(unsigned char const *)psz++) != '\0') 1313 uHash = (uHash << 6) + (uHash << 16) - uHash + (unsigned char)ch; 1314 return uHash; 1315 } 1316 #endif 1317 1318 1319 /** 1320 * String expansion execution worker for outputting a variable. 1321 * 1322 * @returns The new variable buffer position. 1323 * @param pVar The variable to reference. 1324 * @param pchDst The current variable buffer position. 1325 */ 1326 static char *kmk_exec_expand_worker_reference_variable(struct variable *pVar, char *pchDst) 1327 { 1328 if (pVar->value_length > 0) 1329 { 1330 if (!pVar->recursive) 1331 pchDst = variable_buffer_output(pchDst, pVar->value, pVar->value_length); 1332 else 1333 pchDst = reference_recursive_variable(pchDst, pVar); 1334 } 1335 else if (pVar->append) 1336 pchDst = reference_recursive_variable(pchDst, pVar); 1337 return pchDst; 1338 } 1339 1340 1341 /** 1342 * Executes a stream string expansion instructions, outputting to the current 1343 * varaible buffer. 1344 * 1345 * @returns The new variable buffer position. 1346 * @param pInstrCore The instruction to start executing at. 1347 * @param pchDst The current variable buffer position. 1348 */ 1349 static char *kmk_exec_expand_instruction_stream_to_var_buf(PKMKCCEXPCORE pInstrCore, char *pchDst) 1350 { 1351 for (;;) 1352 { 1353 switch (pInstrCore->enmOpCode) 1354 { 1355 case kKmkCcExpInstr_CopyString: 1356 { 1357 PKMKCCEXPCOPYSTRING pInstr = (PKMKCCEXPCOPYSTRING)pInstrCore; 1358 pchDst = variable_buffer_output(pchDst, pInstr->pachSrc, pInstr->cchCopy); 1359 1360 pInstrCore = &(pInstr + 1)->Core; 1361 break; 1362 } 1363 1364 case kKmkCcExpInstr_PlainVariable: 1365 { 1366 PKMKCCEXPPLAINVAR pInstr = (PKMKCCEXPPLAINVAR)pInstrCore; 1367 struct variable *pVar = lookup_variable_strcached(pInstr->pszName); 1368 if (pVar) 1369 pchDst = kmk_exec_expand_worker_reference_variable(pVar, pchDst); 1370 else 1371 warn_undefined(pInstr->pszName, strcache2_get_len(&variable_strcache, pInstr->pszName)); 1372 1373 pInstrCore = &(pInstr + 1)->Core; 1374 break; 1375 } 1376 1377 case kKmkCcExpInstr_DynamicVariable: 1378 { 1379 PKMKCCEXPDYNVAR pInstr = (PKMKCCEXPDYNVAR)pInstrCore; 1380 struct variable *pVar; 1381 uint32_t cchName; 1382 char *pszName = kmk_exec_expand_subprog_to_tmp(&pInstr->SubProg, &cchName); 1383 char *pszColon = (char *)memchr(pszName, ':', cchName); 1384 char *pszEqual; 1385 if ( pszColon == NULL 1386 || (pszEqual = (char *)memchr(pszColon + 1, '=', &pszName[cchName] - pszColon - 1)) == NULL 1387 || pszEqual == pszColon + 1) 1388 { 1389 pVar = lookup_variable(pszName, cchName); 1390 if (pVar) 1391 pchDst = kmk_exec_expand_worker_reference_variable(pVar, pchDst); 1392 else 1393 warn_undefined(pszName, cchName); 1394 } 1395 else if (pszColon != pszName) 1396 { 1397 /* 1398 * Oh, we have to do search and replace. How tedious. 1399 * Since the variable name is a temporary buffer, we can transform 1400 * the strings into proper search and replacement patterns directly. 1401 */ 1402 pVar = lookup_variable(pszName, pszColon - pszName); 1403 if (pVar) 1404 { 1405 char const *pszExpandedVarValue = pVar->recursive ? recursively_expand(pVar) : pVar->value; 1406 char *pszSearchPat = pszColon + 1; 1407 char *pszReplacePat = pszEqual + 1; 1408 const char *pchPctSearchPat; 1409 const char *pchPctReplacePat; 1410 1411 *pszEqual = '\0'; 1412 pchPctSearchPat = find_percent(pszSearchPat); 1413 pchPctReplacePat = find_percent(pszReplacePat); 1414 1415 if (!pchPctReplacePat) 1416 { 1417 if (pszReplacePat[-2] != '\0') /* On the offchance that a pct was unquoted by find_percent. */ 1418 { 1419 memmove(pszName + 1, pszSearchPat, pszReplacePat - pszSearchPat); 1420 if (pchPctSearchPat) 1421 pchPctSearchPat -= pszSearchPat - &pszName[1]; 1422 pszSearchPat = &pszName[1]; 1423 } 1424 pchPctReplacePat = --pszReplacePat; 1425 *pszReplacePat = '%'; 1426 } 1427 1428 if (!pchPctSearchPat) 1429 { 1430 pchPctSearchPat = --pszSearchPat; 1431 *pszSearchPat = '%'; 1432 } 1433 1434 pchDst = patsubst_expand_pat(pchDst, pszExpandedVarValue, 1435 pszSearchPat, pszReplacePat, 1436 pchPctSearchPat, pchPctReplacePat); 1437 1438 if (pVar->recursive) 1439 free((void *)pszExpandedVarValue); 1440 } 1441 else 1442 warn_undefined(pszName, pszColon - pszName); 1443 } 1444 free(pszName); 1445 1446 pInstrCore = pInstr->pNext; 1447 break; 1448 } 1449 1450 1451 case kKmkCcExpInstr_SearchAndReplacePlainVariable: 1452 { 1453 PKMKCCEXPSRPLAINVAR pInstr = (PKMKCCEXPSRPLAINVAR)pInstrCore; 1454 struct variable *pVar = lookup_variable_strcached(pInstr->pszName); 1455 if (pVar) 1456 { 1457 char const *pszExpandedVarValue = pVar->recursive ? recursively_expand(pVar) : pVar->value; 1458 pchDst = patsubst_expand_pat(pchDst, 1459 pszExpandedVarValue, 1460 pInstr->pszSearchPattern, 1461 pInstr->pszReplacePattern, 1462 &pInstr->pszSearchPattern[pInstr->offPctSearchPattern], 1463 &pInstr->pszReplacePattern[pInstr->offPctReplacePattern]); 1464 if (pVar->recursive) 1465 free((void *)pszExpandedVarValue); 1466 } 1467 else 1468 warn_undefined(pInstr->pszName, strcache2_get_len(&variable_strcache, pInstr->pszName)); 1469 1470 pInstrCore = pInstr->pNext; 1471 break; 1472 } 1473 1474 case kKmkCcExpInstr_PlainFunction: 1475 { 1476 PKMKCCEXPPLAINFUNC pInstr = (PKMKCCEXPPLAINFUNC)pInstrCore; 1477 #ifndef NDEBUG 1478 uint32_t uCrcBefore = 0; 1479 uint32_t uCrcAfter = 0; 1480 uint32_t iArg = pInstr->Core.cArgs; 1481 while (iArg-- > 0) 1482 uCrcBefore = kmk_exec_debug_string_hash(uCrcBefore, pInstr->apszArgs[iArg]); 1483 #endif 1484 1485 pchDst = pInstr->Core.pfnFunction(pchDst, (char **)&pInstr->apszArgs[0], pInstr->Core.pszFuncName); 1486 1487 #ifndef NDEBUG 1488 iArg = pInstr->Core.cArgs; 1489 while (iArg-- > 0) 1490 uCrcAfter = kmk_exec_debug_string_hash(uCrcAfter, pInstr->apszArgs[iArg]); 1491 assert(uCrcBefore == uCrcAfter); 1492 #endif 1493 1494 pInstrCore = pInstr->Core.pNext; 1495 break; 1496 } 1497 1498 case kKmkCcExpInstr_DynamicFunction: 1499 { 1500 PKMKCCEXPDYNFUNC pInstr = (PKMKCCEXPDYNFUNC)pInstrCore; 1501 char **papszArgsShadow = xmalloc( (pInstr->Core.cArgs * 2 + 1) * sizeof(char *)); 1502 char **papszArgs = &papszArgsShadow[pInstr->Core.cArgs]; 1503 uint32_t iArg; 1504 #ifndef NDEBUG 1505 uint32_t uCrcBefore = 0; 1506 uint32_t uCrcAfter = 0; 1507 #endif 1508 iArg = pInstr->Core.cArgs; 1509 papszArgs[iArg] = NULL; 1510 while (iArg-- > 0) 1511 { 1512 char *pszArg; 1513 if (pInstr->aArgs[iArg].fPlain) 1514 pszArg = (char *)pInstr->aArgs[iArg].u.Plain.pszArg; 1515 else 1516 pszArg = kmk_exec_expand_subprog_to_tmp(&pInstr->aArgs[iArg].u.SubProg, NULL); 1517 papszArgsShadow[iArg] = pszArg; 1518 papszArgs[iArg] = pszArg; 1519 #ifndef NDEBUG 1520 uCrcBefore = kmk_exec_debug_string_hash(uCrcBefore, pszArg); 1521 #endif 1522 } 1523 1524 pchDst = pInstr->Core.pfnFunction(pchDst, papszArgs, pInstr->Core.pszFuncName); 1525 1526 iArg = pInstr->Core.cArgs; 1527 while (iArg-- > 0) 1528 { 1529 #ifndef NDEBUG 1530 assert(papszArgsShadow[iArg] == papszArgs[iArg]); 1531 uCrcAfter = kmk_exec_debug_string_hash(uCrcAfter, papszArgsShadow[iArg]); 1532 #endif 1533 if (!pInstr->aArgs[iArg].fPlain) 1534 free(papszArgsShadow); 1535 } 1536 assert(uCrcBefore == uCrcAfter); 1537 free(papszArgsShadow); 1538 1539 pInstrCore = pInstr->Core.pNext; 1540 break; 1541 } 1542 1543 case kKmkCcExpInstr_Jump: 1544 { 1545 PKMKCCEXPJUMP pInstr = (PKMKCCEXPJUMP)pInstrCore; 1546 pInstrCore = pInstr->pNext; 1547 break; 1548 } 1549 1550 case kKmkCcExpInstr_Return: 1551 return pchDst; 1552 1553 default: 1554 fatal(NULL, _("Unknown string expansion opcode: %d (%#x)"), 1555 (int)pInstrCore->enmOpCode, (int)pInstrCore->enmOpCode); 1556 return NULL; 1557 } 1558 } 1559 } 1560 1561 1562 /** 1563 * Updates the string expansion statistics. 1564 * 1565 * @param pStats The statistics structure to update. 1566 * @param cchResult The result lenght. 1567 */ 1568 void kmk_cc_exp_stats_update(PKMKCCEXPSTATS pStats, uint32_t cchResult) 1569 { 1570 /* 1571 * Keep statistics on output size. The average is simplified and not an 1572 * exact average for every expansion that has taken place. 1573 */ 1574 if (cchResult > pStats->cchMax) 1575 { 1576 if (pStats->cchMax) 1577 pStats->cchAvg = cchResult; 1578 pStats->cchMax = cchResult; 1579 } 1580 pStats->cchAvg = (pStats->cchAvg * 7 + cchResult) / 8; 1581 } 1582 1583 1584 /** 1585 * Execute a string expansion sub-program, outputting to a new heap buffer. 1586 * 1587 * @returns Pointer to the output buffer (hand to free when done). 1588 * @param pSubProg The sub-program to execute. 1589 * @param pcchResult Where to return the size of the result. Optional. 1590 */ 1591 static char *kmk_exec_expand_subprog_to_tmp(PKMKCCEXPSUBPROG pSubProg, uint32_t *pcchResult) 1592 { 1593 char *pchOldVarBuf; 1594 unsigned int cbOldVarBuf; 1595 char *pchDst; 1596 char *pszResult; 1597 uint32_t cchResult; 1598 1599 /* 1600 * Temporarily replace the variable buffer while executing the instruction 1601 * stream for this sub program. 1602 */ 1603 pchDst = install_variable_buffer_with_hint(&pchOldVarBuf, &cbOldVarBuf, 1604 pSubProg->Stats.cchAvg ? pSubProg->Stats.cchAvg + 32 : 256); 1605 1606 pchDst = kmk_exec_expand_instruction_stream_to_var_buf(pSubProg->pFirstInstr, pchDst); 1607 1608 /* Ensure that it's terminated. */ 1609 pchDst = variable_buffer_output(pchDst, "\0", 1) - 1; 1610 1611 /* Grab the result buffer before restoring the previous one. */ 1612 pszResult = variable_buffer; 1613 cchResult = (uint32_t)(pchDst - pszResult); 1614 if (pcchResult) 1615 *pcchResult = cchResult; 1616 kmk_cc_exp_stats_update(&pSubProg->Stats, cchResult); 1617 1618 restore_variable_buffer(pchOldVarBuf, cbOldVarBuf); 1619 1620 return pszResult; 1621 } 1622 1623 1624 /** 1625 * Execute a string expansion program, outputting to the current variable 1626 * buffer. 1627 * 1628 * @returns New variable buffer position. 1629 * @param pProg The program to execute. 1630 * @param pchDst The current varaible buffer position. 1631 */ 1632 static char *kmk_exec_expand_prog_to_var_buf(PKMKCCEXPPROG pProg, char *pchDst) 1633 { 1634 uint32_t cchResult; 1635 uint32_t offStart = (uint32_t)(pchDst - variable_buffer); 1636 1637 if (pProg->Stats.cchAvg >= variable_buffer_length - offStart) 1638 pchDst = ensure_variable_buffer_space(pchDst, offStart + pProg->Stats.cchAvg + 32); 1639 1640 pchDst = kmk_exec_expand_instruction_stream_to_var_buf(pProg->pFirstInstr, pchDst); 1641 1642 cchResult = (uint32_t)(pchDst - variable_buffer); 1643 assert(cchResult >= offStart); 1644 cchResult -= offStart; 1645 kmk_cc_exp_stats_update(&pProg->Stats, cchResult); 1646 1647 return pchDst; 1648 } 1649 1650 1147 1651 /** 1148 1652 * Equivalent of eval_buffer, only it's using the evalprog of the variable. … … 1167 1671 { 1168 1672 assert(pVar->expandprog); 1169 assert(0); 1170 return pchDst; 1673 return kmk_exec_expand_prog_to_var_buf(pVar->expandprog, pchDst); 1171 1674 } 1172 1675 … … 1180 1683 { 1181 1684 assert(pVar->evalprog || pVar->expandprog); 1685 #if 0 1686 if (pVar->evalprog) 1687 { 1688 kmk_cc_block_free_list(pVar->evalprog->pBlockTail); 1689 pVar->evalprog = NULL; 1690 } 1691 #endif 1692 if (pVar->expandprog) 1693 { 1694 kmk_cc_block_free_list(pVar->expandprog->pBlockTail); 1695 pVar->expandprog = NULL; 1696 } 1182 1697 } 1183 1698 … … 1191 1706 { 1192 1707 assert(pVar->evalprog || pVar->expandprog); 1708 #if 0 1709 if (pVar->evalprog) 1710 { 1711 kmk_cc_block_free_list(pVar->evalprog->pBlockTail); 1712 pVar->evalprog = NULL; 1713 } 1714 #endif 1715 if (pVar->expandprog) 1716 { 1717 kmk_cc_block_free_list(pVar->expandprog->pBlockTail); 1718 pVar->expandprog = NULL; 1719 } 1193 1720 } 1194 1721
Note:
See TracChangeset
for help on using the changeset viewer.