diff options
Diffstat (limited to 'src/library_gc.js')
-rw-r--r-- | src/library_gc.js | 80 |
1 files changed, 68 insertions, 12 deletions
diff --git a/src/library_gc.js b/src/library_gc.js index fe4cbf63..b3dae0e9 100644 --- a/src/library_gc.js +++ b/src/library_gc.js @@ -1,14 +1,16 @@ if (GC_SUPPORT) { EXPORTED_FUNCTIONS['_calloc'] = 1; + EXPORTED_FUNCTIONS['_realloc'] = 1; var LibraryGC = { - $GC__deps: ['sbrk'], + $GC__deps: ['sbrk', 'realloc', 'calloc'], $GC: { ALLOCATIONS_TO_GC: 1*1024*1024, sizes: {}, // if in this map, then a live allocated object. this is iterable scannables: {}, + uncollectables: {}, finalizers: {}, finalizerArgs: {}, @@ -24,7 +26,7 @@ if (GC_SUPPORT) { _GC_finalizer_notifier = _malloc(4); setValue(_GC_finalizer_notifier, 0, 'i32'); if (ENVIRONMENT_IS_WEB) { - setInterval(function() { + Browser.safeSetInterval(function() { GC.maybeCollect(); }, 1000); } else { @@ -34,7 +36,7 @@ if (GC_SUPPORT) { } }, - malloc: function(bytes, clear, scannable) { + malloc: function(bytes, clear, scannable, collectable) { if (!bytes) return 0; var ptr; if (clear) { @@ -42,6 +44,9 @@ if (GC_SUPPORT) { } else { ptr = _malloc(bytes); } + if (!collectable) { + GC.uncollectables[ptr] = true; + } GC.scannables[ptr] = scannable; GC.sizes[ptr] = bytes; GC.totalAllocations += bytes; @@ -49,6 +54,41 @@ if (GC_SUPPORT) { return ptr; }, + realloc: function(ptr, newBytes) { + if (newBytes != 0) { + var oldBytes = GC.sizes[ptr]; + var newPtr = _realloc(ptr, newBytes); + if (newBytes > oldBytes) { + _memset(newPtr + oldBytes, 0, newBytes - oldBytes); + } + delete GC.sizes[ptr]; + GC.sizes[newPtr] = newBytes; + scannable = GC.scannables[ptr]; + delete GC.scannables[ptr]; + GC.scannables[newPtr] = scannable; + var finalizer = GC.finalizers[ptr]; + if (finalizer) { + delete GC.finalizers[ptr]; + GC.finalizers[newPtr] = finalizer; + } + var finalizerArgs = GC.finalizerArgs[ptr]; + if (finalizerArgs) { + delete GC.finalizerArgs[ptr]; + GC.finalizerArgs[newPtr] = finalizerArgs; + } + var uncollectable = GC.uncollectables[ptr]; + if (uncollectable) { + delete GC.uncollectables[ptr]; + GC.uncollectables[newPtr] = true; + } + GC.totalAllocations += (newBytes - oldBytes); + return newPtr; + } else { + GC.free(ptr); + return 0; + } + }, + free: function(ptr) { // does not check if anything refers to it, this is a forced free var finalizer = GC.finalizers[ptr]; if (finalizer) { @@ -56,8 +96,8 @@ if (GC_SUPPORT) { GC.finalizers[ptr] = 0; } _free(ptr); - delete GC.sizes[ptr]; GC.totalAllocations -= GC.sizes[ptr]; + delete GC.sizes[ptr]; }, registerFinalizer: function(ptr, func, arg, oldFunc, oldArg) { @@ -74,6 +114,10 @@ if (GC_SUPPORT) { GC.finalizerArgs[ptr] = arg; }, + getHeapSize: function() { + return GC.totalAllocations; + }, + maybeCollect: function() { if (GC.needCollect()) GC.collect(); }, @@ -104,12 +148,9 @@ if (GC_SUPPORT) { prep: function() { // Clear reachables and scan for roots GC.reachable = {}; // 1 if reachable. XXX GC.reachableList = []; // each reachable is added once to this. XXX - // static data areas - var staticStart = STACK_MAX; - var staticEnd = _sbrk.DYNAMIC_START || STATICTOP; // after DYNAMIC_START, sbrk manages it (but it might not exist yet) - GC.scan(staticStart, staticEnd); + GC.scan(STATIC_BASE, STATICTOP); // TODO: scan stack and registers. Currently we assume we run from a timeout or such, so no stack/regs - // stack: STACK_ROOT to STACKTOP + // stack: STACK_BASE to STACKTOP // registers: call scanners }, @@ -123,7 +164,7 @@ if (GC_SUPPORT) { sweep: function() { // traverse all objects and free all unreachable var freeList = []; for (var ptr in GC.sizes) { - if (!GC.reachable[ptr]) { + if (!GC.reachable[ptr] && !GC.uncollectables[ptr]) { freeList.push(parseInt(ptr)); } } @@ -140,12 +181,22 @@ if (GC_SUPPORT) { GC_MALLOC__deps: ['$GC'], GC_MALLOC: function(bytes) { - return GC.malloc(bytes, true, true); + return GC.malloc(bytes, true, true, true); }, GC_MALLOC_ATOMIC__deps: ['$GC'], GC_MALLOC_ATOMIC: function(bytes) { - return GC.malloc(bytes, false, false); + return GC.malloc(bytes, false, false, true); + }, + + GC_MALLOC_UNCOLLECTABLE__deps: ['$GC'], + GC_MALLOC_UNCOLLECTABLE: function(bytes) { + return GC.malloc(bytes, true, true, false); + }, + + GC_REALLOC__deps: ['$GC'], + GC_REALLOC: function(ptr, newBytes) { + return GC.realloc(ptr, newBytes); }, GC_FREE__deps: ['$GC'], @@ -158,6 +209,11 @@ if (GC_SUPPORT) { GC.registerFinalizer(ptr, func, arg, old_func, old_arg); }, + GC_get_heap_size__deps: ['$GC'], + GC_get_heap_size: function() { + return GC.getHeapSize(); + }, + GC_MAYBE_COLLECT__deps: ['$GC'], GC_MAYBE_COLLECT: function() { GC.maybeCollect(); |