Skip to content

Commit 1151c37

Browse files
committed
[WiP] Initial changes to support wasm64 in emcc
1 parent c92bbd5 commit 1151c37

File tree

12 files changed

+124
-38
lines changed

12 files changed

+124
-38
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,3 +522,4 @@ a license to everyone to use it as detailed in LICENSE.)
522522
* Sam Gao <[email protected]>
523523
* Sebastian Mayr <[email protected]>
524524
* Vladimir Gamalyan <[email protected]>
525+
* Wouter van Oortmerssen <[email protected]> (copyright owned by Google, LLC)

emcc.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,8 @@ def backend_binaryen_passes():
554554
# safe heap must run before post-emscripten, so post-emscripten can apply the sbrk ptr
555555
if shared.Settings.SAFE_HEAP:
556556
passes += ['--safe-heap']
557+
if shared.Settings.MEMORY64 == 2:
558+
passes += ['--memory64-lowering']
557559
if run_binaryen_optimizer:
558560
passes += ['--post-emscripten']
559561
if not shared.Settings.EXIT_RUNTIME:
@@ -1894,6 +1896,12 @@ def include_and_export(name):
18941896
if shared.Settings.USE_PTHREADS:
18951897
newargs.append('-pthread')
18961898

1899+
# Any "pointers" passed to JS will now be i64's, in both modes.
1900+
if shared.Settings.MEMORY64:
1901+
if getattr(settings_key_changes, 'WASM_BIGINT', '') == '0':
1902+
exit_with_error('MEMORY64 is not compatible with WASM_BIGINT=0')
1903+
shared.Settings.WASM_BIGINT = 1
1904+
18971905
# check if we can address the 2GB mark and higher: either if we start at
18981906
# 2GB, or if we allow growth to either any amount or to 2GB or more.
18991907
if shared.Settings.INITIAL_MEMORY > 2 * 1024 * 1024 * 1024 or \

src/settings.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,12 @@ var MEMORY_GROWTH_GEOMETRIC_CAP = 96*1024*1024;
214214
// and MEMORY_GROWTH_GEOMETRIC_CAP are ignored.
215215
var MEMORY_GROWTH_LINEAR_STEP = -1;
216216

217+
// The "architecture" to compile for. 0 means the default wasm32, 1 is
218+
// the full end-to-end wasm64 mode, and 2 is wasm64 for clang/lld but lowered to
219+
// wasm32 in Binaryen (such that it can run on wasm32 engines, while internally
220+
// using i64 pointers).
221+
var MEMORY64 = 0;
222+
217223
// If true, allows more functions to be added to the table at runtime. This is
218224
// necessary for dynamic linking, and set automatically in that mode.
219225
var ALLOW_TABLE_GROWTH = 0;

system/include/wasi/api.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929
#include <stddef.h>
3030
#include <stdint.h>
3131

32+
#pragma push_macro("_Static_assert")
33+
#undef _Static_assert
34+
#define _Static_assert(X, Y)
35+
3236
_Static_assert(_Alignof(int8_t) == 1, "non-wasi data layout");
3337
_Static_assert(_Alignof(uint8_t) == 1, "non-wasi data layout");
3438
_Static_assert(_Alignof(int16_t) == 2, "non-wasi data layout");
@@ -2751,4 +2755,6 @@ __wasi_errno_t __wasi_sock_shutdown(
27512755
}
27522756
#endif
27532757

2758+
#pragma pop_macro("_Static_assert")
2759+
27542760
#endif

system/lib/compiler-rt/stack_limits.S

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,32 @@
44
.globl emscripten_stack_get_base
55
.globl emscripten_stack_get_end
66

7-
.globaltype __stack_pointer, i32
7+
#ifdef __wasm64__
8+
#define PTR i64
9+
#define ALIGN 3
10+
#define PTRSTORE .int64
11+
#else
12+
#define PTR i32
13+
#define ALIGN 2
14+
#define PTRSTORE .int32
15+
#endif
16+
17+
.globaltype __stack_pointer, PTR
818

