Index: /trunk/src/kmk/expand.c
===================================================================
--- /trunk/src/kmk/expand.c	(revision 2769)
+++ /trunk/src/kmk/expand.c	(revision 2770)
@@ -256,5 +256,5 @@
       v->expand_count++;
       if (   v->expandprog
-          || (v->expand_count == 10 && kmk_cc_compile_variable_for_expand (v)) )
+          || (v->expand_count == 3 && kmk_cc_compile_variable_for_expand (v)) )
         o = kmk_exec_expand_to_var_buf (v, o);
       else
@@ -1081,4 +1081,5 @@
       v->value_length = p - v->value;
       v->value_alloc_len = variable_buffer_length;
+      VARIABLE_CHANGED(v);
 
       /* Restore the variable buffer, but without freeing the current. */
Index: /trunk/src/kmk/function.c
===================================================================
--- /trunk/src/kmk/function.c	(revision 2769)
+++ /trunk/src/kmk/function.c	(revision 2770)
@@ -1360,4 +1360,5 @@
       var->value[len] = '\0';
       var->value_length = len;
+      VARIABLE_CHANGED (var);
 
       variable_expand_string_2 (o, body, body_len, &o);
@@ -1754,5 +1755,6 @@
   while ((p = find_next_token (&t, &len)) != 0)
     {
-      ++t;
+      if (*t != '\0') /* bird: Fixes access beyond end of string and overflowing words array. */
+        ++t;
       p[len] = '\0';
       words[wordi++] = p;
@@ -2160,4 +2162,6 @@
               v->value_length = dst - v->value;
             }
+
+          VARIABLE_CHANGED (v);
 
 # ifdef CONFIG_WITH_COMPILER
@@ -4648,4 +4652,5 @@
               stack_var->value_length = lastitem - stack_var->value;
 #endif
+              VARIABLE_CHANGED (stack_var);
             }
         }
Index: /trunk/src/kmk/kbuild.c
===================================================================
--- /trunk/src/kmk/kbuild.c	(revision 2769)
+++ /trunk/src/kmk/kbuild.c	(revision 2770)
@@ -570,4 +570,5 @@
     }
     pVar->recursive = 0;
+    VARIABLE_CHANGED(pVar);
     return pVar;
 }
@@ -2621,4 +2622,6 @@
             pDefTemplate->value_length = off;
             pDefTemplate->value[off] = '\0';
+
+            VARIABLE_CHANGED(pDefTemplate);
         }
 
