aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rwxr-xr-xemcc9
-rw-r--r--src/library_gc.js71
-rw-r--r--system/include/gc.h9
-rw-r--r--system/include/libc/sys/features.h5
-rw-r--r--system/include/libc/sys/types.h6
-rwxr-xr-xtests/runner.py19
7 files changed, 106 insertions, 14 deletions
diff --git a/AUTHORS b/AUTHORS
index f491acc0..74efb628 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -47,6 +47,7 @@ a license to everyone to use it as detailed in LICENSE.)
* Michael Riss <Michael.Riss@gmx.de>
* Jasper St. Pierre <jstpierre@mecheye.net>
* Manuel Schölling <manuel.schoelling@gmx.de>
+* Bruce Mitchener, Jr. <bruce.mitchener@gmail.com>
diff --git a/emcc b/emcc
index 73f12cda..3ea0a964 100755
--- a/emcc
+++ b/emcc
@@ -248,6 +248,15 @@ Options that are modified or new in %s include:
are compiling to. To run your code, you
will need both the .html and the .data.
+ emcc runs tools/file_packager.py to do the
+ actual packaging of embedded and preloaded
+ files. You can run the file packager yourself
+ if you want, see docs inside that file. You
+ should then put the output of the file packager
+ in an emcc --pre-js, so that it executes before
+ your main compiled code (or run it before in
+ some other way).
+
--compression <codec> Compress both the compiled code and embedded/
preloaded files. <codec> should be a triple,
diff --git a/src/library_gc.js b/src/library_gc.js
index fe4cbf63..083019ca 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'],
$GC: {
ALLOCATIONS_TO_GC: 1*1024*1024,
sizes: {}, // if in this map, then a live allocated object. this is iterable
scannables: {},
+ uncollectables: {},
finalizers: {},
finalizerArgs: {},
@@ -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();
},
@@ -123,7 +167,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 +184,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 +212,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();
diff --git a/system/include/gc.h b/system/include/gc.h
index e0419dcb..8c5a8989 100644
--- a/system/include/gc.h
+++ b/system/include/gc.h
@@ -29,6 +29,12 @@ void *GC_MALLOC(int bytes);
/* Allocate memory for an object that the user promises will not contain pointers. */
void *GC_MALLOC_ATOMIC(int bytes);
+/* Allocate memory that might container pointers but that can't be collected. */
+void *GC_MALLOC_UNCOLLECTABLE(int bytes);
+
+/* Reallocate a GC managed memory block to a new size. */
+void *GC_REALLOC(void *ptr, int newBytes);
+
/* Explicitly deallocate an object. Dangerous as it forces a free and does not check if the object is reffed. */
void GC_FREE(void *ptr);
@@ -36,6 +42,9 @@ void GC_FREE(void *ptr);
void GC_REGISTER_FINALIZER_NO_ORDER(void *ptr, void (*func)(void *, void *), void *arg,
void *(*old_func)(void *, void *), void *old_arg);
+/* Gets the bytes allocated and managed by the GC */
+int GC_get_heap_size();
+
/* Non-Boehm additions */
/* Call this once per frame or such, it will collect if necessary */
diff --git a/system/include/libc/sys/features.h b/system/include/libc/sys/features.h
index 87a520a0..8c32bf04 100644
--- a/system/include/libc/sys/features.h
+++ b/system/include/libc/sys/features.h
@@ -26,7 +26,10 @@ extern "C" {
#endif
#if EMSCRIPTEN
-#define _POSIX_REALTIME_SIGNALS 1
+#define _POSIX_REALTIME_SIGNALS 1
+#define _POSIX_THREADS 200112L
+#define _UNIX98_THREAD_MUTEX_ATTRIBUTES 1
+#define _POSIX_READER_WRITER_LOCKS 200112L
#endif
/* RTEMS adheres to POSIX -- 1003.1b with some features from annexes. */
diff --git a/system/include/libc/sys/types.h b/system/include/libc/sys/types.h
index e90a74ac..c36f724c 100644
--- a/system/include/libc/sys/types.h
+++ b/system/include/libc/sys/types.h
@@ -24,12 +24,6 @@
#include <machine/_types.h>
-#if EMSCRIPTEN
- #define _POSIX_THREADS
- #define _UNIX98_THREAD_MUTEX_ATTRIBUTES
- #define _POSIX_READER_WRITER_LOCKS
-#endif
-
#if defined(__rtems__) || defined(__XMK__) || defined(EMSCRIPTEN)
/*
* The following section is RTEMS specific and is needed to more
diff --git a/tests/runner.py b/tests/runner.py
index ea76aec6..4c8b6379 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -7889,7 +7889,7 @@ def process(filename):
int main() {
GC_INIT();
- void *local, *local2, *local3, *local4;
+ void *local, *local2, *local3, *local4, *local5, *local6;
// Hold on to global, drop locals
@@ -7934,6 +7934,20 @@ def process(filename):
GC_REGISTER_FINALIZER_NO_ORDER(local3, finalizer, (void*)3, 0, 0);
local4 = GC_MALLOC(12);
GC_REGISTER_FINALIZER_NO_ORDER(local4, finalizer, (void*)4, 0, 0);
+ local5 = GC_MALLOC_UNCOLLECTABLE(12);
+ // This should never trigger since local5 is uncollectable
+ GC_REGISTER_FINALIZER_NO_ORDER(local5, finalizer, (void*)5, 0, 0);
+
+ printf("heap size = %d\n", GC_get_heap_size());
+
+ local4 = GC_REALLOC(local4, 24);
+
+ printf("heap size = %d\n", GC_get_heap_size());
+
+ local6 = GC_MALLOC(12);
+ GC_REGISTER_FINALIZER_NO_ORDER(local6, finalizer, (void*)6, 0, 0);
+ // This should be the same as a free
+ GC_REALLOC(local6, 0);
void **globalData = (void**)global;
globalData[0] = local;
@@ -7970,6 +7984,9 @@ finalizing2 2 (global == 0)
finalizing2 3 (global == 0)
*
finalizing 0 (global == 1)
+heap size = 72
+heap size = 84
+finalizing 6 (global == 0)
object scan test test
finalizing 4 (global == 0)
*