Remove remaining embedded JavaScript support.
[bbaumbach/samba-autobuild/.git] / source4 / lib / appweb / ejs-2.0 / ejs / ejsGarbage.c
diff --git a/source4/lib/appweb/ejs-2.0/ejs/ejsGarbage.c b/source4/lib/appweb/ejs-2.0/ejs/ejsGarbage.c
deleted file mode 100755 (executable)
index 264da05..0000000
+++ /dev/null
@@ -1,1214 +0,0 @@
-/*
- *     @file   ejsGarbage.c
- *     @brief  EJS Garbage collector.
- *     @overview This implements a generational mark and sweep collection scheme.
- */
-/********************************* Copyright **********************************/
-/*
- *     @copy   default
- *     
- *     Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
- *     
- *     This software is distributed under commercial and open source licenses.
- *     You may use the GPL open source license described below or you may acquire 
- *     a commercial license from Mbedthis Software. You agree to be fully bound 
- *     by the terms of either license. Consult the LICENSE.TXT distributed with 
- *     this software for full details.
- *     
- *     This software is open source; you can redistribute it and/or modify it 
- *     under the terms of the GNU General Public License as published by the 
- *     Free Software Foundation; either version 2 of the License, or (at your 
- *     option) any later version. See the GNU General Public License for more 
- *     details at: http://www.mbedthis.com/downloads/gplLicense.html
- *     
- *     This program is distributed WITHOUT ANY WARRANTY; without even the 
- *     implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
- *     
- *     This GPL license does NOT permit incorporating this software into 
- *     proprietary programs. If you are unable to comply with the GPL, you must
- *     acquire a commercial license to use this software. Commercial licenses 
- *     for this software and support services are available from Mbedthis 
- *     Software at http://www.mbedthis.com 
- *     
- *     @end
- */
-/********************************** Includes **********************************/
-
-#include       "ejs.h"
-
-#if BLD_FEATURE_EJS
-
-/****************************** Forward Declarations **************************/
-
-static void    mark(Ejs *ep);
-static void            markObjByVar(Ejs *ep, EjsVar *op);
-static void    markObj(EjsObj *obj);
-static void    markPerm(Ejs *ep, uint gen);
-static int             sweep(Ejs *ep, uint gen);
-static EjsGCLink *ejsAlloc(EJS_LOC_DEC(ep, loc), int slabIndex);
-static void    ejsGracefulDegrade(Ejs *ep);
-static void    resetMarks(Ejs *ep, EjsSlab *slab);
-
-#if FUTURE
-static void    ageGenerations(Ejs *ep);
-#endif
-
-#if BLD_DEBUG && (!BREW || BREW_SIMULATOR)
-uint breakAddr;
-#endif
-
-/************************************* Code ***********************************/
-
-void ejsGCInit(Ejs *ep, int objInc, int propInc, int varInc, int strInc)
-{
-       EjsSlab         *slab;
-
-       if (ep->service && ep->service->globalClass) {
-               ep->service->globalClass->objectState->gcMarked = 1;
-       }
-
-       slab = &ep->slabs[EJS_SLAB_OBJ];
-       slab->allocIncrement = objInc;
-       slab->size = EJS_ALLOC_ALIGN(sizeof(EjsObj));
-
-       slab = &ep->slabs[EJS_SLAB_PROPERTY];
-       slab->allocIncrement = propInc;
-       slab->size = EJS_ALLOC_ALIGN(sizeof(EjsProperty));
-
-       slab = &ep->slabs[EJS_SLAB_VAR];
-       slab->allocIncrement = varInc;
-       slab->size = EJS_ALLOC_ALIGN(sizeof(EjsVar));
-
-       /*
-        *      Initialize GC.
-        *      Enable GC both idle and demand collections.
-        *      Set no limits and garbage collect if the slabs are
-        *      empty and we have used more than the THRESHOLD of ram.
-        */
-       ep->gc.debugLevel = 0;
-       ep->gc.enable = 1;
-       ep->gc.enableIdleCollect = 1;
-       ep->gc.enableDemandCollect = 1;
-       ep->gc.workQuota = EJS_GC_WORK_QUOTA;
-       ep->gc.maxMemory = 0;
-}
-
-
-/******************************************************************************/
-#if BLD_FEATURE_ALLOC_STATS
-
-void ejsPrintAllocReport(Ejs *ep, bool printLeakReport)
-{
-       EjsSlab         *slab;
-       char            *name;
-       int                     slabIndex, isObj;
-       
-       for (slabIndex = 0; slabIndex < EJS_SLAB_MAX; slabIndex++) {
-               slab = &ep->slabs[slabIndex];
-               if (slabIndex == EJS_SLAB_VAR) {
-                       name = "var";
-               } else if (slabIndex == EJS_SLAB_PROPERTY) {
-                       name = "prop";
-               } else {
-                       name = "obj";
-               }
-               mprLog(ep, 0, " ");
-               mprLog(ep, 0, "  GC \"%s\" local slab", name);
-               mprLog(ep, 0, "  Total blocks           %14d", 
-                       slab->allocCount + slab->freeCount);
-               mprLog(ep, 0, "  Block size             %14d", slab->size);
-               mprLog(ep, 0, "  Slab RAM allocated     %14d", 
-                       (slab->allocCount + slab->freeCount) * slab->size);
-               mprLog(ep, 0, "  Slab RAM in use        %14d", 
-                       slab->allocCount * slab->size);
-               mprLog(ep, 0, "  Blocks in use          %14d", slab->allocCount);
-               mprLog(ep, 0, "  Free blocks            %14d", slab->freeCount);
-               mprLog(ep, 0, "  Peak allocated         %14d", slab->peakAllocated);
-               mprLog(ep, 0, "  Peak free              %14d", slab->peakFree);
-               mprLog(ep, 0, "  Total allocations      %14d", slab->totalAlloc);
-               mprLog(ep, 0, "  Total blocks reclaimed %14d", slab->totalReclaimed);
-               mprLog(ep, 0, "  Total sweeps           %14d", slab->totalSweeps);
-               mprLog(ep, 0, "  Allocation inc         %14d", slab->allocIncrement);
-       }
-
-       mprLog(ep, 0, " ");
-       mprLog(ep, 0, "  Total EJS memory in use    %10d", ejsGetUsedMemory(ep));
-       mprLog(ep, 0, "  Total EJS memory allocated %10d", 
-               ejsGetAllocatedMemory(ep));
-
-       if (printLeakReport) {
-               mprLog(ep, 0, " ");
-               for (slabIndex = 0; slabIndex < EJS_SLAB_MAX; slabIndex++) {
-                       int             size;
-
-                       slab = &ep->slabs[slabIndex];
-
-                       isObj = 0;
-                       mprLog(ep, 0, " ");
-                       if (slabIndex == EJS_SLAB_VAR) {
-                               name = "var";
-                               size = sizeof(EjsVar);
-                       } else if (slabIndex == EJS_SLAB_PROPERTY) {
-                               name = "prop";
-                               size = sizeof(EjsProperty);
-                       } else {
-                               name = "obj";
-                               size = sizeof(EjsObj);
-                               isObj++;
-                       }
-#if BLD_FEATURE_ALLOC_LEAK_TRACK
-{
-                       EjsGCLink       *lp;
-                       EjsObj          *obj;
-                       int                     count;
-
-                       mprLog(ep, 0, "EJS Leak Report for \"%s\"", name);
-                       count = 0;
-
-                       for (lp = slab->allocList[0].next; lp; lp = lp->next) {
-                               mprLog(ep, 0, "  %-20s           %10d", lp->allocatedBy, size);
-                               if (isObj) {
-                                       obj = (EjsObj*) lp;
-                                       mprLog(ep, 0, "  %-20s           %10d %s %s", 
-                                               lp->allocatedBy, size,
-                                               obj->permanent ? "permanent" : "", 
-                                               obj->alive ? "alive" : ""
-                                       );
-                               } else {
-                                       mprLog(ep, 0, "  %-20s           %10d", lp->allocatedBy, 
-                                               size);
-                               }
-                               count++;
-                       }
-                       mprLog(ep, 0, "  Total blocks               %14d", count);
-}
-#endif
-               }
-               mprLog(ep, 0, " ");
-       }
-}
-
-#endif
-/******************************************************************************/
-/*
- *     Slab allocator
- */
-
-static EjsGCLink *ejsAlloc(EJS_LOC_DEC(ep, loc), int slabIndex)
-{
-       EjsSlab         *slab;
-       EjsGCLink       *block;
-       EjsGC           *gc;
-       uint            allocatedMemory;
-       int                     i;
-
-       mprStackCheck(ep);
-
-       if (slabIndex < 0 || slabIndex >= EJS_SLAB_MAX) {
-               mprAssert(0);
-               return 0;
-       }
-
-       /*
-        *      See if the slab has some free blocks
-        */
-       slab = &ep->slabs[slabIndex];
-       if ((block = slab->freeList.next) == 0) {
-
-               allocatedMemory = ejsGetAllocatedMemory(ep);
-               gc = &ep->gc;
-
-               /*
-                *      No blocks available. If demand collection is enabled, try
-                *      to garbage collect first. We collect if we have done a good 
-                *      work quota or we are over the max memory limit.
-                */
-               if (slabIndex != EJS_SLAB_VAR && 
-                               ep->gc.enable && ep->gc.enableDemandCollect) {
-                       if ((ep->gc.workDone > ep->gc.workQuota) || 
-                          (gc->maxMemory > 0 && allocatedMemory > gc->maxMemory)) {
-
-#if DEBUG_USE_ONLY
-                               if (ep->gc.debugLevel > 0) {
-                                       mprLog(ep, 0, "Need GC, EJS RAM %d, MPR RAM %d\n",
-                                               allocatedMemory, mprGetAllocatedMemory(ep));
-                                       if (ep->gc.debugLevel > 4) {
-                                               ejsPrintAllocReport(ep, 0);
-                                       }
-                               }
-#endif
-                               if (ejsCollectGarbage(ep, slabIndex) == 0) {
-                                       block = slab->freeList.next;
-                               }
-                       }
-               }
-
-               if (block == 0) {
-                       if (gc->maxMemory > 0 && allocatedMemory > gc->maxMemory) {
-                               /*
-                                *      We are above the max memory limit. We will fail this
-                                *      memory allocation, but allow subsequent allocations to 
-                                *      permit error recovery. We gracefully degrade by setting 
-                                *      slab chunk sizes to 1. This minimizes real memory
-                                *      consumption. This allows us to create 
-                                *      an exception block to be created by upper layers.
-                                */
-                               if (! gc->degraded) {
-                                       ejsGracefulDegrade(ep);
-                                       return 0;
-                               }
-                       }
-
-                       /*
-                        *      Still non available, so allocate more memory for a set of blocks
-                        *      OPT -- should bypass mprAlloc. Need mprMalloc.
-                        */
-                       block = mprAlloc(ep->slabAllocContext, 
-                               slab->size * slab->allocIncrement);
-                       if (block == 0) {
-                               /*
-                                *      Now we're in trouble. We should really never get here
-                                *      as the graceful degrade will have signaled a memory 
-                                *      allocation failure.
-                                */
-                               mprAssert(block != 0);
-                               return 0;
-                       }
-
-                       /*
-                        *      Chain all the blocks together onto the slab free list
-                        */
-                       for (i = slab->allocIncrement - 1; i >= 0; i--) {
-                               block->next = slab->freeList.next;
-#if BLD_DEBUG
-                               block->magic = EJS_MAGIC_FREE;
-#endif
-                               slab->freeList.next = block;
-                               block = (EjsGCLink*) ((char*) block + slab->size);
-                       }
-
-                       block = slab->freeList.next;
-
-#if BLD_FEATURE_ALLOC_STATS
-                       slab->freeCount += slab->allocIncrement;
-                       if (slab->freeCount > slab->peakFree) {
-                               slab->peakFree = slab->freeCount;
-                       }
-#endif
-               }
-       }
-
-       /*
-        *      We use block to point to the user data in the block. We only
-        *      store the magic number (if debug). No other data is stored in the
-        *      user block.
-        */
-#if BLD_DEBUG
-       mprAssert(block->magic == EJS_MAGIC_FREE);
-#endif
-
-       /*
-        *      Remove from the free list
-        */
-       slab->freeList.next = block->next;
-
-       /*
-        *      Zero block
-        */
-       memset(block, 0, slab->size);
-
-#if BLD_DEBUG
-       block->magic = EJS_MAGIC;
-#endif
-
-#if BLD_FEATURE_ALLOC_STATS
-       slab->totalAlloc++;
-       if (++slab->allocCount > slab->peakAllocated) {
-               slab->peakAllocated = slab->allocCount;
-       }
-       slab->freeCount--;
-#endif
-
-#if BLD_DEBUG && (!BREW || BREW_SIMULATOR)
-       if ((uint) block == breakAddr) {
-               mprBreakpoint(MPR_LOC, "Watched Block");
-       }
-#endif
-       return block;
-}
-
-
-/******************************************************************************/
-
-EjsObj *ejsAllocObj(EJS_LOC_DEC(ep, loc))
-{
-       EjsObj          *obj;
-       EjsSlab         *slab;
-
-       obj = (EjsObj*) ejsAlloc(EJS_LOC_PASS(ep, loc), EJS_SLAB_OBJ);
-
-       /*
-        *      Add to the allocated block list for the New generation.
-        */
-       if (obj) {
-               slab = &ep->slabs[EJS_SLAB_OBJ];
-               obj->gc.next = slab->allocList[EJS_GEN_NEW].next;
-
-#if BLD_FEATURE_ALLOC_LEAK_TRACK
-               obj->gc.allocatedBy = loc;
-#endif
-
-               obj->ejs = ep;
-               slab->allocList[EJS_GEN_NEW].next = (EjsGCLink*) obj;
-
-               ep->gc.workDone++;
-       }
-
-       return obj;
-}
-
-
-/******************************************************************************/
-
-EjsProperty *ejsAllocProperty(EJS_LOC_DEC(ep, loc))
-{
-       EjsProperty             *prop;
-
-       prop = (EjsProperty*) ejsAlloc(EJS_LOC_PASS(ep, loc), EJS_SLAB_PROPERTY);
-       mprAssert(prop);
-
-       if (prop) {
-               prop->var.type = EJS_TYPE_NULL;
-               prop->var.isProperty = 1;
-#if BLD_FEATURE_ALLOC_LEAK_TRACK
-               prop->var.gc.allocatedBy = loc;
-#endif
-       }
-       return prop;
-}
-
-
-/******************************************************************************/
-
-EjsVar *ejsAllocVar(EJS_LOC_DEC(ep, loc))
-{
-       EjsVar  *vp;
-
-       vp = (EjsVar*) ejsAlloc(EJS_LOC_PASS(ep, loc), EJS_SLAB_VAR);
-       mprAssert(vp);
-
-       if (vp) {
-#if BLD_FEATURE_ALLOC_LEAK_TRACK
-               EjsSlab *slab;
-               vp->gc.allocatedBy = loc;
-               slab = &ep->slabs[EJS_SLAB_VAR];
-               vp->gc.next = slab->allocList[EJS_GEN_NEW].next;
-               slab->allocList[EJS_GEN_NEW].next = (EjsGCLink*) vp;
-#endif
-#if BLD_DEBUG
-               vp->propertyName = 0;
-#endif
-       }
-       return vp;
-}
-
-
-/******************************************************************************/
-/*
- *     Return the block back to the relevant slab
- */
-
-void ejsFree(Ejs *ep, void *ptr, int slabIndex)
-{
-       EjsSlab         *slab;
-       EjsGCLink       *block;
-
-       mprAssert(ep);
-       mprAssert(ptr);
-
-       if (slabIndex < 0 || slabIndex >= EJS_SLAB_MAX) {
-               mprAssert(slabIndex >= 0 && slabIndex < EJS_SLAB_MAX);
-               return;
-       }
-       slab = &ep->slabs[slabIndex];
-
-#if BLD_FEATURE_ALLOC_LEAK_TRACK
-       if (slabIndex == EJS_SLAB_VAR) {
-               EjsVar          *vp, *np, *prev;
-
-               /*
-                *      Remove the block rom the alloc list. WARNING: this is slow
-                *      and should not be used in production code.
-                */
-               vp = (EjsVar*) ptr;
-               prev = 0;
-               for (np = (EjsVar*) slab->allocList[0].next; np; 
-                               np = (EjsVar*) np->gc.next) {
-                       if (vp == np) {
-                               if (prev) {
-                                       prev->gc.next = (EjsGCLink*) np->gc.next;
-                               } else {
-                                       slab->allocList[0].next = (EjsGCLink*) np->gc.next;
-                               }
-                               break;
-                       }
-                       prev = np;
-               }
-               if (np == 0) {
-                       mprAssert(0);
-               }
-       }
-#endif
-
-       /*
-        *      Insert into the free list. Only use the next ptr
-        */
-       block = (EjsGCLink*) ptr;
-
-#if BLD_DEBUG
-#if !BREW || BREW_SIMULATOR
-       if ((uint) block == breakAddr) {
-               mprBreakpoint(MPR_LOC, "Watched Block");
-       }
-#endif
-       mprAssert(block->magic == EJS_MAGIC);
-       block->magic = EJS_MAGIC_FREE;
-#endif
-
-       block->next = slab->freeList.next;
-       slab->freeList.next = block;
-
-#if BLD_FEATURE_ALLOC_STATS
-       slab->allocCount--;
-       if (++slab->freeCount >= slab->peakFree) {
-               slab->peakFree = slab->freeCount;
-       }
-       slab->totalReclaimed++;
-       if (slabIndex != 2) {
-               slabIndex = slabIndex;
-       }
-#endif
-}
-
-/******************************************************************************/
-/*
- *     Mark an object as being in-use. Traverse all properties for referenced 
- *     objects and base classes.
- */
-
-static void markObjByVar(Ejs *ep, EjsVar *obj)
-{
-       EjsProperty             *pp;
-       EjsVar                  *vp, *baseClass;
-
-       mprAssert(ep);
-       mprAssert(obj);
-
-       obj->objectState->gcMarked = 1;
-
-#if BLD_DEBUG
-       if (ep->gc.debugLevel >= 3) {
-               int indent = min(ep->gc.gcIndent * 2, 32);
-               mprLog(ep, 0, "%.*s %-24s %.*s 0x%08X", 
-                       indent, "                                 ",
-                       obj->propertyName,
-                       32 - indent, "................................ ",
-                       (uint) obj->objectState);
-               ep->gc.gcIndent++;
-       }
-       ep->gc.objectsInUse++;
-#endif
-
-       /*
-        *      Traverse all referenced objects
-        *      OPT -- optimize by directly accessing the object links and not using
-        *      ejsGetFirst/NextProperty. Then just examine objects
-        *      OPT -- first property in global is global. Should optimize this.
-        */
-       pp = ejsGetFirstProperty(obj, EJS_ENUM_ALL);
-       while (pp) {
-               vp = ejsGetVarPtr(pp);
-               if (vp->type == EJS_TYPE_OBJECT) {
-                       if (!vp->objectState->gcMarked) {
-#if FUTURE
-                               /*
-                                *      OPT -- we can use the dirty bit on objects to avoid 
-                                *      visiting permanent objects that are clean. If so, don't
-                                *      forget the else case below.
-                                */
-                               obj = vp->objectState;
-                               if ((!obj->alive && !obj->permanent) || obj->dirty)
-#endif
-                               markObjByVar(ep, vp);
-                       }
-
-               } else {
-#if BLD_DEBUG
-                       if (ep->gc.debugLevel >= 3) {
-                               int indent = min(ep->gc.gcIndent * 2, 32);
-                               mprLog(ep, 0, "%.*s %-24s %.*s %s", 
-                                       indent, "                                 ",
-                                       vp->propertyName,
-                                       32 - indent, "................................ ",
-                                       ejsGetVarTypeAsString(vp));
-                       }
-                       ep->gc.propertiesInUse++;
-#endif
-               }
-               pp = ejsGetNextProperty(pp, EJS_ENUM_ALL);
-       }
-
-       /*
-        *      Traverse the base class
-        */
-       baseClass = obj->objectState->baseClass;
-       if (baseClass) {
-               mprAssert(baseClass->type == EJS_TYPE_OBJECT);
-               mprAssert(baseClass->objectState);
-               if (baseClass->objectState) {
-                       if (! baseClass->objectState->gcMarked) {
-                               markObjByVar(ep, baseClass);
-                       }
-               }
-       }
-#if BLD_DEBUG
-       if (ep->gc.debugLevel >= 3) {
-               ep->gc.gcIndent--;
-       }
-#endif
-}
-
-
-/******************************************************************************/
-/*
- *     Mark phase. Examine all variable frames and the return result.
- */
-
-static void mark(Ejs *ep)
-{
-       EjsVar  *vp;
-       int             i;
-
-#if BLD_DEBUG
-       if (ep->gc.debugLevel >= 3) {
-               mprLog(ep, 0, " ");
-               mprLog(ep, 0, "GC: Marked Blocks:");
-       }
-#endif
-
-       if (ep->frames) {
-               for (i = 0; i < mprGetItemCount(ep->frames); i++) {
-
-                       vp = (EjsVar*) mprGetItem(ep->frames, i);
-                       mprAssert(vp->type == EJS_TYPE_OBJECT);
-
-                       if (! vp->objectState->gcMarked) {
-                               markObjByVar(ep, vp);
-                       }
-               }
-       }
-
-       vp = ep->result;
-       if (vp && vp->type == EJS_TYPE_OBJECT && ! vp->objectState->gcMarked) {
-               markObjByVar(ep, vp);
-       }
-
-       vp = ep->currentObj;
-       if (vp && vp->type == EJS_TYPE_OBJECT && ! vp->objectState->gcMarked) {
-               markObjByVar(ep, vp);
-       }
-
-       vp = ejsGetVarPtr(ep->currentProperty);
-       if (vp && vp->type == EJS_TYPE_OBJECT && ! vp->objectState->gcMarked) {
-               markObjByVar(ep, vp);
-       }
-
-       /*
-        *      OPT -- we could mark master as "mark permanent" somehow and
-        *      then we would not need to walk the master objects.
-        */
-       if (ep->slabAllocContext == ep->service->master) {
-               if (ep->service->master->global) {
-                       markObjByVar(ep, ep->service->master->global);
-               }
-       }
-
-#if BLD_DEBUG
-       if (ep->gc.debugLevel >= 3) {
-               mprLog(ep, 0, " ");
-       }
-#endif
-}
-
-
-/******************************************************************************/
-#if UNUSED
-
-static void resetMark(EjsVar *obj)
-{
-       EjsProperty             *pp;
-       EjsVar                  *vp, *baseClass;
-
-       obj->objectState->gcMarked = 0;
-       obj->objectState->visited = 1;
-
-       pp = ejsGetFirstProperty(obj, EJS_ENUM_ALL);
-       while (pp) {
-               vp = ejsGetVarPtr(pp);
-               if (vp->type == EJS_TYPE_OBJECT && !vp->objectState->visited) {
-                       resetMark(vp);                  
-               }
-               pp = ejsGetNextProperty(pp, EJS_ENUM_ALL);
-       }
-
-       baseClass = obj->objectState->baseClass;
-       if (baseClass) {
-               mprAssert(baseClass->type == EJS_TYPE_OBJECT);
-               mprAssert(baseClass->objectState);
-               if (baseClass->objectState) {
-                       if (! baseClass->objectState->visited) {
-                               resetMark(baseClass);
-                       }
-               }
-       }
-       obj->objectState->visited = 0;
-}
-
-/******************************************************************************/
-/*
- *     Mark phase. Examine all variable frames and the return result.
- */
-
-static void resetAllMarks(Ejs *ep)
-{
-       EjsVar  *vp;
-       int             i;
-
-       for (i = 0; i < mprGetItemCount(ep->frames); i++) {
-               vp = (EjsVar*) mprGetItem(ep->frames, i);
-               resetMark(vp);
-       }
-
-       if (ep->result && ep->result->type == EJS_TYPE_OBJECT &&
-                       ! ep->result->objectState->gcMarked) {
-               resetMark(ep->result);
-       }
-}
-
-#endif
-/******************************************************************************/
-/*
- *     Sweep up the garbage
- */
-
-static void resetMarks(Ejs *ep, EjsSlab *slab)
-{
-       EjsVar          *vp;
-       EjsObj          *obj;
-       int                     gen, i;
-
-       for (gen = EJS_GEN_NEW; gen < EJS_GEN_MAX; gen++) {
-               obj = (EjsObj*) slab->allocList[gen].next;
-               for (; obj; obj = (EjsObj*) obj->gc.next) {
-                       obj->gcMarked = 0;
-                       obj->visited = 0;
-               }
-       }
-
-       if (ep->frames) {
-               for (i = 0; i < mprGetItemCount(ep->frames); i++) {
-
-                       vp = (EjsVar*) mprGetItem(ep->frames, i);
-                       mprAssert(vp->type == EJS_TYPE_OBJECT);
-
-                       vp->objectState->gcMarked = 0;
-                       vp->objectState->visited = 0;
-               }
-       }
-
-       if (ep->result && ep->result->type == EJS_TYPE_OBJECT) {
-               ep->result->objectState->gcMarked = 0;
-       }
-}
-
-/******************************************************************************/
-/*
- *     Mark all permanent and non-alive objects
- */
-
-static void markPerm(Ejs *ep, uint gen)
-{
-       EjsSlab         *slab;
-       EjsObj          *obj;
-
-       slab = &ep->slabs[EJS_SLAB_OBJ];
-
-       for (obj = (EjsObj*) slab->allocList[gen].next; obj; ) {
-
-               if (! obj->gcMarked) {
-                       if (!obj->alive || obj->permanent) {
-                               markObj(obj);
-                       }
-               }
-               obj = (EjsObj*) obj->gc.next;
-
-       }
-}
-
-/******************************************************************************/
-
-static void markObj(EjsObj *obj)
-{
-       EjsProperty             *pp;
-       EjsPropLink             *lp, *head;
-       EjsObj                  *op;
-
-       mprAssert(obj);
-
-       obj->gcMarked = 1;
-
-       head = &obj->link;
-       for (lp = head->next; lp != head; lp = lp->next) {
-
-               pp = ejsGetPropertyFromLink(lp);
-
-               if (pp->var.type == EJS_TYPE_OBJECT) {
-                       op = pp->var.objectState;
-                       if (op != 0 && !op->gcMarked) {
-                               markObj(op);
-                       }
-               }
-       }
-}
-
-/******************************************************************************/
-/*
- *     Sweep up the garbage. Return the number of objects freed.
- */
-
-static int sweep(Ejs *ep, uint gen)
-{
-       EjsSlab         *slab;
-       EjsObj          *obj, *next, *prev;
-       int                     count;
-
-       slab = &ep->slabs[EJS_SLAB_OBJ];
-
-       /*
-        *      Examine allocated objects in the specified generation (only).
-        *      NOTE: we only sweep object allocated to this interpreter and so
-        *      we do not sweep any permanent objects in the default interpreter.
-        */
-       prev = 0;
-       count = 0;
-       for (obj = (EjsObj*) slab->allocList[gen].next; obj; obj = next) {
-
-               next = (EjsObj*) obj->gc.next;
-
-#if BLD_DEBUG && (!BREW || BREW_SIMULATOR)
-               if ((uint) obj == breakAddr) {
-                       mprBreakpoint(MPR_LOC, "Watched Block");
-               }
-#endif
-
-               /*
-                *      If object has not been marked inuse and is not a permanent
-                *      object, then free it.
-                */
-               if (! obj->gcMarked && obj->alive && !obj->permanent) {
-
-#if BLD_DEBUG
-                       if (ep->gc.debugLevel >= 2) {
-                               if (obj->objName) {
-                                       mprLog(ep, 0, "GC: destroy %-18s   %10d, %8X", 
-                                               obj->objName, (uint) obj, (uint) obj);
-                               } else {
-                                       mprLog(ep, 0, "GC: destroy UNKNOWN %x", (uint) obj);
-                               }
-                       }
-#endif
-                       if (ejsDestroyObj(ep, obj) < 0) {
-                               prev = obj;
-                               obj->gcMarked = 0;
-                               continue;
-                       }
-
-                       if (prev) {
-                               prev->gc.next = (EjsGCLink*) next;
-                       } else {
-                               slab->allocList[gen].next = (EjsGCLink*) next;
-                       }
-                       count++;
-
-               } else {
-                       prev = obj;
-                       /* Reset for next time */
-                       obj->gcMarked = 0;
-               } 
-       }
-
-       if (gen == (EJS_GEN_OLD - 1)) {
-               slab->lastRecentBlock = prev;
-       }
-#if BLD_FEATURE_ALLOC_STATS
-       slab->totalSweeps++;
-#endif
-#if BLD_DEBUG
-       if (ep->gc.debugLevel > 0) {
-               mprLog(ep, 0, "GC: Sweep freed %d objects", count);
-       }
-#endif
-       return count;
-}
-
-/******************************************************************************/
-/*
- *     Sweep all variables
- */
-
-void ejsSweepAll(Ejs *ep)
-{
-       EjsSlab         *slab;
-       EjsObj          *obj, *next, *prev;
-       int                     gen;
-
-       slab = &ep->slabs[EJS_SLAB_OBJ];
-
-       for (gen = EJS_GEN_NEW; gen < EJS_GEN_MAX; gen++) {
-               prev = 0;
-               for (obj = (EjsObj*) slab->allocList[gen].next; obj; obj = next) {
-                       next = (EjsObj*) obj->gc.next;
-                       ejsDestroyObj(ep, obj);
-               }
-               break;
-       }
-}
-
-/******************************************************************************/
-
-bool ejsObjIsCollectable(EjsVar *vp)
-{
-       if (vp == 0 || !ejsVarIsObject(vp)) {
-               return 0;
-       }
-       return (vp->objectState->alive && !vp->objectState->permanent);
-}
-
-/******************************************************************************/
-#if FUTURE
-
-static void ageGenerations(Ejs *ep)
-{
-       EjsSlab         *slab;
-       EjsGCLink       *oldList;
-       int                     gen;
-
-       slab = &ep->slabs[EJS_SLAB_OBJ];
-
-       /*
-        *      Age all blocks. First append all (old - 1) blocks onto the old 
-        *      alloc list 
-        */
-       oldList = &slab->allocList[EJS_GEN_OLD];
-
-       if (slab->lastRecentBlock) {
-               slab->lastRecentBlock->gc.next = oldList->next;
-               oldList->next = (EjsGCLink*) slab->lastRecentBlock;
-       }
-
-       /*
-        *      Now simply copy all allocation lists up one generation
-        */
-       for (gen = EJS_GEN_OLD - 1; gen > 0; gen--) {
-               slab->allocList[gen] = slab->allocList[gen - 1];
-       }
-       slab->allocList[0].next = 0;
-}
-
-#endif
-/******************************************************************************/
-/*
- *     Collect the garbage. This is a mark and sweep over all possible objects.
- *     If an object is not referenced, it and all contained properties will be
- *     freed. If a slabIndex is provided, the collection halts when a block is 
- *     available for allocation on that slab.
- *
- *     Return 0 if memory is now available after collecting garbage. Otherwise,
- *     return MPR_ERR_MEMORY.
- */
-
-int ejsCollectGarbage(Ejs *ep, int slabIndex)
-{
-       EjsGeneration   gen;
-       
-       if (ep->flags & EJS_FLAGS_DONT_GC) {
-               return -1;
-       }
-
-       /*
-        *      Prevent destructors invoking the garbage collector
-        */
-       if (ep->gc.collecting) {
-               return 0;
-       }
-       ep->gc.collecting = 1;
-
-       resetMarks(ep, &ep->slabs[EJS_SLAB_OBJ]);
-
-       /*
-        *      Examine each generation of objects starting with the most recent 
-        *      generation. Stop scanning when we have a free block to use.
-        */
-       for (gen = EJS_GEN_NEW; gen < EJS_GEN_MAX; gen++) {
-
-               if (slabIndex >= 0 && ep->slabs[slabIndex].freeList.next) {
-                       break;
-               }
-
-               /*
-                *      FUTURE OPT. Should mark objects in new generation and those 
-                *      with a dirty bit set in older generations. Don't need to mark
-                *      entire heap. But how to keep list of dirty objects. 
-                */
-               mark(ep);
-               markPerm(ep, gen);
-               sweep(ep, gen);
-
-               /* FUTURE - not using generations yet */
-               break;
-       }
-
-       /*
-        *      FUTURE -- not using generations yet.  
-        *
-        *              ageGenerations(ep);
-        */
-
-       ep->gc.workDone = 0;
-       ep->gc.collecting = 0;
-
-       return (gen < EJS_GEN_MAX) ? 0 : MPR_ERR_MEMORY;
-}
-
-/******************************************************************************/
-/*
- *     Should be called when the app has been idle for a little while and when it
- *     is likely to be idle a bit longer. Call ejsIsTimeForGC to see if this is
- *     true. Return the count of objects collected .
- */
-
-int ejsIncrementalCollectGarbage(Ejs *ep)
-{
-       int             count;
-
-       if (ep->gc.collecting) {
-               return 0;
-       }
-
-       ep->gc.collecting = 1;
-
-       resetMarks(ep, &ep->slabs[EJS_SLAB_OBJ]);
-       mark(ep);
-
-       /* Not generational yet */
-       count = sweep(ep, EJS_GEN_NEW);
-
-       ep->gc.collecting = 0;
-       ep->gc.workDone = 0;
-
-       return count;
-}
-
-/******************************************************************************/
-#if BLD_DEBUG
-
-void ejsDumpObjects(Ejs *ep)
-{
-       int             oldDebugLevel;
-
-       mprLog(ep, 0, "Dump of objects in use\n");
-
-       oldDebugLevel = ep->gc.debugLevel;
-
-       ep->gc.debugLevel = 3;
-       ep->gc.objectsInUse = 0;
-       ep->gc.propertiesInUse = 0;
-       ep->gc.collecting = 1;
-
-       resetMarks(ep, &ep->slabs[EJS_SLAB_OBJ]);
-       mark(ep);
-
-       ep->gc.collecting = 0;
-       ep->gc.debugLevel = oldDebugLevel;
-
-       mprLog(ep, 0, "%d objects and %d properties in use",
-               ep->gc.objectsInUse, ep->gc.propertiesInUse);
-       mprLog(ep, 0, "%d object bytes, %d property bytes and %d total",
-               (int) (ep->gc.objectsInUse * sizeof(EjsObj)),
-               (int) (ep->gc.propertiesInUse * sizeof(EjsProperty)),
-               (int) ((ep->gc.objectsInUse * sizeof(EjsObj) +
-                               ep->gc.propertiesInUse * sizeof(EjsProperty))));
-}
-
-#endif
-/******************************************************************************/
-/*
- *     Return true if there is time to do a garbage collection and if we will
- *     benefit from it.
- */
-
-int ejsIsTimeForGC(Ejs *ep, int timeTillNextEvent)
-{
-       EjsGC           *gc;
-
-       if (timeTillNextEvent < EJS_MIN_TIME_FOR_GC) {
-               /*
-                *      Not enough time to complete a collection
-                */
-               return 0;
-       }
-
-       gc = &ep->gc;
-
-       /*
-        *      Return if we haven't done enough work to warrant a collection
-        *      Trigger a little short of the work quota to try to run GC before
-        *      a demand allocation requires it.
-        */
-       if (!gc->enable || !gc->enableIdleCollect || 
-                       (gc->workDone < (gc->workQuota - EJS_GC_MIN_WORK_QUOTA))) {
-               return 0;
-       }
-
-#if UNUSED
-       mprLog(ep, 0, "Time for GC. Work done %d, time till next event %d",
-               gc->workDone, timeTillNextEvent);
-#endif
-       return 1;
-}
-
-/******************************************************************************/
-/*
- *     Return the amount of memory in use by EJS
- */
-
-uint ejsGetUsedMemory(Ejs *ep)
-{
-#if BLD_FEATURE_ALLOC_STATS
-       EjsSlab         *slab;
-       int                     i, totalMemory, slabMemory;
-
-       totalMemory = 0;
-       for (i = 0; i < EJS_SLAB_MAX; i++) {
-               slab = &ep->slabs[i];
-               slabMemory = slab->allocCount * slab->size;
-               totalMemory += slabMemory;
-       }
-       return totalMemory;
-#else
-       return 0;
-#endif
-}
-
-/******************************************************************************/
-/*
- *     Return the amount of memory allocated by EJS
- */
-
-uint ejsGetAllocatedMemory(Ejs *ep)
-{
-#if BLD_FEATURE_ALLOC_STATS
-       EjsSlab         *slab;
-       int                     i, totalMemory, slabMemory;
-
-       totalMemory = 0;
-       for (i = 0; i < EJS_SLAB_MAX; i++) {
-               slab = &ep->slabs[i];
-               slabMemory = (slab->allocCount + slab->freeCount) * slab->size;
-               totalMemory += slabMemory;
-       }
-       return totalMemory;
-#else
-       return 0;
-#endif
-}
-
-/******************************************************************************/
-/*
- *     On a memory allocation failure, go into graceful degrade mode. Set all
- *     slab allocation chunk increments to 1 so we can create an exception block 
- *     to throw.
- */
-
-static void ejsGracefulDegrade(Ejs *ep)
-{
-       EjsSlab         *slab;
-       int                     i;
-
-       mprLog(ep, 1, "WARNING: Memory almost depleted. In graceful degrade mode");
-       for (i = 0; i < EJS_SLAB_MAX; i++) {
-               slab = &ep->slabs[i];
-               slab->allocIncrement = 8;
-       }
-       ep->gc.degraded = 1;
-}
-
-/******************************************************************************/
-
-int ejsSetGCDebugLevel(Ejs *ep, int debugLevel)
-{
-       int             old;
-
-       old = ep->gc.debugLevel;
-       ep->gc.debugLevel = debugLevel;
-       return old;
-}
-
-/******************************************************************************/
-
-int ejsSetGCMaxMemory(Ejs *ep, uint maxMemory)
-{
-       int             old;
-
-       old = ep->gc.maxMemory;
-       ep->gc.maxMemory = maxMemory;
-
-       return old;
-}
-
-/******************************************************************************/
-
-bool ejsBlockInUseInt(EjsVar *vp)
-{
-       if (vp) {
-#if BLD_DEBUG
-               if (vp->gc.magic != EJS_MAGIC) {
-                       return 0;
-               }
-               if (vp->type == EJS_TYPE_OBJECT && vp->objectState && 
-                       vp->objectState->gc.magic != EJS_MAGIC) {
-                       return 0;
-               }
-#endif
-               return 1;
-       }
-       return 1;
-}
-
-/******************************************************************************/
-#else
-void ejsGarbageDummy() {}
-
-#endif /* BLD_FEATURE_EJS */
-
-/******************************************************************************/
-/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- * vim:tw=78
- * vim600: sw=4 ts=4 fdm=marker
- * vim<600: sw=4 ts=4
- */