919
# TODO(sbc): It would be nice if these we initialized directly
10-
# using i32.const rather than using the `emscripten_stack_init`
11-
.globaltype __stack_end, i32
20+
# using PTR.const rather than using the `emscripten_stack_init`
21+
.globaltype __stack_end, PTR
1222
__stack_end:
13-
.globaltype __stack_base, i32
23+
.globaltype __stack_base, PTR
1424
__stack_base:
1525

1626
emscripten_stack_get_base:
17-
.functype emscripten_stack_get_base () -> (i32)
27+
.functype emscripten_stack_get_base () -> (PTR)
1828
global.get __stack_base
1929
end_function
2030

2131
emscripten_stack_get_end:
22-
.functype emscripten_stack_get_end () -> (i32)
32+
.functype emscripten_stack_get_end () -> (PTR)
2333
global.get __stack_end
2434
end_function
2535

@@ -33,41 +43,41 @@ emscripten_stack_init:
3343
#ifdef __PIC__
3444
global.get __heap_base@GOT
3545
#else
36-
i32.const __heap_base
46+
PTR.const __heap_base
3747
#endif
3848
global.set __stack_base
3949

4050
# The end of stack data is the limit of the stack growth
4151
#ifdef __PIC__
4252
global.get __data_end@GOT
4353
#else
44-
i32.const __data_end
54+
PTR.const __data_end
4555
#endif
4656
# Align up to 16 bytes
47-
i32.const 0xf
48-
i32.add
49-
i32.const -0x10
50-
i32.and
57+
PTR.const 0xf
58+
PTR.add
59+
PTR.const -0x10
60+
PTR.and
5161
global.set __stack_end
5262

5363
end_function
5464

5565
emscripten_stack_set_limits:
56-
.functype emscripten_stack_set_limits (i32, i32) -> ()
66+
.functype emscripten_stack_set_limits (PTR, PTR) -> ()
5767
local.get 0
5868
global.set __stack_base
5969
local.get 1
6070
global.set __stack_end
6171
end_function
6272

6373
emscripten_stack_get_free:
64-
.functype emscripten_stack_get_free () -> (i32)
74+
.functype emscripten_stack_get_free () -> (PTR)
6575
global.get __stack_pointer
6676
global.get __stack_end
67-
i32.sub
77+
PTR.sub
6878
end_function
6979

7080
# Add emscripten_stack_init to static ctors
7181
.section .init_array.1,"",@
72-
.p2align 2
73-
.int32 emscripten_stack_init
82+
.p2align ALIGN
83+
PTRSTORE emscripten_stack_init

system/lib/compiler-rt/stack_ops.s renamed to system/lib/compiler-rt/stack_ops.S

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,45 @@
33
.globl stackAlloc
44
.globl emscripten_stack_get_current
55

6-
.globaltype __stack_pointer, i32
6+
#ifdef __wasm64__
7+
#define PTR i64
8+
#define MASK 0xfffffffffffffff0
9+
#else
10+
#define PTR i32
11+
#define MASK 0xfffffff0
12+
#endif
13+
14+
.globaltype __stack_pointer, PTR
715

816
stackSave:
9-
.functype stackSave() -> (i32)
17+
.functype stackSave() -> (PTR)
1018
global.get __stack_pointer
1119
end_function
1220

1321
stackRestore:
14-
.functype stackRestore(i32) -> ()
22+
.functype stackRestore(PTR) -> ()
1523
local.get 0
1624
global.set __stack_pointer
1725
end_function
1826

1927
stackAlloc:
20-
.functype stackAlloc(i32) -> (i32)
21-
.local i32, i32
28+
.functype stackAlloc(PTR) -> (PTR)
29+
.local PTR, PTR
2230
global.get __stack_pointer
2331
# Get arg 0 -> number of bytes to allocate
2432
local.get 0
2533
# Stack grows down. Subtract arg0 from __stack_pointer
26-
i32.sub
34+
PTR.sub
2735
# Align result by anding with ~15
28-
i32.const 0xfffffff0
29-
i32.and
36+
PTR.const MASK
37+
PTR.and
3038
local.tee 1
3139
global.set __stack_pointer
3240
local.get 1
3341
end_function
3442

