aboutsummaryrefslogtreecommitdiff
path: root/src/library_gc.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/library_gc.js')
-rw-r--r--src/library_gc.js80
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();