Coverage Report

Created: 2026-10-17 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wasm3/source/m3_atomic.h
Line
Count
Source
1
//
2
//  m3_atomic.h
3
//
4
//  The primitives under the threads proposal's atomic accesses. Each takes the
5
//  address of a naturally aligned cell in linear memory - the interpreter has
6
//  checked that already - and works in host byte order; a big-endian host swaps
7
//  on the way in and out, as the ordinary loads and stores do.
8
//
9
//  The width of the cell is a value, its log2 from 0 to 3, and so is the operation of
10
//  a read-modify-write, so that one body serves every instruction of a kind. Values
11
//  travel as u64 and are cut to the width on the way into the cell.
12
//
13
//  Every read-modify-write returns the value the cell held before.
14
//
15
//  With one thread the accesses only have to be correct in sequence, so these are
16
//  plain reads and writes.
17
//
18
19
#ifndef m3_atomic_h
20
#define m3_atomic_h
21
22
#include "m3_core.h"
23
24
#if d_m3HasAtomics
25
26
d_m3BeginExternC
27
28
enum {
29
    c_atomicAdd,
30
    c_atomicSub,
31
    c_atomicAnd,
32
    c_atomicOr,
33
    c_atomicXor,
34
    c_atomicXchg
35
};
36
37
#  define d_m3AtomicTyped(T)                                            \
38
    static inline T m3_AtomicLoad_##T (const u8* i_cell)                \
39
956k
    {                                                                   \
40
956k
        T value;                                                        \
41
956k
        memcpy (& value, i_cell, sizeof (value));                       \
42
956k
        M3_BSWAP_##T (value);                                           \
43
956k
        return value;                                                   \
44
956k
    }                                                                   \
m3_compile.c:m3_AtomicLoad_u32
Line
Count
Source
39
156k
    {                                                                   \
40
156k
        T value;                                                        \
41
156k
        memcpy (& value, i_cell, sizeof (value));                       \
42
156k
        M3_BSWAP_##T (value);                                           \
43
156k
        return value;                                                   \
44
156k
    }                                                                   \
m3_compile.c:m3_AtomicLoad_u64
Line
Count
Source
39
230k
    {                                                                   \
40
230k
        T value;                                                        \
41
230k
        memcpy (& value, i_cell, sizeof (value));                       \
42
230k
        M3_BSWAP_##T (value);                                           \
43
230k
        return value;                                                   \
44
230k
    }                                                                   \
m3_compile.c:m3_AtomicLoad_u8
Line
Count
Source
39
416k
    {                                                                   \
40
416k
        T value;                                                        \
41
416k
        memcpy (& value, i_cell, sizeof (value));                       \
42
416k
        M3_BSWAP_##T (value);                                           \
43
416k
        return value;                                                   \
44
416k
    }                                                                   \
m3_compile.c:m3_AtomicLoad_u16
Line
Count
Source
39
153k
    {                                                                   \
40
153k
        T value;                                                        \
41
153k
        memcpy (& value, i_cell, sizeof (value));                       \
42
153k
        M3_BSWAP_##T (value);                                           \
43
153k
        return value;                                                   \
44
153k
    }                                                                   \
45
                                                                        \
46
    static inline void m3_AtomicStore_##T (u8* o_cell, T i_value)       \
47
697k
    {                                                                   \
48
697k
        M3_BSWAP_##T (i_value);                                         \
49
697k
        memcpy (o_cell, & i_value, sizeof (i_value));                   \
50
697k
    }
m3_compile.c:m3_AtomicStore_u8
Line
Count
Source
47
330k
    {                                                                   \
48
330k
        M3_BSWAP_##T (i_value);                                         \
49
330k
        memcpy (o_cell, & i_value, sizeof (i_value));                   \
50
330k
    }
m3_compile.c:m3_AtomicStore_u16
Line
Count
Source
47
115k
    {                                                                   \
48
115k
        M3_BSWAP_##T (i_value);                                         \
49
115k
        memcpy (o_cell, & i_value, sizeof (i_value));                   \
50
115k
    }
m3_compile.c:m3_AtomicStore_u32
Line
Count
Source
47
117k
    {                                                                   \
48
117k
        M3_BSWAP_##T (i_value);                                         \
49
117k
        memcpy (o_cell, & i_value, sizeof (i_value));                   \
50
117k
    }
m3_compile.c:m3_AtomicStore_u64
Line
Count
Source
47
134k
    {                                                                   \
48
134k
        M3_BSWAP_##T (i_value);                                         \
49
134k
        memcpy (o_cell, & i_value, sizeof (i_value));                   \
50
134k
    }
51
52
d_m3AtomicTyped(u8);
53
d_m3AtomicTyped(u16);
54
d_m3AtomicTyped(u32);
55
d_m3AtomicTyped(u64);
56
57
static inline
58
u64 m3_AtomicLoadW (const u8* i_cell, u32 i_log2Width)
59
954k
{
60
954k
    switch (i_log2Width) {
61
416k
    case 0: return m3_AtomicLoad_u8(i_cell);
62
153k
    case 1: return m3_AtomicLoad_u16(i_cell);
63
156k
    case 2: return m3_AtomicLoad_u32(i_cell);
64
228k
    default: return m3_AtomicLoad_u64(i_cell);
65
954k
    }
66
954k
}
67
68
static inline
69
void m3_AtomicStoreW (u8* o_cell, u32 i_log2Width, u64 i_value)
70
697k
{
71
697k
    switch (i_log2Width) {
72
330k
    case 0: m3_AtomicStore_u8(o_cell, (u8)i_value); break;
73
115k
    case 1: m3_AtomicStore_u16(o_cell, (u16)i_value); break;
74
117k
    case 2: m3_AtomicStore_u32(o_cell, (u32)i_value); break;
75
134k
    default: m3_AtomicStore_u64(o_cell, i_value); break;
76
697k
    }
77
697k
}
78
79
static inline
80
u64 m3_AtomicRmwW (u8* io_cell, u32 i_log2Width, u32 i_kind, u64 i_value)
81
394k
{
82
394k
    u64 old = m3_AtomicLoadW(io_cell, i_log2Width);
83
394k
    u64 updated;
84
85
394k
    switch (i_kind) {
86
125k
    case c_atomicAdd: updated = old + i_value; break;
87
83.0k
    case c_atomicSub: updated = old - i_value; break;
88
16.5k
    case c_atomicAnd: updated = old & i_value; break;
89
72.8k
    case c_atomicOr: updated = old | i_value; break;
90
39.3k
    case c_atomicXor: updated = old ^ i_value; break;
91
57.5k
    default: updated = i_value; break;
92
394k
    }
93
94
394k
    m3_AtomicStoreW(io_cell, i_log2Width, updated);
95
394k
    return old;
96
394k
}
97
98
static inline
99
u64 m3_AtomicCmpxchgW (u8* io_cell, u32 i_log2Width, u64 i_expected, u64 i_replacement)
100
297k
{
101
297k
    u64 old = m3_AtomicLoadW(io_cell, i_log2Width);
102
297k
    u64 mask = (i_log2Width == 3) ? ~(u64)0 : (((u64)1 << (8u << i_log2Width)) - 1);
103
104
297k
    if (old == (i_expected & mask)) {
105
206k
        m3_AtomicStoreW(io_cell, i_log2Width, i_replacement);
106
206k
    }
107
297k
    return old;
108
297k
}
109
110
d_m3EndExternC
111
112
#endif // d_m3HasAtomics
113
114
#endif // m3_atomic_h