Index: /trunk/src/kmk/kmk_cc_exec.c
===================================================================
--- /trunk/src/kmk/kmk_cc_exec.c	(revision 2769)
+++ /trunk/src/kmk/kmk_cc_exec.c	(revision 2770)
@@ -70,6 +70,4 @@
 typedef struct KMKCCEXPSTATS
 {
-    /** Max expanded size. */
-    uint32_t                    cchMax;
     /** Recent average size. */
     uint32_t                    cchAvg;
@@ -198,4 +196,6 @@
     /** Number of arguments. */
     uint32_t                cArgs;
+    /** Set if the function could be modifying the input arguments. */
+    uint8_t                 fDirty;
     /** Where to continue after this instruction.  (This is necessary since the
      * instructions are of variable size and may be followed by string data.) */
@@ -209,5 +209,5 @@
      * @param   pszFuncName The name of the function being called.
      */
-    char *                 (*pfnFunction)(char *pchDst, char **papszArgs, const char *pszFuncName);
+    char *                (*pfnFunction)(char *pchDst, char **papszArgs, const char *pszFuncName);
     /** Pointer to the function name in the variable string cache. */
     const char             *pszFuncName;
@@ -295,4 +295,20 @@
 
 /*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+#ifndef NDEBUG
+# ifdef _MSC_VER
+#  define KMK_CC_ASSERT(a_TrueExpr)         do { if (!(a_TrueExpr)) __debugbreak(); } while (0)
+# else
+#  define KMK_CC_ASSERT(a_TrueExpr)         assert(a_TrueExpr)
+# endif
+#else
+# define KMK_CC_ASSERT(a_TrueExpr)          do {} while (0)
+#endif
+#define KMK_CC_ASSERT_ALIGNED(a_uValue, a_uAlignment) \
+    KMK_CC_ASSERT( ((a_uValue) & ((a_uAlignment) - 1)) == 0 )
+
+
+/*******************************************************************************
 *   Global Variables                                                           *
 *******************************************************************************/
@@ -327,5 +343,5 @@
     PKMKCCBLOCK     pNewBlock;
 
-    assert(((cbFirst + sizeof(void *) - 1) & (sizeof(void *) - 1)) == 0);
+    KMK_CC_ASSERT_ALIGNED(cbFirst, sizeof(void *));
 
     /*
@@ -377,5 +393,5 @@
     {
         pBlockTail->offNext = (pBlockTail->offNext + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
-        assert(pBlockTail->cbBlock - pBlockTail->offNext >= sizeof(KMKCCEXPJUMP));
+        KMK_CC_ASSERT(pBlockTail->cbBlock - pBlockTail->offNext >= sizeof(KMKCCEXPJUMP));
     }
 }
@@ -441,5 +457,5 @@
     uint32_t    cbLeft = pBlockTail->cbBlock - pBlockTail->offNext;
 
-    assert(cbLeft >= sizeof(KMKCCEXPJUMP));
+    KMK_CC_ASSERT(cbLeft >= sizeof(KMKCCEXPJUMP));
     if (cbLeft >= cb + sizeof(KMKCCEXPJUMP))
     {
@@ -508,5 +524,5 @@
     pJump->pNext = pRet;
     pOldBlock->offNext += sizeof(*pJump);
-    assert(pOldBlock->offNext <= pOldBlock->cbBlock);
+    KMK_CC_ASSERT(pOldBlock->offNext <= pOldBlock->cbBlock);
 
     return pRet;
@@ -526,6 +542,6 @@
     uint32_t    cbLeft = pBlockTail->cbBlock - pBlockTail->offNext;
 
-    assert(cbLeft >= sizeof(KMKCCEXPJUMP));
-    assert(((cb + sizeof(void *) - 1) & (sizeof(void *) - 1)) == 0 || cb == sizeof(KMKCCEXPCORE));
+    KMK_CC_ASSERT(cbLeft >= sizeof(KMKCCEXPJUMP));
+    KMK_CC_ASSERT( (cb & (sizeof(void *) - 1)) == 0 || cb == sizeof(KMKCCEXPCORE) /* final */ );
 
     if (cbLeft >= cb + sizeof(KMKCCEXPJUMP))
@@ -588,4 +604,36 @@
     pCore->enmOpCode = kKmkCcExpInstr_Return;
     return 0;
+}
+
+
+/**
+ * Checks if a function is known to mess up the arguments its given.
+ *
+ * When executing calls to "dirty" functions, all arguments must be duplicated
+ * on the heap.
+ *
+ * @returns 1 if dirty, 0 if clean.
+ * @param   pszFunction         The function name.
+ */
+static uint8_t kmk_cc_is_dirty_function(const char *pszFunction)
+{
+    switch (pszFunction[0])
+    {
+        default:
+            return 0;
+        case 'f':
+            if (pszFunction[1] == 'i')
+            {
+                if (!strcmp(pszFunction, "filter"))
+                    return 1;
+                if (!strcmp(pszFunction, "filter-out"))
+                    return 1;
+            }
+            return 0;
+        case 's':
+            if (!strcmp(pszFunction, "sort"))
+                return 1;
+            return 0;
+    }
 }
 
@@ -624,4 +672,5 @@
     pInstr->Core.pfnFunction    = pfnFunction;
     pInstr->Core.pszFuncName    = pszFunction;
