Skip to content

Commit bffaff3

Browse files
committed
WIP: wasm
1 parent 2e87ac3 commit bffaff3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+4246
-110
lines changed

src/core/atomic.d

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,11 @@ TailShared!T atomicOp(string op, T, V1)(ref shared T val, V1 mod) pure nothrow @
576576
if (__traits(compiles, mixin("*cast(T*)&val" ~ op ~ "mod")))
577577
in (atomicValueIsProperlyAligned(val))
578578
{
579+
version (WebAssembly) {
580+
T* get = cast(T*)&val;
581+
// TODO: WASM atomics
582+
mixin("return (*get)" ~ op ~ "mod;");
583+
} else {
579584
version (LDC)
580585
{
581586
import ldc.intrinsics;
@@ -655,6 +660,7 @@ in (atomicValueIsProperlyAligned(val))
655660
{
656661
static assert(false, "Operation not supported.");
657662
}
663+
}
658664
}
659665

660666

@@ -1114,6 +1120,7 @@ version (CoreUnittest)
11141120
{
11151121
debug: // tests CAS in-contract
11161122

1123+
version (WebAssembly) {} else
11171124
pure nothrow unittest
11181125
{
11191126
import core.exception : AssertError;
@@ -1179,6 +1186,8 @@ version (CoreUnittest)
11791186
assert(ptr is null);
11801187
}
11811188

1189+
// TODO: WebAssembly has no threads
1190+
version (WebAssembly) {} else
11821191
unittest
11831192
{
11841193
import core.thread;

src/core/demangle.d

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2355,6 +2355,7 @@ char[] mangleFunc(T:FT*, FT)(const(char)[] fqn, char[] dst = null) @safe pure no
23552355

23562356
private enum hasTypeBackRef = (int function(void**,void**)).mangleof[$-4 .. $] == "QdZi";
23572357

2358+
version (WebAssembly) {} else
23582359
@safe pure nothrow unittest
23592360
{
23602361
assert(mangleFunc!(int function(int))("a.b") == "_D1a1bFiZi");
@@ -2431,6 +2432,8 @@ else version (Darwin)
24312432
else
24322433
enum string cPrefix = "";
24332434

2435+
// TODO: can this be removed?
2436+
version (WebAssembly) {} else
24342437
@safe pure nothrow unittest
24352438
{
24362439
immutable string[2][] table =
@@ -2562,6 +2565,7 @@ else
25622565
else
25632566
alias staticIota = Seq!(staticIota!(x - 1), x - 1);
25642567
}
2568+
25652569
foreach ( i, name; table )
25662570
{
25672571
auto r = demangle( name[0] );
@@ -2585,6 +2589,7 @@ else
25852589
}
25862590
}
25872591

2592+
version (WebAssembly) {} else
25882593
unittest
25892594
{
25902595
// https://issues.dlang.org/show_bug.cgi?id=18300
@@ -2597,6 +2602,7 @@ unittest
25972602
}
25982603
}
25992604

2605+
version (WebAssembly) {} else
26002606
unittest
26012607
{
26022608
// https://issues.dlang.org/show_bug.cgi?id=18300
@@ -2669,7 +2675,12 @@ extern (C) private
26692675
import core.stdc.errno : errno;
26702676

26712677
const err = errno;
2672-
real val = strtold(nptr.ptr, null);
2678+
version (WebAssembly) {
2679+
real val;
2680+
strtold(nptr.ptr, null, &val);
2681+
} else {
2682+
real val = strtold(nptr.ptr, null);
2683+
}
26732684
snprintf(nptr.ptr, nptr.length, "%#Lg", val);
26742685
errno = err;
26752686
}

src/core/exception.d

Lines changed: 72 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -425,8 +425,18 @@ alias AssertHandler = void function(string file, size_t line, string msg) nothro
425425
*/
426426
extern (C) void onAssertError( string file = __FILE__, size_t line = __LINE__ ) nothrow
427427
{
428-
if ( _assertHandler is null )
429-
throw new AssertError( file, line );
428+
if ( _assertHandler is null ) {
429+
version (WebAssembly)
430+
{
431+
import core.stdc.stdio;
432+
printf("Failed assert @ %.*s:%d\n", cast(uint)file.length, file.ptr, line);
433+
import ldc.intrinsics : llvm_trap;
434+
llvm_trap(); // an unreachable is better than abort since it will translate to an unreachable in WASM and most WASM engines give stack traces then. Whereas with an abort it will terminate and you get no stack trace.
435+
} else
436+
{
437+
throw new AssertError( file, line );
438+
}
439+
}
430440
_assertHandler( file, line, null);
431441
}
432442

@@ -441,10 +451,21 @@ extern (C) void onAssertError( string file = __FILE__, size_t line = __LINE__ )
441451
* line = The line number on which this error occurred.
442452
* msg = An error message supplied by the user.
443453
*/
444-
extern (C) void onAssertErrorMsg( string file, size_t line, string msg ) nothrow
454+
extern (C) void onAssertErrorMsg( string file, size_t line, string msg ) nothrow @trusted
445455
{
446-
if ( _assertHandler is null )
447-
throw new AssertError( msg, file, line );
456+
if (_assertHandler is null) {
457+
version (WebAssembly)
458+
{
459+
import core.stdc.stdio;
460+
printf("Failed assert: %.*s @ %.*s:%d\n", cast(uint)msg.length, msg.ptr, cast(uint)file.length, file.ptr, line);
461+
import ldc.intrinsics : llvm_trap;
462+
llvm_trap(); // an unreachable is better than abort since it will translate to an unreachable in WASM and most WASM engines give stack traces then. Whereas with an abort it will terminate and you get no stack trace.
463+
} else
464+
{
465+
throw new AssertError( msg, file, line );
466+
}
467+
}
468+
448469
_assertHandler( file, line, msg );
449470
}
450471

@@ -479,11 +500,17 @@ extern (C) void onUnittestErrorMsg( string file, size_t line, string msg ) nothr
479500
* Throws:
480501
* $(LREF RangeError).
481502
*/
482-
extern (C) void onRangeError( string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
483-
{
484-
throw staticError!RangeError( file, line, null );
485-
}
486-
503+
version (WebAssembly) {
504+
extern (C) void onRangeError( string file = __FILE__, size_t line = __LINE__ ) @trusted nothrow
505+
{
506+
onAssertErrorMsg(file, line, "onRangeError");
507+
}
508+
} else {
509+
extern (C) void onRangeError( string file = __FILE__, size_t line = __LINE__ ) @trusted nothrow @nogc
510+
{
511+
throw staticError!RangeError( file, line, null );
512+
}
513+
}
487514

488515
/**
489516
* A callback for finalize errors in D. A $(LREF FinalizeError) will be thrown.
@@ -499,9 +526,14 @@ extern (C) void onRangeError( string file = __FILE__, size_t line = __LINE__ ) @
499526
*/
500527
extern (C) void onFinalizeError( TypeInfo info, Throwable e, string file = __FILE__, size_t line = __LINE__ ) @trusted nothrow
501528
{
502-
// This error is thrown during a garbage collection, so no allocation must occur while
503-
// generating this object. So we use a preallocated instance
504-
throw staticError!FinalizeError(info, e, file, line);
529+
version (WebAssembly) {
530+
onAssertErrorMsg( file, line, e.msg );
531+
} else
532+
{
533+
// This error is thrown during a garbage collection, so no allocation must occur while
534+
// generating this object. So we use a preallocated instance
535+
throw staticError!FinalizeError(info, e, file, line);
536+
}
505537
}
506538

507539
/**
@@ -513,15 +545,24 @@ extern (C) void onFinalizeError( TypeInfo info, Throwable e, string file = __FIL
513545
*/
514546
extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
515547
{
516-
// NOTE: Since an out of memory condition exists, no allocation must occur
517-
// while generating this object.
518-
throw staticError!OutOfMemoryError();
548+
version (WebAssembly) {
549+
assert(0, "Out of memory" );
550+
} else
551+
{
552+
// NOTE: Since an out of memory condition exists, no allocation must occur
553+
// while generating this object.
554+
throw staticError!OutOfMemoryError();
555+
}
519556
}
520557

521558
extern (C) void onOutOfMemoryErrorNoGC() @trusted nothrow @nogc
522559
{
523-
// suppress stacktrace until they are @nogc
524-
throw staticError!OutOfMemoryError(false);
560+
version (WebAssembly) {
561+
assert(0, "Out of memory" );
562+
} else {
563+
// suppress stacktrace until they are @nogc
564+
throw staticError!OutOfMemoryError(false);
565+
}
525566
}
526567

527568

@@ -534,9 +575,13 @@ extern (C) void onOutOfMemoryErrorNoGC() @trusted nothrow @nogc
534575
*/
535576
extern (C) void onInvalidMemoryOperationError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
536577
{
537-
// The same restriction applies as for onOutOfMemoryError. The GC is in an
538-
// undefined state, thus no allocation must occur while generating this object.
539-
throw staticError!InvalidMemoryOperationError();
578+
version (WebAssembly) {
579+
assert(0, "Invalid memory operation" );
580+
} else {
581+
// The same restriction applies as for onOutOfMemoryError. The GC is in an
582+
// undefined state, thus no allocation must occur while generating this object.
583+
throw staticError!InvalidMemoryOperationError();
584+
}
540585
}
541586

542587
/**
@@ -551,9 +596,13 @@ extern (C) void onInvalidMemoryOperationError(void* pretend_sideffect = null) @t
551596
* Throws:
552597
* $(LREF UnicodeException).
553598
*/
554-
extern (C) void onUnicodeError( string msg, size_t idx, string file = __FILE__, size_t line = __LINE__ ) @safe pure
599+
extern (C) void onUnicodeError( string msg, size_t idx, string file = __FILE__, size_t line = __LINE__ ) @safe
555600
{
556-
throw new UnicodeException( msg, idx, file, line );
601+
version (WebAssembly) {
602+
onAssertErrorMsg(file, line, msg); // TODO: what to do with idx? is it is already in msg?
603+
} else {
604+
throw new UnicodeException( msg, idx, file, line );
605+
}
557606
}
558607

559608
/***********************************

src/core/internal/abort.d

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ module core.internal.abort;
66
*/
77
void abort(scope string msg, scope string filename = __FILE__, size_t line = __LINE__) @nogc nothrow @safe
88
{
9+
version (WebAssembly) {
10+
import core.stdc.stdio;
11+
import core.sys.wasi.core;
12+
(() @trusted { fprintf(stderr, "Abort: %s @ %s:%d\n", &msg[0], &filename[0], line); })();
13+
proc_exit(1);
14+
}
15+
else {
916
import core.stdc.stdlib: c_abort = abort;
1017
// use available OS system calls to print the message to stderr
1118
version (Posix)
@@ -50,4 +57,5 @@ void abort(scope string msg, scope string filename = __FILE__, size_t line = __L
5057
// write an appropriate message, then abort the program
5158
writeStr("Aborting from ", filename, "(", line.unsignedToTempString(strbuff), ") ", msg);
5259
c_abort();
60+
}
5361
}

src/core/internal/array/construction.d

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ Tarr _d_arrayctor(Tarr : T[], T)(return scope Tarr to, scope Tarr from) @trusted
117117
assert(arr1 == arr2);
118118
}
119119

120+
version (WebAssembly) {} else // in WASI no catching of exceptions
120121
@safe nothrow unittest
121122
{
122123
// Test that throwing works
@@ -250,6 +251,7 @@ void _d_arraysetctor(Tarr : T[], T)(scope Tarr p, scope ref T value) @trusted
250251
assert(arr == [S(1234), S(1234), S(1234), S(1234)]);
251252
}
252253

254+
version (WebAssembly) {} else // in WASI no catching of exceptions
253255
@safe nothrow unittest
254256
{
255257
// Test that throwing works

src/core/internal/atomic.d

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,30 +22,54 @@ version (LDC)
2222
inout(T) atomicLoad(MemoryOrder order = MemoryOrder.seq, T)(inout(T)* src) pure nothrow @nogc @trusted
2323
{
2424
alias A = _AtomicType!T;
25+
version (WebAssembly) {
26+
return *src;
27+
} else {
2528
A result = llvm_atomic_load!A(cast(shared A*) src, _ordering!(order));
2629
return *cast(inout(T)*) &result;
30+
}
2731
}
2832

2933
void atomicStore(MemoryOrder order = MemoryOrder.seq, T)(T* dest, T value) pure nothrow @nogc @trusted
3034
{
3135
alias A = _AtomicType!T;
36+
version (WebAssembly) {
37+
*dest = value;
38+
} else
3239
llvm_atomic_store!A(*cast(A*) &value, cast(shared A*) dest, _ordering!(order));
3340
}
3441

3542
T atomicExchange(MemoryOrder order = MemoryOrder.seq, bool result = true, T)(T* dest, T value) pure nothrow @nogc @trusted
3643
{
3744
alias A = _AtomicType!T;
45+
version (WebAssembly) {
46+
auto old = *dest;
47+
*dest = value;
48+
return old;
49+
} else {
3850
A result = llvm_atomic_rmw_xchg!A(cast(shared A*) dest, *cast(A*) &value, _ordering!(order));
3951
return *cast(T*) &result;
52+
}
4053
}
4154

4255
bool atomicCompareExchange(bool weak = false, MemoryOrder succ = MemoryOrder.seq, MemoryOrder fail = MemoryOrder.seq, T)(T* dest, T* compare, T value) pure nothrow @nogc @trusted
4356
{
4457
alias A = _AtomicType!T;
58+
version (WebAssembly) {
59+
// TODO: WebAssembly has no atomic ops yet
60+
import core.stdc.string : memcmp;
61+
if (memcmp(cast(void*)dest, cast(void*)compare, T.sizeof) == 0) {
62+
*dest = value;
63+
return true;
64+
}
65+
*compare = *dest;
66+
return false;
67+
} else {
4568
auto result = llvm_atomic_cmp_xchg!A(cast(shared A*) dest, *cast(A*) compare, *cast(A*) &value,
4669
_ordering!(succ), _ordering!(fail), weak);
4770
*compare = *cast(T*) &result.previousValue;
4871
return result.exchanged;
72+
}
4973
}
5074
bool atomicCompareExchangeWeak(MemoryOrder succ = MemoryOrder.seq, MemoryOrder fail = MemoryOrder.seq, T)(T* dest, T* compare, T value) pure nothrow @nogc @trusted
5175
{
@@ -59,9 +83,19 @@ version (LDC)
5983
bool atomicCompareExchangeNoResult(bool weak = false, MemoryOrder succ = MemoryOrder.seq, MemoryOrder fail = MemoryOrder.seq, T)(T* dest, const T compare, T value) pure nothrow @nogc @trusted
6084
{
6185
alias A = _AtomicType!T;
86+
version (WebAssembly) {
87+
// TODO: WebAssembly has no atomic ops yet
88+
import core.stdc.string : memcmp;
89+
if (memcmp(cast(void*)dest, cast(void*)&compare, T.sizeof) == 0) {
90+
*dest = value;
91+
return true;
92+
}
93+
return false;
94+
} else {
6295
auto result = llvm_atomic_cmp_xchg!A(cast(shared A*) dest, *cast(A*) &compare, *cast(A*) &value,
6396
_ordering!(succ), _ordering!(fail), weak);
6497
return result.exchanged;
98+
}
6599
}
66100
bool atomicCompareExchangeStrongNoResult(MemoryOrder succ = MemoryOrder.seq, MemoryOrder fail = MemoryOrder.seq, T)(T* dest, const T compare, T value) pure nothrow @nogc @trusted
67101
{
@@ -70,6 +104,7 @@ version (LDC)
70104

71105
void atomicFence(MemoryOrder order = MemoryOrder.seq)() pure nothrow @nogc @trusted
72106
{
107+
version (WebAssembly) {} else
73108
llvm_memory_fence(_ordering!(order));
74109
}
75110

src/core/internal/container/array.d

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@ unittest
208208
assert(cnt == 0);
209209
}
210210

211+
// NOTE: fails in wasm because of exceptions
212+
version (WebAssembly) {} else
211213
unittest
212214
{
213215
import core.exception;

src/core/internal/container/hashtab.d

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,8 @@ unittest
306306
assert(cnt == 0);
307307
}
308308

309+
// NOTE: fails in wasm because of exceptions
310+
version (WebAssembly) {} else
309311
unittest
310312
{
311313
import core.exception;

src/core/internal/entrypoint.d

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,16 @@ template _d_cmain()
5252
}
5353
}
5454
}
55+
version (WebAssembly)
56+
{
57+
import ldc.attributes;
58+
import core.sys.wasi.core;
59+
void __wasm_call_ctors();
60+
pragma(mangle, "_start")
61+
@weak export void _start() {
62+
__wasm_call_ctors();
63+
proc_exit(main(0, null));
64+
}
65+
}
5566
}
5667
}

0 commit comments

Comments
 (0)