3543
emscripten_stack_get_current:
36-
.functype emscripten_stack_get_current () -> (i32)
44+
.functype emscripten_stack_get_current () -> (PTR)
3745
global.get __stack_pointer
3846
end_function
3947

system/lib/pthread/library_pthread_stub.c

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -298,41 +298,69 @@ int pthread_barrier_wait(pthread_barrier_t* mutex) { return 0; }
298298
/* magic value to track a validly constructed TLS slot */
299299
#define PTHREAD_TLS_MAGIC_ID 0x02468ACE
300300

301+
// pthread_key_t is 32-bit, so to be able to store pointers in there, we sadly
302+
// have to track an array of them.
303+
static size_t num_tls_entries = 0;
304+
static size_t max_tls_entries = 0;
305+
static void** tls_entries = NULL;
306+
301307
int pthread_key_create(pthread_key_t* key, void (*destructor)(void*)) {
302308
if (key == 0)
303309
return EINVAL;
304310
uintptr_t* tls = (uintptr_t*)malloc(sizeof(uintptr_t) * 2);
305311
tls[0] = 0;
306312
tls[1] = PTHREAD_TLS_MAGIC_ID;
307-
*key = (pthread_key_t)tls;
313+
if (!max_tls_entries) {
314+
// First time we're called, allocate entry table.
315+
max_tls_entries = 4;
316+
tls_entries = (void**)malloc(max_tls_entries, sizeof(void *));
317+
}
318+
// Find empty spot.
319+
size_t entry = 0;
320+
for (; entry < num_tls_entries; entry++) {
321+
if (!tls_entries[entry]) break;
322+
}
323+
if (entry == max_tls_entries) {
324+
// No empty spots, table full: double the table.
325+
max_tls_entries *= 2;
326+
tls_entries =
327+
(void**)realloc(tls_entries, num_tls_entries * sizeof(void *));
328+
}
329+
if (entry == num_tls_entries) {
330+
// No empty spots, but table not full.
331+
num_tls_entries++;
332+
}
333+
tls_entries[entry] = tls;
334+
*key = (pthread_key_t)entry;
308335
return 0;
309336
}
310337

311338
int pthread_key_delete(pthread_key_t key) {
312-
if (key == 0)
339+
if (key == 0 || !max_tls_entries)
313340
return EINVAL;
314-
uintptr_t* tls = (uintptr_t*)key;
315-
if (tls[1] != PTHREAD_TLS_MAGIC_ID)
341+
uintptr_t* tls = tls_entries[key];
342+
if (!tls || tls[1] != PTHREAD_TLS_MAGIC_ID)
316343
return EINVAL;
317344
tls[0] = tls[1] = 0;
345+
tls_entries[key] = NULL;
318346
free(tls);
319347
return 0;
320348
}
321349

322350
void* pthread_getspecific(pthread_key_t key) {
323-
if (key == 0)
351+
if (key == 0 || !max_tls_entries)
324352
return NULL;
325-
uintptr_t* tls = (uintptr_t*)key;
326-
if (tls[1] != PTHREAD_TLS_MAGIC_ID)
353+
uintptr_t* tls = tls_entries[key];
354+
if (!tls || tls[1] != PTHREAD_TLS_MAGIC_ID)
327355
return NULL;
328356
return (void*)tls[0];
329357
}
330358