+    pInstr->Core.fDirty         = kmk_cc_is_dirty_function(pszFunction);
 
     /*
@@ -645,5 +694,5 @@
             if (ch == chClose)
             {
-                assert(cDepth > 0);
+                KMK_CC_ASSERT(cDepth > 0);
                 if (cDepth > 0)
                     cDepth--;
@@ -651,5 +700,5 @@
             else if (ch == chOpen)
                 cDepth++;
-            else if (ch == ',' && cDepth == 0)
+            else if (ch == ',' && cDepth == 0 && iArg + 1 < cActualArgs)
                 break;
             else if (ch == '$')
@@ -658,5 +707,5 @@
         }
 
-        pInstr->aArgs[iArg].fPlain = fDollar;
+        pInstr->aArgs[iArg].fPlain = !fDollar;
         if (fDollar)
         {
@@ -679,5 +728,5 @@
         cchArgs -= cchThisArg + 1;
     }
-    assert(iArg == cActualArgs);
+    KMK_CC_ASSERT(iArg == cActualArgs);
 
     /*
@@ -723,4 +772,5 @@
     pInstr->Core.pfnFunction    = pfnFunction;
     pInstr->Core.pszFuncName    = pszFunction;
+    pInstr->Core.fDirty         = kmk_cc_is_dirty_function(pszFunction);
 
     /*
@@ -742,5 +792,5 @@
             if (ch == chClose)
             {
-                assert(cDepth > 0);
+                KMK_CC_ASSERT(cDepth > 0);
                 if (cDepth > 0)
                     cDepth--;
@@ -748,5 +798,5 @@
             else if (ch == chOpen)
                 cDepth++;
-            else if (ch == ',' && cDepth == 0)
+            else if (ch == ',' && cDepth == 0 && iArg + 1 < cActualArgs)
                 break;
             cchThisArg++;
@@ -761,5 +811,5 @@
     }
 
-    assert(iArg == cActualArgs);
+    KMK_CC_ASSERT(iArg == cActualArgs);
     pInstr->apszArgs[iArg] = NULL;
 
@@ -787,5 +837,5 @@
     PKMKCCEXPDYNVAR pInstr;
     int rc;
-    assert(cchNameExpr > 0);
+    KMK_CC_ASSERT(cchNameExpr > 0);
 
     pInstr = (PKMKCCEXPDYNVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
@@ -1002,5 +1052,7 @@
 
                         /* First loop: Identify potential function calls and dynamic expansion. */
