From 2bda48dd261b64991c5ced52d72d87b44008ad43 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 30 Jan 2024 16:01:40 -0800 Subject: [PATCH] More fixes for 4gb and 2gb high memory modes --- .circleci/config.yml | 2 + src/library_html5_webgl.js | 3 +- system/include/emscripten/html5_webgl.h | 2 +- test/browser/emmalloc_memgrowth.cpp | 55 +++++++++++-------------- test/browser/webgl_create_context.cpp | 4 +- test/fs/test_idbfs_sync.c | 47 ++++++++------------- test/test_browser.py | 42 +++++++++++++++---- 7 files changed, 84 insertions(+), 71 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 109750f75af8a..47dbfc306f1da 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -819,6 +819,7 @@ jobs: browser_2gb.test_emscripten_animate_canvas_element_size_manual_css browser_2gb.test_fulles2_sdlproc browser_2gb.test_cubegeom* + browser_2gb.test_html5_webgl_create_context* " test-browser-chrome-wasm64-4gb: executor: bionic @@ -834,6 +835,7 @@ jobs: browser64_4gb.test_fetch* browser64_4gb.test_emscripten_animate_canvas_element_size_manual_css browser64_4gb.test_fulles2_sdlproc + browser64_4gb.test_html5_webgl_create_context* " test-browser-firefox: executor: bionic diff --git a/src/library_html5_webgl.js b/src/library_html5_webgl.js index 54641a83c59c4..88583ef59fec4 100644 --- a/src/library_html5_webgl.js +++ b/src/library_html5_webgl.js @@ -14,8 +14,9 @@ var LibraryHtml5WebGL = { var len = arr.length; var writeLength = dstLength < len ? dstLength : len; var heap = heapType ? HEAPF32 : HEAP32; + dst = {{{ getHeapOffset('dst', 'float') }}}; for (var i = 0; i < writeLength; ++i) { - heap[(dst >> 2) + i] = arr[i]; + heap[dst + i] = arr[i]; } return len; }, diff --git a/system/include/emscripten/html5_webgl.h b/system/include/emscripten/html5_webgl.h index 98971be3216db..b9d5980afcf2e 100644 --- a/system/include/emscripten/html5_webgl.h +++ b/system/include/emscripten/html5_webgl.h @@ -14,7 +14,7 @@ extern "C" { #endif -typedef intptr_t EMSCRIPTEN_WEBGL_CONTEXT_HANDLE; +typedef uintptr_t EMSCRIPTEN_WEBGL_CONTEXT_HANDLE; typedef int EMSCRIPTEN_WEBGL_CONTEXT_PROXY_MODE; #define EMSCRIPTEN_WEBGL_CONTEXT_PROXY_DISALLOW 0 diff --git a/test/browser/emmalloc_memgrowth.cpp b/test/browser/emmalloc_memgrowth.cpp index 21cf1a3972758..9e42332c31bf5 100644 --- a/test/browser/emmalloc_memgrowth.cpp +++ b/test/browser/emmalloc_memgrowth.cpp @@ -5,37 +5,30 @@ uint64_t nextAllocationSize = 16*1024*1024; bool allocHasFailed = false; -void grow_memory() -{ - uint8_t *ptr = (uint8_t*)malloc((size_t)nextAllocationSize); - EM_ASM({}, ptr); // Pass ptr out to confuse LLVM that it is used, so it won't optimize it away in -O1 and higher. - size_t heapSize = emscripten_get_heap_size(); - printf("Allocated %zu: %d. Heap size: %zu\n", (size_t)nextAllocationSize, ptr ? 1 : 0, heapSize); - if (ptr) - { - if (!allocHasFailed) - { - nextAllocationSize *= 2; - // Make sure we don't overflow, and also exercise malloc(-1) to gracefully return 0 in ABORTING_MALLOC=0 mode. - if (nextAllocationSize > 0xFFFFFFFFULL) - nextAllocationSize = 0xFFFFFFFFULL; - } - } - else - { - nextAllocationSize /= 2; - allocHasFailed = true; - } +void grow_memory() { + uint8_t *ptr = (uint8_t*)malloc((size_t)nextAllocationSize); + EM_ASM({}, ptr); // Pass ptr out to confuse LLVM that it is used, so it won't optimize it away in -O1 and higher. + size_t heapSize = emscripten_get_heap_size(); + printf("Allocated %zu: %d. Heap size: %zu\n", (size_t)nextAllocationSize, ptr ? 1 : 0, heapSize); + if (ptr) { + if (!allocHasFailed) { + nextAllocationSize *= 2; + // Make sure we don't overflow, and also exercise malloc(-1) to gracefully return 0 in ABORTING_MALLOC=0 mode. + if (nextAllocationSize > 0xFFFFFFFFULL) + nextAllocationSize = 0xFFFFFFFFULL; + } + } else { + nextAllocationSize /= 2; + allocHasFailed = true; + } } -int main() -{ - // Exhaust all available memory. - for(int i = 0; i < 50; ++i) - grow_memory(); - // If we get this far without crashing on OOM, we are ok! - printf("Test finished!\n"); -#ifdef REPORT_RESULT - REPORT_RESULT(0); -#endif +int main() { + // Exhaust all available memory. + for(int i = 0; i < 50; ++i) { + grow_memory(); + } + // If we get this far without crashing on OOM, we are ok! + printf("Test finished!\n"); + return 0; } diff --git a/test/browser/webgl_create_context.cpp b/test/browser/webgl_create_context.cpp index 8d7a6278c0506..3b23d2fc8cb0f 100644 --- a/test/browser/webgl_create_context.cpp +++ b/test/browser/webgl_create_context.cpp @@ -60,7 +60,7 @@ void loop() { assert(emscripten_webgl_get_current_context() == 0); context = emscripten_webgl_create_context("#canvas", &attrs); - assert(context > 0); // Must have received a valid context. + assert(context != NULL); // Must have received a valid context. res = emscripten_webgl_make_context_current(context); assert(res == EMSCRIPTEN_RESULT_SUCCESS); assert(emscripten_webgl_get_current_context() == context); @@ -104,7 +104,7 @@ int main() { assert(emscripten_webgl_get_current_context() == 0); EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context("#customCanvas", &attrs); - assert(context > 0); // Must have received a valid context. + assert(context != NULL); // Must have received a valid context. EMSCRIPTEN_RESULT res = emscripten_webgl_make_context_current(context); assert(res == EMSCRIPTEN_RESULT_SUCCESS); assert(emscripten_webgl_get_current_context() == context); diff --git a/test/fs/test_idbfs_sync.c b/test/fs/test_idbfs_sync.c index 2040e0417fb19..05f478ff4a3e0 100644 --- a/test/fs/test_idbfs_sync.c +++ b/test/fs/test_idbfs_sync.c @@ -15,8 +15,7 @@ int result = 1; -void success() -{ +void success() { REPORT_RESULT(result); #ifdef FORCE_EXIT emscripten_force_exit(0); @@ -24,10 +23,9 @@ void success() } void test() { - int fd; struct stat st; - + #if FIRST // for each file, we first make sure it doesn't currently exist @@ -49,22 +47,20 @@ void test() { fd = open("/working1/waka.txt", O_RDWR | O_CREAT, 0666); if (fd == -1) result = -5000 - errno; - else - { + else { if (write(fd,"az",2) != 2) result = -6000 - errno; if (close(fd) != 0) result = -7000 - errno; } - + // a file whose contents are random-ish string set by the test_browser.py file if ((stat("/working1/moar.txt", &st) != -1) || (errno != ENOENT)) result = -8000 - errno; fd = open("/working1/moar.txt", O_RDWR | O_CREAT, 0666); if (fd == -1) result = -9000 - errno; - else - { + else { if (write(fd, SECRET, strlen(SECRET)) != strlen(SECRET)) result = -10000 - errno; if (close(fd) != 0) @@ -92,8 +88,7 @@ void test() { fd = open("/working1/waka.txt", O_RDONLY); if (fd == -1) result = -17000 - errno; - else - { + else { char bf[4]; int bytes_read = read(fd,&bf[0],sizeof(bf)); if (bytes_read != 2) @@ -105,19 +100,17 @@ void test() { if (unlink("/working1/waka.txt") != 0) result = -21000 - errno; } - + // does the random-ish file exist and does it contain SECRET? fd = open("/working1/moar.txt", O_RDONLY); - if (fd == -1) + if (fd == -1) { result = -22000 - errno; - else - { + } else { char bf[256]; int bytes_read = read(fd,&bf[0],sizeof(bf)); - if (bytes_read != strlen(SECRET)) + if (bytes_read != strlen(SECRET)) { result = -23000; - else - { + } else { bf[strlen(SECRET)] = 0; if (strcmp(bf,SECRET) != 0) result = -24000; @@ -129,14 +122,13 @@ void test() { } // does the directory exist? - if (stat("/working1/dir", &st) != 0) + if (stat("/working1/dir", &st) != 0) { result = -27000 - errno; - else - { + } else { if (!S_ISDIR(st.st_mode)) result = -28000; - if (rmdir("/working1/dir") != 0) - result = -29000 - errno; + if (rmdir("/working1/dir") != 0) + result = -29000 - errno; } #endif @@ -164,20 +156,18 @@ void test() { ccall('success', 'v'); }); ); - } int main() { - EM_ASM( FS.mkdir('/working1'); FS.mount(IDBFS, {}, '/working1'); #if !FIRST - // syncfs(true, f) should not break on already-existing directories: - FS.mkdir('/working1/dir'); + // syncfs(true, f) should not break on already-existing directories: + FS.mkdir('/working1/dir'); #endif - + // sync from persisted state into memory and then // run the 'test' function FS.syncfs(true, function (err) { @@ -187,6 +177,5 @@ int main() { ); emscripten_exit_with_live_runtime(); - return 0; } diff --git a/test/test_browser.py b/test/test_browser.py index 5e3f6e93bf8fc..60136e0f807cb 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -237,6 +237,8 @@ def setUp(self): def require_wasm2js(self): if self.is_wasm64(): self.skipTest('wasm2js is not compatible with MEMORY64') + if self.is_2gb() or self.is_4gb(): + self.skipTest('wasm2j does not support over 2gb of memory') def require_jspi(self): if not is_chrome(): @@ -1525,7 +1527,9 @@ def test_idbstore_sync(self, asyncify): def test_idbstore_sync_worker(self): secret = str(time.time()) - self.btest('test_idbstore_sync_worker.c', expected='0', args=['-lidbstore.js', f'-DSECRET="{secret}"', '-O3', '-g2', '--proxy-to-worker', '-sINITIAL_MEMORY=80MB', '-sASYNCIFY']) + if not self.is_2gb() and not self.is_4gb(): + self.set_setting('INITIAL_MEMORY', '80mb') + self.btest('test_idbstore_sync_worker.c', expected='0', args=['-lidbstore.js', f'-DSECRET="{secret}"', '-O3', '-g2', '--proxy-to-worker', '-sASYNCIFY']) def test_force_exit(self): self.btest_exit('force_exit.c', assert_returncode=10) @@ -1816,6 +1820,7 @@ def test_glgears_animation(self, filename): self.run_browser('something.html', '/report_gl_result?true') @requires_graphics_hardware + @no_4gb('assertion fails') def test_fulles2_sdlproc(self): self.btest_exit('full_es2_sdlproc.c', assert_returncode=1, args=['-sGL_TESTING', '-DHAVE_BUILTIN_SINCOS', '-sFULL_ES2', '-lGL', '-lSDL', '-lglut', '-sGL_ENABLE_GET_PROC_ADDRESS']) @@ -1826,6 +1831,7 @@ def test_glgears_deriv(self): assert 'gl-matrix' not in read_file('test.html'), 'Should not include glMatrix when not needed' @requires_graphics_hardware + @no_4gb('fails to render') def test_glbook(self): self.emcc_args.append('-Wno-int-conversion') self.emcc_args.append('-Wno-pointer-sign') @@ -1859,6 +1865,7 @@ def book_path(path): args=args) @requires_graphics_hardware + @no_4gb('fails to render') @parameterized({ 'normal': (['-sFULL_ES2'],), # Enabling FULL_ES3 also enables ES2 automatically @@ -2017,6 +2024,7 @@ def test_gl_glteximage(self): }) @requires_graphics_hardware @requires_threads + @no_4gb('assertion failure') def test_gl_textures(self, args): self.btest_exit('gl_textures.cpp', args=['-lGL', '-g', '-sSTACK_SIZE=1MB'] + args) @@ -2047,14 +2055,18 @@ def test_gl_renderers(self): self.btest('gl_renderers.c', reference='gl_renderers.png', args=['-sGL_UNSAFE_OPTS=0', '-sLEGACY_GL_EMULATION', '-lGL', '-lSDL']) @requires_graphics_hardware + @no_2gb('render fails') + @no_4gb('render fails') def test_gl_stride(self): self.btest('gl_stride.c', reference='gl_stride.png', args=['-sGL_UNSAFE_OPTS=0', '-sLEGACY_GL_EMULATION', '-lGL', '-lSDL']) @requires_graphics_hardware + @no_4gb('assertion failure') def test_gl_vertex_buffer_pre(self): self.btest('gl_vertex_buffer_pre.c', reference='gl_vertex_buffer_pre.png', args=['-sGL_UNSAFE_OPTS=0', '-sLEGACY_GL_EMULATION', '-lGL', '-lSDL']) @requires_graphics_hardware + @no_4gb('assertion failure') def test_gl_vertex_buffer(self): self.btest('gl_vertex_buffer.c', reference='gl_vertex_buffer.png', args=['-sGL_UNSAFE_OPTS=0', '-sLEGACY_GL_EMULATION', '-lGL', '-lSDL'], reference_slack=1) @@ -2310,6 +2322,7 @@ def test_tex_nonbyte(self): self.btest('tex_nonbyte.c', reference='tex_nonbyte.png', args=['-sLEGACY_GL_EMULATION', '-lGL', '-lSDL']) @requires_graphics_hardware + @no_4gb('fails to render') def test_float_tex(self): self.btest('float_tex.cpp', reference='float_tex.png', args=['-lGL', '-lglut']) @@ -2712,7 +2725,7 @@ def test_html5_webgl_create_context_no_antialias(self, args): '': ([],), 'closure': (['-O2', '-g1', '--closure=1'],), 'full_es2': (['-sFULL_ES2'],), - 'pthread': (['-pthread'],), + 'pthread': (['-pthread', '-sGL_DEBUG'],), }) def test_html5_webgl_create_context(self, args): self.btest_exit('webgl_create_context.cpp', args=args + ['-lGL']) @@ -5571,6 +5584,7 @@ def test_4gb(self): # Tests that emmalloc supports up to 4GB Wasm heaps. @no_firefox('no 4GB support yet') + @no_4gb('uses MAXIMUM_MEMORY') def test_emmalloc_4gb(self): # For now, keep this in browser as this suite runs serially, which # means we don't compete for memory with anything else (and run it @@ -5581,6 +5595,7 @@ def test_emmalloc_4gb(self): # Test that it is possible to malloc() a huge 3GB memory block in 4GB mode using emmalloc. # Also test emmalloc-memvalidate and emmalloc-memvalidate-verbose build configurations. @no_firefox('no 4GB support yet') + @no_2gb('not enough space tp run in this mode') @parameterized({ '': (['-sMALLOC=emmalloc'],), 'debug': (['-sMALLOC=emmalloc-debug'],), @@ -5588,14 +5603,21 @@ def test_emmalloc_4gb(self): 'memvalidate_verbose': (['-sMALLOC=emmalloc-memvalidate-verbose'],), }) def test_emmalloc_3gb(self, args): - self.btest_exit('alloc_3gb.c', - args=['-sMAXIMUM_MEMORY=4GB', '-sALLOW_MEMORY_GROWTH=1'] + args) + if self.is_4gb(): + self.set_setting('MAXIMUM_MEMORY', '8GB') + else: + self.set_setting('MAXIMUM_MEMORY', '4GB') + self.btest_exit('alloc_3gb.c', args=['-sALLOW_MEMORY_GROWTH=1'] + args) # Test that it is possible to malloc() a huge 3GB memory block in 4GB mode using dlmalloc. @no_firefox('no 4GB support yet') + @no_2gb('not enough space tp run in this mode') def test_dlmalloc_3gb(self): - self.btest_exit('alloc_3gb.c', - args=['-sMALLOC=dlmalloc', '-sMAXIMUM_MEMORY=4GB', '-sALLOW_MEMORY_GROWTH=1']) + if self.is_4gb(): + self.set_setting('MAXIMUM_MEMORY', '8GB') + else: + self.set_setting('MAXIMUM_MEMORY', '4GB') + self.btest_exit('alloc_3gb.c', args=['-sMALLOC=dlmalloc', '-sALLOW_MEMORY_GROWTH=1']) @no_wasm64() @parameterized({ @@ -5649,7 +5671,9 @@ def test_wasmfs_opfs_errors(self): @no_firefox('no 4GB support yet') def test_emmalloc_memgrowth(self, *args): - self.btest('emmalloc_memgrowth.cpp', expected='0', args=['-sMALLOC=emmalloc', '-sALLOW_MEMORY_GROWTH=1', '-sABORTING_MALLOC=0', '-sASSERTIONS=2', '-sMINIMAL_RUNTIME=1', '-sMAXIMUM_MEMORY=4GB']) + if not self.is_4gb(): + self.set_setting('MAXIMUM_MEMORY', '4GB') + self.btest_exit('emmalloc_memgrowth.cpp', args=['-sMALLOC=emmalloc', '-sALLOW_MEMORY_GROWTH=1', '-sABORTING_MALLOC=0', '-sASSERTIONS=2', '-sMINIMAL_RUNTIME=1']) @no_firefox('no 4GB support yet') @no_2gb('uses MAXIMUM_MEMORY') @@ -5902,6 +5926,8 @@ def setUp(self): self.set_setting('INITIAL_MEMORY', '4200mb') self.set_setting('GLOBAL_BASE', '4gb') self.emcc_args.append('-Wno-experimental') + # Without this we get a warning about GLOBAL_BASE being ignored when used with SIDE_MODULE + self.emcc_args.append('-Wno-unused-command-line-argument') self.require_wasm64() @@ -5920,3 +5946,5 @@ def setUp(self): super().setUp() self.set_setting('INITIAL_MEMORY', '2200mb') self.set_setting('GLOBAL_BASE', '2gb') + # Without this we get a warning about GLOBAL_BASE being ignored when used with SIDE_MODULE + self.emcc_args.append('-Wno-unused-command-line-argument')