331359
int pthread_setspecific(pthread_key_t key, const void* value) {
332-
if (key == 0)
360+
if (key == 0 || !max_tls_entries)
333361
return EINVAL;
334-
uintptr_t* tls = (uintptr_t*)key;
335-
if (tls[1] != PTHREAD_TLS_MAGIC_ID)
362+
uintptr_t* tls = tls_entries[key];
363+
if (!tls || tls[1] != PTHREAD_TLS_MAGIC_ID)
336364
return EINVAL;
337365
tls[0] = (uintptr_t)value;
338366
return 0;

tests/test_core.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8207,6 +8207,11 @@ def test_export_start(self):
82078207
self.set_setting('EXPORTED_FUNCTIONS', ['__start'])
82088208
self.do_run_in_out_file_test('tests', 'core', 'test_hello_world.c')
82098209

8210+
@unittest.skip("memory64 functionality only partially working")
8211+
def test_memory64_hello_world(self):
8212+
self.set_setting('MEMORY64', 2)
8213+
self.do_run_in_out_file_test('tests', 'core', 'test_hello_world.c')
8214+
82108215
# Tests the operation of API found in #include <emscripten/math.h>
82118216
def test_emscripten_math(self):
82128217
self.do_run_in_out_file_test('tests', 'core', 'test_emscripten_math.c')

tools/building.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,9 @@ def lld_flags_for_executable(external_symbol_list):
487487
if Settings.USE_PTHREADS:
488488
cmd.append('--shared-memory')
489489

490+
if Settings.MEMORY64:
491+
cmd.append('-mwasm64')
492+
490493
# wasm-ld can strip debug info for us. this strips both the Names
491494
# section and DWARF, so we can only use it when we don't need any of
492495
# those things.
@@ -1545,6 +1548,8 @@ def get_binaryen_feature_flags():
15451548
ret = ['--mvp-features']
15461549
if Settings.USE_PTHREADS:
15471550
ret += ['--enable-threads']
1551+
if Settings.MEMORY64:
1552+
ret += ['--enable-memory64']
15481553
ret += Settings.BINARYEN_FEATURES
15491554
return ret
15501555

tools/cache.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ def __init__(self, dirname, use_subdir=True):
3535
subdir += '-lto'
3636
if shared.Settings.RELOCATABLE:
3737
subdir += '-pic'
38+
if shared.Settings.MEMORY64:
39+
subdir += '-memory64'
3840
dirname = os.path.join(dirname, subdir)
3941

4042
self.dirname = dirname

tools/shared.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,10 @@ def apply_configuration():
409409

410410

411411
def get_llvm_target():
412-
return 'wasm32-unknown-emscripten'
412+
if Settings.MEMORY64:
413+
return 'wasm64-unknown-emscripten'
414+
else:
415+
return 'wasm32-unknown-emscripten'
413416

414417

415418
def emsdk_ldflags(user_args):

tools/system_libs.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ def get_cflags(force_object_files=False):
6161
flags += ['-flto=' + shared.Settings.LTO]
6262
if shared.Settings.RELOCATABLE:
6363
flags += ['-s', 'RELOCATABLE']
64+
if shared.Settings.MEMORY64:
65+
flags += ['-s', 'MEMORY64=' + str(shared.Settings.MEMORY64)]
6466
return flags
6567

6668

@@ -371,6 +373,8 @@ def build_objects(self):
371373
cmd = [shared.EMXX]
372374
if ext != '.s':
373375
cmd += cflags
376+
elif shared.Settings.MEMORY64:
377+
cmd += ['-s', 'MEMORY64=' + str(shared.Settings.MEMORY64)]
374378
commands.append(cmd + ['-c', src, '-o', o])
375379
objects.append(o)
376380
run_build_commands(commands)
@@ -644,7 +648,7 @@ class libcompiler_rt(MTLibrary):
644648
cflags = ['-O2', '-fno-builtin']
645649
src_dir = ['system', 'lib', 'compiler-rt', 'lib', 'builtins']
646650
src_files = glob_in_path(src_dir, '*.c')
647-
src_files.append(shared.path_from_root('system', 'lib', 'compiler-rt', 'stack_ops.s'))
651+
src_files.append(shared.path_from_root('system', 'lib', 'compiler-rt', 'stack_ops.S'))
648652
src_files.append(shared.path_from_root('system', 'lib', 'compiler-rt', 'stack_limits.S'))
649653
src_files.append(shared.path_from_root('system', 'lib', 'compiler-rt', 'emscripten_setjmp.c'))
650654
src_files.append(shared.path_from_root('system', 'lib', 'compiler-rt', 'emscripten_exception_builtins.c'))

0 commit comments

Comments
 (0)