-                        assert(!func_char_map[chOpen]); assert(!func_char_map[chClose]); assert(!func_char_map['$']);
+                        KMK_CC_ASSERT(!func_char_map[chOpen]);
+                        KMK_CC_ASSERT(!func_char_map[chClose]);
+                        KMK_CC_ASSERT(!func_char_map['$']);
                         while (cchName < cchStr)
                         {
@@ -1198,5 +1250,4 @@
 {
     pStats->cchAvg = 0;
-    pStats->cchMax = 0;
 }
 
@@ -1219,5 +1270,5 @@
 static int kmk_cc_exp_compile_subprog(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr, PKMKCCEXPSUBPROG pSubProg)
 {
-    assert(cchStr);
+    KMK_CC_ASSERT(cchStr > 0);
     pSubProg->pFirstInstr = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
     kmk_cc_exp_stats_init(&pSubProg->Stats);
@@ -1286,13 +1337,11 @@
 struct kmk_cc_expandprog *kmk_cc_compile_variable_for_expand(struct variable *pVar)
 {
-    assert(!pVar->expandprog);
+    KMK_CC_ASSERT(!pVar->expandprog);
     if (   !pVar->expandprog
         && pVar->value_length > 0
         && pVar->recursive)
     {
-        assert(strlen(pVar->value) == pVar->value_length);
-#if 0 /** @todo test & debug this code. Write interpreters! */
+        KMK_CC_ASSERT(strlen(pVar->value) == pVar->value_length);
         pVar->expandprog = kmk_cc_exp_compile(pVar->value, pVar->value_length);
-#endif
     }
     return pVar->expandprog;
@@ -1475,20 +1524,41 @@
             {
                 PKMKCCEXPPLAINFUNC pInstr = (PKMKCCEXPPLAINFUNC)pInstrCore;
+                uint32_t iArg;
+                if (!pInstr->Core.fDirty)
+                {
 #ifndef NDEBUG
-                uint32_t uCrcBefore = 0;
-                uint32_t uCrcAfter = 0;
-                uint32_t iArg = pInstr->Core.cArgs;
-                while (iArg-- > 0)
-                    uCrcBefore = kmk_exec_debug_string_hash(uCrcBefore, pInstr->apszArgs[iArg]);
+                    uint32_t uCrcBefore = 0;
+                    uint32_t uCrcAfter = 0;
+                    iArg = pInstr->Core.cArgs;
+                    while (iArg-- > 0)
+                        uCrcBefore = kmk_exec_debug_string_hash(uCrcBefore, pInstr->apszArgs[iArg]);
 #endif
 
-                pchDst = pInstr->Core.pfnFunction(pchDst, (char **)&pInstr->apszArgs[0], pInstr->Core.pszFuncName);
+                    pchDst = pInstr->Core.pfnFunction(pchDst, (char **)&pInstr->apszArgs[0], pInstr->Core.pszFuncName);
 
 #ifndef NDEBUG
-                iArg = pInstr->Core.cArgs;
-                while (iArg-- > 0)
-                    uCrcAfter = kmk_exec_debug_string_hash(uCrcAfter, pInstr->apszArgs[iArg]);
-                assert(uCrcBefore == uCrcAfter);
+                    iArg = pInstr->Core.cArgs;
+                    while (iArg-- > 0)
+                        uCrcAfter = kmk_exec_debug_string_hash(uCrcAfter, pInstr->apszArgs[iArg]);
+                    KMK_CC_ASSERT(uCrcBefore == uCrcAfter);
 #endif
+                }
+                else
+                {
+                    char **papszShadowArgs = xmalloc((pInstr->Core.cArgs * 2 + 1) * sizeof(papszShadowArgs[0]));
+                    char **papszArgs = &papszShadowArgs[pInstr->Core.cArgs];
+
+                    iArg = pInstr->Core.cArgs;
+                    papszArgs[iArg] = NULL;
+                    while (iArg-- > 0)
+                        papszArgs[iArg] = papszShadowArgs[iArg] = xstrdup(pInstr->apszArgs[iArg]);
+
+                    pchDst = pInstr->Core.pfnFunction(pchDst, (char **)&pInstr->apszArgs[0], pInstr->Core.pszFuncName);
+
+                    iArg = pInstr->Core.cArgs;
+                    while (iArg-- > 0)
+                        free(papszShadowArgs[iArg]);
+                    free(papszShadowArgs);
+                }
 
                 pInstrCore = pInstr->Core.pNext;
@@ -1502,37 +1572,61 @@
                 char           **papszArgs = &papszArgsShadow[pInstr->Core.cArgs];
                 uint32_t         iArg;
-#ifndef NDEBUG
-                uint32_t         uCrcBefore = 0;
-                uint32_t         uCrcAfter = 0;
-#endif
-                iArg = pInstr->Core.cArgs;
-                papszArgs[iArg] = NULL;
-                while (iArg-- > 0)
-                {
-                    char *pszArg;
-                    if (pInstr->aArgs[iArg].fPlain)
-                        pszArg = (char *)pInstr->aArgs[iArg].u.Plain.pszArg;
-                    else
-                        pszArg = kmk_exec_expand_subprog_to_tmp(&pInstr->aArgs[iArg].u.SubProg, NULL);
-                    papszArgsShadow[iArg] = pszArg;
-                    papszArgs[iArg]       = pszArg;
-#ifndef NDEBUG
-                    uCrcBefore = kmk_exec_debug_string_hash(uCrcBefore, pszArg);
-#endif
-                }
-
-                pchDst = pInstr->Core.pfnFunction(pchDst, papszArgs, pInstr->Core.pszFuncName);
-
-                iArg = pInstr->Core.cArgs;
-                while (iArg-- > 0)
+
+                if (!pInstr->Core.fDirty)
                 {
 #ifndef NDEBUG
-                    assert(papszArgsShadow[iArg] == papszArgs[iArg]);
-                    uCrcAfter = kmk_exec_debug_string_hash(uCrcAfter, papszArgsShadow[iArg]);
+                    uint32_t    uCrcBefore = 0;
+                    uint32_t    uCrcAfter = 0;
 #endif
-                    if (!pInstr->aArgs[iArg].fPlain)
-                        free(papszArgsShadow);
+                    iArg = pInstr->Core.cArgs;
+                    papszArgs[iArg] = NULL;
+                    while (iArg-- > 0)
+                    {
+                        char *pszArg;
+                        if (!pInstr->aArgs[iArg].fPlain)
+                            pszArg = kmk_exec_expand_subprog_to_tmp(&pInstr->aArgs[iArg].u.SubProg, NULL);
+                        else
+                            pszArg = (char *)pInstr->aArgs[iArg].u.Plain.pszArg;
+                        papszArgsShadow[iArg] = pszArg;
+                        papszArgs[iArg]       = pszArg;
+#ifndef NDEBUG
+                        uCrcBefore = kmk_exec_debug_string_hash(uCrcBefore, pszArg);
+#endif
+                    }
+                    pchDst = pInstr->Core.pfnFunction(pchDst, papszArgs, pInstr->Core.pszFuncName);
+
+                    iArg = pInstr->Core.cArgs;
+                    while (iArg-- > 0)
+                    {
+#ifndef NDEBUG
+                        KMK_CC_ASSERT(papszArgsShadow[iArg] == papszArgs[iArg]);
+                        uCrcAfter = kmk_exec_debug_string_hash(uCrcAfter, papszArgsShadow[iArg]);
+#endif
+                        if (!pInstr->aArgs[iArg].fPlain)
+                            free(papszArgsShadow[iArg]);
+                    }
+                    KMK_CC_ASSERT(uCrcBefore == uCrcAfter);
                 }
-                assert(uCrcBefore == uCrcAfter);
+                else
+                {
+                    iArg = pInstr->Core.cArgs;
+                    papszArgs[iArg] = NULL;
+                    while (iArg-- > 0)
+                    {
+                        char *pszArg;
+                        if (!pInstr->aArgs[iArg].fPlain)
+                            pszArg = kmk_exec_expand_subprog_to_tmp(&pInstr->aArgs[iArg].u.SubProg, NULL);
+                        else
+                            pszArg = xstrdup(pInstr->aArgs[iArg].u.Plain.pszArg);
+                        papszArgsShadow[iArg] = pszArg;
+                        papszArgs[iArg]       = pszArg;
+                    }
+
+                    pchDst = pInstr->Core.pfnFunction(pchDst, papszArgs, pInstr->Core.pszFuncName);
+
+                    iArg = pInstr->Core.cArgs;
+                    while (iArg-- > 0)
+                        free(papszArgsShadow[iArg]);
+                }
                 free(papszArgsShadow);
 
@@ -1569,13 +1663,7 @@
 {
     /*
-     * Keep statistics on output size.  The average is simplified and not an
-     * exact average for every expansion that has taken place.
+     * The average is simplified and not an exact average for every
+     * expansion that has taken place.
      */
-    if (cchResult > pStats->cchMax)
-    {
-        if (pStats->cchMax)
-            pStats->cchAvg = cchResult;
-        pStats->cchMax = cchResult;
-    }
     pStats->cchAvg = (pStats->cchAvg * 7 + cchResult) / 8;
 }
@@ -1616,5 +1704,6 @@
     kmk_cc_exp_stats_update(&pSubProg->Stats, cchResult);
 
-    restore_variable_buffer(pchOldVarBuf, cbOldVarBuf);
+    variable_buffer = pchOldVarBuf;
+    variable_buffer_length = cbOldVarBuf;
 
     return pszResult;
@@ -1641,5 +1730,5 @@
 
     cchResult = (uint32_t)(pchDst - variable_buffer);
-    assert(cchResult >= offStart);
+    KMK_CC_ASSERT(cchResult >= offStart);
     cchResult -= offStart;
     kmk_cc_exp_stats_update(&pProg->Stats, cchResult);
@@ -1656,5 +1745,5 @@
 void kmk_exec_evalval(struct variable *pVar)
 {
-    assert(pVar->evalprog);
+    KMK_CC_ASSERT(pVar->evalprog);
     assert(0);
 }
@@ -1670,5 +1759,5 @@
 char *kmk_exec_expand_to_var_buf(struct variable *pVar, char *pchDst)
 {
-    assert(pVar->expandprog);
+    KMK_CC_ASSERT(pVar->expandprog);
     return kmk_exec_expand_prog_to_var_buf(pVar->expandprog, pchDst);
 }
@@ -1682,5 +1771,5 @@
 void  kmk_cc_variable_changed(struct variable *pVar)
 {
-    assert(pVar->evalprog || pVar->expandprog);
+    KMK_CC_ASSERT(pVar->evalprog || pVar->expandprog);
 #if 0
     if (pVar->evalprog)
@@ -1705,5 +1794,5 @@
 void  kmk_cc_variable_deleted(struct variable *pVar)
 {
-    assert(pVar->evalprog || pVar->expandprog);
+    KMK_CC_ASSERT(pVar->evalprog || pVar->expandprog);
 #if 0
     if (pVar->evalprog)
Index: /trunk/src/kmk/read.c
===================================================================
--- /trunk/src/kmk/read.c	(revision 2769)
+++ /trunk/src/kmk/read.c	(revision 2770)
@@ -2296,8 +2296,17 @@
 
           v->origin = origin;
+#ifndef CONFIG_WITH_VALUE_LENGTH
           if (v->flavor == f_simple)
             v->value = allocated_variable_expand (v->value);
           else
             v->value = xstrdup (v->value);
+#else
+          v->value_length = strlen (v->value);
+          if (v->flavor == f_simple)
+            v->value = allocated_variable_expand_2 (v->value, v->value_length, &v->value_length);
+          else
+            v->value = (char *)memcpy (xmalloc (v->value_length + 1), v->value, v->value_length + 1);
+          v->value_alloc_len = v->value_length + 1;
+#endif
 
           fname = p->target;
@@ -2370,4 +2379,5 @@
               v->recursive = gv->recursive;
               v->append = 0;
+              VARIABLE_CHANGED (v);
             }
         }
Index: /trunk/src/kmk/variable.c
===================================================================
--- /trunk/src/kmk/variable.c	(revision 2769)
+++ /trunk/src/kmk/variable.c	(revision 2770)
@@ -386,9 +386,5 @@
 	  v->origin = origin;
 	  v->recursive = recursive;
-         MAKE_STATS_2(v->changes++);
-#ifdef CONFIG_WITH_COMPILER
-         if (v->evalprog || v->expandprog)
-           kmk_cc_variable_changed (v);
-#endif
+         VARIABLE_CHANGED (v);
 	}
       return v;
@@ -603,9 +599,5 @@
       if (v->value != 0 && !v->rdonly_val)
           free (v->value);
-      MAKE_STATS_2(v->changes++);
-#ifdef CONFIG_WITH_COMPILER
-      if (v->evalprog || v->expandprog)
-        kmk_cc_variable_changed (v);
-#endif
+      VARIABLE_CHANGED (v);
     }
   else
@@ -764,4 +756,5 @@
       var->value_alloc_len = max;
 #endif
+      VARIABLE_CHANGED (var);
 
       /* Remember how many variables are in our current count.  Since we never
@@ -2225,4 +2218,5 @@
     memcpy (v->value, value, value_len + 1);
   v->value_length = new_value_len;
+  VARIABLE_CHANGED (v);
 }
 
@@ -2439,9 +2433,4 @@
             if (free_value)
                free (free_value);
-            MAKE_STATS_2(v->changes++);
-# ifdef CONFIG_WITH_COMPILER
-            if (v->evalprog || v->expandprog)
-              kmk_cc_variable_changed (v);
-# endif
             return v;
 #else /* !CONFIG_WITH_VALUE_LENGTH */
Index: /trunk/src/kmk/variable.h
===================================================================
--- /trunk/src/kmk/variable.h	(revision 2769)
+++ /trunk/src/kmk/variable.h	(revision 2770)
@@ -116,6 +116,6 @@
 #endif
 #if defined (CONFIG_WITH_COMPILER) || defined (CONFIG_WITH_MAKE_STATS)
-    unsigned int evalval_count; /* Times used with $(evalval ) or $(evalctx ). */
-    unsigned int expand_count;  /* Times expanded (not to be confused with exp_count). */
+    unsigned int evalval_count; /* Times used with $(evalval ) or $(evalctx ) since last change. */
+    unsigned int expand_count;  /* Times expanded since last change (not to be confused with exp_count). */
 #endif
 #ifdef CONFIG_WITH_COMPILER
@@ -124,4 +124,19 @@
 #endif
   };
+
+/* Update statistics and invalidates optimizations when a variable changes. */
+#ifdef CONFIG_WITH_COMPILER
+# define VARIABLE_CHANGED(v) \
+  do { \
+      MAKE_STATS_2((v)->changes++); \
+      if ((v)->evalprog || (v)->expandprog) kmk_cc_variable_changed(v); \
+      (v)->expand_count = 0; \
+      (v)->evalval_count = 0; \
+    } while (0)
+#else
+# define VARIABLE_CHANGED(v) MAKE_STATS_2((v)->changes++)
+#endif
+
+
 
 /* Structure that represents a variable set.  */
