Coverage Report

Created: 2026-08-13 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/moddable/xs/sources/xsAtomics.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016-2026  Moddable Tech, Inc.
3
 *
4
 *   This file is part of the Moddable SDK Runtime.
5
 * 
6
 *   The Moddable SDK Runtime is free software: you can redistribute it and/or modify
7
 *   it under the terms of the GNU Lesser General Public License as published by
8
 *   the Free Software Foundation, either version 3 of the License, or
9
 *   (at your option) any later version.
10
 * 
11
 *   The Moddable SDK Runtime is distributed in the hope that it will be useful,
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *   GNU Lesser General Public License for more details.
15
 * 
16
 *   You should have received a copy of the GNU Lesser General Public License
17
 *   along with the Moddable SDK Runtime.  If not, see <http://www.gnu.org/licenses/>.
18
 *
19
 */
20
21
#include "xsAll.h"
22
23
static txInteger fxCheckAtomicsIndex(txMachine* the, txInteger index, txInteger length);
24
static txSlot* fxCheckAtomicsTypedArray(txMachine* the, txBoolean onlyInt32);
25
static txSlot* fxCheckAtomicsArrayBuffer(txMachine* the, txSlot* slot, txBoolean onlyShared, txBoolean mutable);
26
static void* fxCheckAtomicsArrayBufferDetached(txMachine* the, txSlot* slot, txBoolean mutable);
27
static txSlot* fxCheckSharedArrayBuffer(txMachine* the, txSlot* slot, txString which);
28
static void fxPushAtomicsValue(txMachine* the, int i, txID id);
29
30
#define mxAtomicsHead0(TYPE,TO) \
31
3
  TYPE result = 0; \
32
3
  txBoolean lock = host->kind == XS_HOST_KIND; \
33
3
  void* data = (lock) ? host->value.host.data : fxCheckAtomicsArrayBufferDetached(the, host, XS_IMMUTABLE); \
34
3
  TYPE* address = (TYPE*)(((txByte*)data) + offset)
35
36
#define mxAtomicsHead1(TYPE,TO) \
37
23
  TYPE result = 0; \
38
23
  TYPE value = (TYPE)TO(the, slot); \
39
23
  txBoolean lock = host->kind == XS_HOST_KIND; \
40
23
  void* data = (lock) ? host->value.host.data : fxCheckAtomicsArrayBufferDetached(the, host, XS_MUTABLE); \
41
23
  TYPE* address = (TYPE*)(((txByte*)data) + offset)
42
43
#define mxAtomicsHead2(TYPE,TO) \
44
1
  TYPE result = (TYPE)TO(the, slot + 1); \
45
1
  TYPE value = (TYPE)TO(the, slot); \
46
1
  txBoolean lock = host->kind == XS_HOST_KIND; \
47
1
  void* data = (lock) ? host->value.host.data : fxCheckAtomicsArrayBufferDetached(the, host, XS_MUTABLE); \
48
1
  TYPE* address = (TYPE*)(((txByte*)data) + offset)
49
50
#ifdef mxUseGCCAtomics
51
1
  #define mxAtomicsCompareExchange() __atomic_compare_exchange(address, &result, &value, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
52
7
  #define mxAtomicsLoad() __atomic_load(address, &result, __ATOMIC_SEQ_CST)
53
2
  #define mxAtomicsAdd() result = __atomic_fetch_add(address, value, __ATOMIC_SEQ_CST)
54
1
  #define mxAtomicsAnd() result = __atomic_fetch_and(address, value, __ATOMIC_SEQ_CST)
55
1
  #define mxAtomicsExchange() __atomic_exchange(address, &value, &result, __ATOMIC_SEQ_CST)
56
1
  #define mxAtomicsOr() result = __atomic_fetch_or(address, value, __ATOMIC_SEQ_CST)
57
12
  #define mxAtomicsStore() __atomic_store(address, &value, __ATOMIC_SEQ_CST)
58
32.9k
  #define mxAtomicsSub() result = __atomic_fetch_sub(address, value, __ATOMIC_SEQ_CST)
59
1
  #define mxAtomicsXor() result = __atomic_fetch_xor(address, value, __ATOMIC_SEQ_CST)
60
#else
61
  #define mxAtomicsCompareExchange() if (lock) fxLockSharedChunk(data); if (*address == result) *address = value; else result = *address; if (lock) fxUnlockSharedChunk(data)
62
  #define mxAtomicsLoad() if (lock) fxLockSharedChunk(data); result = *address;  if (lock) fxUnlockSharedChunk(data)
63
  #define mxAtomicsAdd() if (lock) fxLockSharedChunk(data); result = *address; *address = result + value; if (lock) fxUnlockSharedChunk(data)
64
  #define mxAtomicsAnd() if (lock) fxLockSharedChunk(data); result = *address; *address = result & value; if (lock) fxUnlockSharedChunk(data)
65
  #define mxAtomicsExchange() if (lock) fxLockSharedChunk(data); result = *address; *address = value; if (lock) fxUnlockSharedChunk(data)
66
  #define mxAtomicsOr() if (lock) fxLockSharedChunk(data); result = *address; *address = result | value; if (lock) fxUnlockSharedChunk(data)
67
  #define mxAtomicsStore() if (lock) fxLockSharedChunk(data); *address = value; if (lock) fxUnlockSharedChunk(data)
68
  #define mxAtomicsSub() if (lock) fxLockSharedChunk(data); result = *address; *address = result - value; if (lock) fxUnlockSharedChunk(data)
69
  #define mxAtomicsXor() if (lock) fxLockSharedChunk(data); result = *address; *address = result ^ value; if (lock) fxUnlockSharedChunk(data)
70
#endif  
71
72
#define mxAtomicsTail() \
73
23
  slot->kind = XS_INTEGER_KIND; \
74
23
  slot->value.integer = result
75
76
#define mxAtomicsTailBigInt64() \
77
0
  fxFromBigInt64(the, slot, result)
78
79
#define mxAtomicsTailBigUint64() \
80
0
  fxFromBigUint64(the, slot, result)
81
  
82
#define mxAtomicsTailOverflow() \
83
0
  if (result <= 0x7FFFFFFF) { \
84
0
    slot->kind = XS_INTEGER_KIND; \
85
0
    slot->value.integer = result; \
86
0
  } \
87
0
  else { \
88
0
    slot->kind = XS_NUMBER_KIND; \
89
0
    slot->value.number = result; \
90
0
  }
91
  
92
#define mxAtomicsTailWait() \
93
4
  return (result != value) ? -1 : (timeout == 0) ? 0 : 1;
94
95
#define mxAtomicsDeclarations(onlyInt32, onlyShared, mutable) \
96
162
  txSlot* dispatch = fxCheckAtomicsTypedArray(the, onlyInt32); \
97
162
  txSlot* view = dispatch->next; \
98
162
  txSlot* buffer = view->next; \
99
162
  txSlot* host = fxCheckAtomicsArrayBuffer(the, buffer, onlyShared, mutable); \
100
162
  txU2 shift = dispatch->value.typedArray.dispatch->shift; \
101
162
  txInteger length = fxGetDataViewSize(the, view, buffer) >> shift; \
102
162
  txInteger index = fxCheckAtomicsIndex(the, 1, length); \
103
162
  txInteger offset = view->value.dataView.offset + (index << shift)
104
105
0
void fxInt8Add(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS1, fxToInteger); mxAtomicsAdd(); mxAtomicsTail(); }
106
0
void fxInt16Add(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS2, fxToInteger); mxAtomicsAdd(); mxAtomicsTail(); }
107
2
void fxInt32Add(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS4, fxToInteger); mxAtomicsAdd(); mxAtomicsTail(); }
108
0
void fxInt64Add(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS8, fxToBigInt64); mxAtomicsAdd(); mxAtomicsTailBigInt64(); }
109
0
void fxUint8Add(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU1, fxToUnsigned); mxAtomicsAdd(); mxAtomicsTail(); }
110
0
void fxUint16Add(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU2, fxToUnsigned); mxAtomicsAdd(); mxAtomicsTail(); }
111
0
void fxUint32Add(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU4, fxToUnsigned); mxAtomicsAdd(); mxAtomicsTailOverflow(); }
112
0
void fxUint64Add(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU8, fxToBigUint64); mxAtomicsAdd(); mxAtomicsTailBigUint64(); }
113
114
0
void fxInt8And(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS1, fxToInteger); mxAtomicsAnd(); mxAtomicsTail(); }
115
0
void fxInt16And(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS2, fxToInteger); mxAtomicsAnd(); mxAtomicsTail(); }
116
1
void fxInt32And(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS4, fxToInteger); mxAtomicsAnd(); mxAtomicsTail(); }
117
0
void fxInt64And(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS8, fxToBigInt64); mxAtomicsAnd(); mxAtomicsTailBigInt64(); }
118
0
void fxUint8And(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU1, fxToUnsigned); mxAtomicsAnd(); mxAtomicsTail(); }
119
0
void fxUint16And(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU2, fxToUnsigned); mxAtomicsAnd(); mxAtomicsTail(); }
120
0
void fxUint32And(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU4, fxToUnsigned); mxAtomicsAnd(); mxAtomicsTailOverflow(); }
121
0
void fxUint64And(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU8, fxToBigUint64); mxAtomicsAnd(); mxAtomicsTailBigUint64(); }
122
123
0
void fxInt8CompareExchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead2(txS1, fxToInteger); mxAtomicsCompareExchange(); mxAtomicsTail(); }
124
0
void fxInt16CompareExchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead2(txS2, fxToInteger); mxAtomicsCompareExchange(); mxAtomicsTail(); }
125
1
void fxInt32CompareExchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead2(txS4, fxToInteger); mxAtomicsCompareExchange(); mxAtomicsTail(); }
126
0
void fxInt64CompareExchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead2(txS8, fxToBigInt64); mxAtomicsCompareExchange(); mxAtomicsTailBigInt64(); }
127
0
void fxUint8CompareExchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead2(txU1, fxToUnsigned); mxAtomicsCompareExchange(); mxAtomicsTail(); }
128
0
void fxUint16CompareExchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead2(txU2, fxToUnsigned); mxAtomicsCompareExchange(); mxAtomicsTail(); }
129
0
void fxUint32CompareExchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead2(txU4, fxToUnsigned); mxAtomicsCompareExchange(); mxAtomicsTailOverflow(); }
130
0
void fxUint64CompareExchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead2(txU8, fxToBigUint64); mxAtomicsCompareExchange(); mxAtomicsTailBigUint64(); }
131
132
0
void fxInt8Exchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS1, fxToInteger); mxAtomicsExchange(); mxAtomicsTail(); }
133
0
void fxInt16Exchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS2, fxToInteger); mxAtomicsExchange(); mxAtomicsTail(); }
134
1
void fxInt32Exchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS4, fxToInteger); mxAtomicsExchange(); mxAtomicsTail(); }
135
0
void fxInt64Exchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS8, fxToBigInt64); mxAtomicsExchange(); mxAtomicsTailBigInt64(); }
136
0
void fxUint8Exchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU1, fxToUnsigned); mxAtomicsExchange(); mxAtomicsTail(); }
137
0
void fxUint16Exchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU2, fxToUnsigned); mxAtomicsExchange(); mxAtomicsTail(); }
138
0
void fxUint32Exchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU4, fxToUnsigned); mxAtomicsExchange(); mxAtomicsTailOverflow(); }
139
0
void fxUint64Exchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU8, fxToBigUint64); mxAtomicsExchange(); mxAtomicsTailBigUint64(); }
140
141
0
void fxInt8Load(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead0(txS1, fxToInteger); mxAtomicsLoad(); mxAtomicsTail(); }
142
0
void fxInt16Load(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead0(txS2, fxToInteger); mxAtomicsLoad(); mxAtomicsTail(); }
143
3
void fxInt32Load(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead0(txS4, fxToInteger); mxAtomicsLoad(); mxAtomicsTail(); }
144
0
void fxInt64Load(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead0(txS8, fxToBigInt64); mxAtomicsLoad(); mxAtomicsTailBigInt64(); }
145
0
void fxUint8Load(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead0(txU1, fxToUnsigned); mxAtomicsLoad(); mxAtomicsTail(); }
146
0
void fxUint16Load(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead0(txU2, fxToUnsigned); mxAtomicsLoad(); mxAtomicsTail(); }
147
0
void fxUint32Load(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead0(txU4, fxToUnsigned); mxAtomicsLoad(); mxAtomicsTailOverflow(); }
148
0
void fxUint64Load(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead0(txU8, fxToBigUint64); mxAtomicsLoad(); mxAtomicsTailBigUint64(); }
149
150
0
void fxInt8Or(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS1, fxToInteger); mxAtomicsOr(); mxAtomicsTail(); }
151
0
void fxInt16Or(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS2, fxToInteger); mxAtomicsOr(); mxAtomicsTail(); }
152
1
void fxInt32Or(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS4, fxToInteger); mxAtomicsOr(); mxAtomicsTail(); }
153
0
void fxInt64Or(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS8, fxToBigInt64); mxAtomicsOr(); mxAtomicsTailBigInt64(); }
154
0
void fxUint8Or(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU1, fxToUnsigned); mxAtomicsOr(); mxAtomicsTail(); }
155
0
void fxUint16Or(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU2, fxToUnsigned); mxAtomicsOr(); mxAtomicsTail(); }
156
0
void fxUint32Or(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU4, fxToUnsigned); mxAtomicsOr(); mxAtomicsTailOverflow(); }
157
0
void fxUint64Or(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU8, fxToBigUint64); mxAtomicsOr(); mxAtomicsTailBigUint64(); }
158
159
0
void fxInt8Store(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS1, fxToInteger); mxAtomicsStore(); mxAtomicsTail(); }
160
0
void fxInt16Store(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS2, fxToInteger); mxAtomicsStore(); mxAtomicsTail(); }
161
12
void fxInt32Store(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS4, fxToInteger); mxAtomicsStore(); mxAtomicsTail(); }
162
0
void fxInt64Store(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS8, fxToBigInt64); mxAtomicsStore(); mxAtomicsTailBigInt64(); }
163
0
void fxUint8Store(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU1, fxToUnsigned); mxAtomicsStore(); mxAtomicsTail(); }
164
0
void fxUint16Store(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU2, fxToUnsigned); mxAtomicsStore(); mxAtomicsTail(); }
165
0
void fxUint32Store(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU4, fxToUnsigned); mxAtomicsStore(); mxAtomicsTailOverflow(); }
166
0
void fxUint64Store(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU8, fxToBigUint64); mxAtomicsStore(); mxAtomicsTailBigUint64(); }
167
168
0
void fxInt8Sub(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS1, fxToInteger); mxAtomicsSub(); mxAtomicsTail(); }
169
0
void fxInt16Sub(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS2, fxToInteger); mxAtomicsSub(); mxAtomicsTail(); }
170
1
void fxInt32Sub(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS4, fxToInteger); mxAtomicsSub(); mxAtomicsTail(); }
171
0
void fxInt64Sub(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS8, fxToBigInt64); mxAtomicsSub(); mxAtomicsTailBigInt64(); }
172
0
void fxUint8Sub(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU1, fxToUnsigned); mxAtomicsSub(); mxAtomicsTail(); }
173
0
void fxUint16Sub(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU2, fxToUnsigned); mxAtomicsSub(); mxAtomicsTail(); }
174
0
void fxUint32Sub(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU4, fxToUnsigned); mxAtomicsSub(); mxAtomicsTailOverflow(); }
175
0
void fxUint64Sub(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU8, fxToBigUint64); mxAtomicsSub(); mxAtomicsTailBigUint64(); }
176
177
0
void fxInt8Xor(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS1, fxToInteger); mxAtomicsXor(); mxAtomicsTail(); }
178
0
void fxInt16Xor(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS2, fxToInteger); mxAtomicsXor(); mxAtomicsTail(); }
179
1
void fxInt32Xor(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS4, fxToInteger); mxAtomicsXor(); mxAtomicsTail(); }
180
0
void fxInt64Xor(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS8, fxToBigInt64); mxAtomicsXor(); mxAtomicsTailBigInt64(); }
181
0
void fxUint8Xor(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU1, fxToUnsigned); mxAtomicsXor(); mxAtomicsTail(); }
182
0
void fxUint16Xor(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU2, fxToUnsigned); mxAtomicsXor(); mxAtomicsTail(); }
183
0
void fxUint32Xor(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU4, fxToUnsigned); mxAtomicsXor(); mxAtomicsTailOverflow(); }
184
0
void fxUint64Xor(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU8, fxToBigUint64); mxAtomicsXor(); mxAtomicsTailBigUint64(); }
185
186
0
txInteger fxInt32Wait(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, txNumber timeout) { mxAtomicsHead1(txS4, fxToInteger); mxAtomicsLoad(); mxAtomicsTailWait(); }
187
4
txInteger fxInt64Wait(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, txNumber timeout) { mxAtomicsHead1(txS8, fxToBigInt64); mxAtomicsLoad(); mxAtomicsTailWait(); }
188
189
void fxBuildAtomics(txMachine* the)
190
24.8k
{
191
24.8k
  txSlot* slot;
192
  
193
24.8k
  mxPush(mxObjectPrototype);
194
24.8k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
195
24.8k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_SharedArrayBuffer_prototype_get_byteLength), C_NULL, mxID(_byteLength), XS_DONT_ENUM_FLAG);
196
24.8k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_SharedArrayBuffer_prototype_get_growable), C_NULL, mxID(_growable), XS_DONT_ENUM_FLAG);
197
24.8k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_SharedArrayBuffer_prototype_get_maxByteLength), C_NULL, mxID(_maxByteLength), XS_DONT_ENUM_FLAG);
198
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_SharedArrayBuffer_prototype_grow), 1, mxID(_grow), XS_DONT_ENUM_FLAG);
199
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_SharedArrayBuffer_prototype_slice), 2, mxID(_slice), XS_DONT_ENUM_FLAG);
200
24.8k
  slot = fxNextStringXProperty(the, slot, "SharedArrayBuffer", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
201
24.8k
  mxSharedArrayBufferPrototype = *the->stack;
202
24.8k
  slot = fxBuildHostConstructor(the, mxCallback(fx_SharedArrayBuffer), 1, mxID(_SharedArrayBuffer));
203
24.8k
  mxSharedArrayBufferConstructor = *the->stack;
204
24.8k
  slot = fxLastProperty(the, slot);
205
24.8k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_species_get), C_NULL, mxID(_Symbol_species), XS_DONT_ENUM_FLAG);
206
24.8k
  mxPop();
207
  
208
24.8k
  mxPush(mxObjectPrototype);
209
24.8k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
210
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_add), 3, mxID(_add), XS_DONT_ENUM_FLAG);
211
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_and), 3, mxID(_and), XS_DONT_ENUM_FLAG);
212
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_compareExchange), 4, mxID(_compareExchange), XS_DONT_ENUM_FLAG);
213
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_exchange), 3, mxID(_exchange), XS_DONT_ENUM_FLAG);
214
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_isLockFree), 1, mxID(_isLockFree), XS_DONT_ENUM_FLAG);
215
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_load), 2, mxID(_load), XS_DONT_ENUM_FLAG);
216
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_or), 3, mxID(_or), XS_DONT_ENUM_FLAG);
217
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_notify), 3, mxID(_notify), XS_DONT_ENUM_FLAG);
218
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_store), 3, mxID(_store), XS_DONT_ENUM_FLAG);
219
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_sub), 3, mxID(_sub), XS_DONT_ENUM_FLAG);
220
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_wait), 4, mxID(_wait), XS_DONT_ENUM_FLAG);
221
24.8k
#if mxECMAScript2024
222
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_waitAsync), 4, mxID(_waitAsync), XS_DONT_ENUM_FLAG);
223
24.8k
#endif
224
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_notify), 3, mxID(_wake), XS_DONT_ENUM_FLAG);
225
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_xor), 3, mxID(_xor), XS_DONT_ENUM_FLAG);
226
24.8k
  slot = fxNextStringXProperty(the, slot, "Atomics", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
227
24.8k
  mxPull(mxAtomicsObject);
228
24.8k
}
229
230
txSlot* fxCheckAtomicsArrayBuffer(txMachine* the, txSlot* slot, txBoolean onlyShared, txBoolean mutable)
231
88
{
232
88
  if ((!slot) || (!mxIsReference(slot)))
233
0
    mxTypeError("typedArray.buffer: not an object");
234
88
  slot = slot->value.reference->next;
235
88
  if (slot && (slot->kind == XS_HOST_KIND) && (slot->value.host.variant.destructor == fxReleaseSharedChunk))
236
74
    return slot;
237
14
  if (onlyShared)
238
7
    mxTypeError("typedArray.buffer: not a SharedArrayBuffer instance");
239
7
  if (slot && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_ARRAY_BUFFER_KIND)) {
240
7
    if (slot->value.arrayBuffer.address == C_NULL)
241
0
      mxTypeError("typedArray.buffer: detached");
242
7
    if (mutable && (slot->flag & XS_DONT_SET_FLAG))
243
0
      mxTypeError("typedArray.buffer: read-only");
244
7
    return slot;
245
7
  }
246
7
  mxTypeError("typedArray.buffer: not a SharedArrayBuffer instance, not an ArrayBuffer instance");
247
0
  return C_NULL;
248
7
}
249
250
void* fxCheckAtomicsArrayBufferDetached(txMachine* the, txSlot* slot, txBoolean mutable)
251
0
{
252
0
  if (slot->value.arrayBuffer.address == C_NULL)
253
0
    mxTypeError("typedArray.buffer: detached");
254
0
  if (mutable && (slot->flag & XS_DONT_SET_FLAG))
255
0
    mxTypeError("typedArray.buffer: read-only");
256
0
  return slot->value.arrayBuffer.address;
257
0
}
258
259
txInteger fxCheckAtomicsIndex(txMachine* the, txInteger i, txInteger length)
260
81
{
261
81
  txSlot *slot = (mxArgc > i) ? mxArgv(i) : C_NULL;
262
81
  if (slot && (XS_INTEGER_KIND == slot->kind)) {
263
61
    int index = slot->value.integer;
264
61
    if ((0 <= index) && (index < length))
265
46
      return index;
266
61
  }
267
268
35
  txNumber index = slot ? c_trunc(fxToNumber(the, slot)) : C_NAN; 
269
35
  if (c_isnan(index))
270
13
    index = 0;
271
35
  if (index < 0)
272
10
    mxRangeError("invalid index");
273
25
  else if (index >= length)
274
19
    mxRangeError("invalid index");
275
6
  return (txInteger)index;
276
35
}
277
278
txSlot* fxCheckAtomicsTypedArray(txMachine* the, txBoolean onlyInt32)
279
162
{
280
162
  txSlot* slot = (mxArgc > 0) ? mxArgv(0) : C_NULL;
281
162
  txID id;
282
162
  if ((!slot) || (!mxIsReference(slot)))
283
14
    mxTypeError("typedArray: not an object");
284
148
  slot = slot->value.reference->next;
285
148
  if ((!slot) || ((slot->kind != XS_TYPED_ARRAY_KIND)))
286
1
    mxTypeError("typedArray: not a TypedArray instance");
287
147
  id = slot->value.typedArray.dispatch->constructorID;
288
147
  if (onlyInt32) {
289
85
    if ((id != _Int32Array) && (id != _BigInt64Array))
290
26
      mxTypeError("typedArray: not an Int32Array instance");
291
85
  }
292
62
  else {
293
62
    if (id == _Float32Array)
294
19
      mxTypeError("typedArray: Float32Array instance");
295
43
    else if (id == _Float64Array)
296
0
      mxTypeError("typedArray: Float64Array instance");
297
43
    else if (id == _Uint8ClampedArray)
298
14
      mxTypeError("typedArray: Uint8ClampedArray instance");
299
29
  #if mxFloat16
300
29
    else if (id == _Float16Array)
301
0
      mxTypeError("typedArray: Float16Array instance");
302
62
  #endif
303
62
  }
304
88
  return slot;
305
147
}
306
307
txSlot* fxCheckSharedArrayBuffer(txMachine* the, txSlot* slot, txString which)
308
1.56k
{
309
1.56k
  if ((!slot) || (!mxIsReference(slot)))
310
60
    mxTypeError("%s: not an object", which);
311
1.50k
  slot = slot->value.reference->next;
312
1.50k
  if ((!slot) || (slot->kind != XS_HOST_KIND) || (slot->value.host.variant.destructor != fxReleaseSharedChunk))
313
60
    mxTypeError("%s: not a SharedArrayBuffer instance", which);
314
1.44k
  return slot;
315
1.50k
}
316
317
void fxPushAtomicsValue(txMachine* the, int i, txID id)
318
27
{
319
27
  txSlot* slot;
320
27
  if (mxArgc > i)
321
25
    mxPushSlot(mxArgv(i));
322
2
  else
323
2
    mxPushUndefined();
324
27
  slot = the->stack;
325
27
  if ((id == _BigInt64Array) || (id == _BigUint64Array))
326
6
    fxBigIntCoerce(the, slot);
327
21
  else if (XS_INTEGER_KIND != slot->kind) {
328
14
    txNumber value;
329
14
    fxNumberCoerce(the, slot);
330
14
    value = c_trunc(slot->value.number); 
331
14
    if (c_isnan(value) || (value == -0))
332
12
      value = 0;
333
14
    slot->value.number = value;
334
14
  }
335
27
}
336
337
338
void fx_SharedArrayBuffer(txMachine* the)
339
33.1k
{
340
33.1k
  txSlot* instance;
341
33.1k
  txS8 byteLength;
342
33.1k
  txS8 maxByteLength = -1;
343
33.1k
  txSlot* property;
344
33.1k
  if (!mxHasTarget)
345
3
    mxTypeError("call: SharedArrayBuffer");
346
33.1k
  byteLength = fxArgToSafeByteLength(the, 0, 0);
347
33.1k
  if ((mxArgc > 1) && mxIsReference(mxArgv(1))) {
348
1.74k
    mxPushSlot(mxArgv(1));
349
1.74k
    mxGetID(mxID(_maxByteLength));
350
1.74k
    mxPullSlot(mxArgv(1));
351
1.74k
    maxByteLength = fxArgToSafeByteLength(the, 1, -1);
352
1.74k
  }
353
33.1k
  if (maxByteLength >= 0) {
354
22
    if (byteLength > maxByteLength)
355
1
      mxRangeError("byteLength > maxByteLength");
356
22
  }
357
33.1k
  mxPushSlot(mxTarget);
358
33.1k
  fxGetPrototypeFromConstructor(the, &mxSharedArrayBufferPrototype);
359
33.1k
  instance = fxNewSlot(the);
360
33.1k
  instance->kind = XS_INSTANCE_KIND;
361
33.1k
  instance->value.instance.garbage = C_NULL;
362
33.1k
  instance->value.instance.prototype = the->stack->value.reference;
363
33.1k
  the->stack->value.reference = instance;
364
33.1k
  the->stack->kind = XS_REFERENCE_KIND;
365
33.1k
  if (byteLength > 0x7FFFFFFF)
366
118
    mxRangeError("byteLength too big");
367
32.9k
  if (maxByteLength > 0x7FFFFFFF)
368
3
    mxRangeError("maxByteLength too big");
369
32.9k
  property = instance->next = fxNewSlot(the);
370
32.9k
  property->flag = XS_INTERNAL_FLAG;
371
32.9k
  property->kind = XS_HOST_KIND;
372
32.9k
  property->value.host.data = fxCreateSharedChunk((txInteger)byteLength);
373
32.9k
  if (!property->value.host.data) {
374
0
    property->value.host.variant.destructor = NULL;
375
0
    mxRangeError("cannot allocate SharedArrayBuffer instance");
376
0
  }
377
32.9k
  property->value.host.variant.destructor = fxReleaseSharedChunk;
378
32.9k
  property = property->next = fxNewSlot(the);
379
32.9k
  property->flag = XS_INTERNAL_FLAG;
380
32.9k
  property->kind = XS_BUFFER_INFO_KIND;
381
32.9k
  property->value.bufferInfo.length = (txInteger)byteLength;
382
32.9k
  property->value.bufferInfo.maxLength = (txInteger)maxByteLength;
383
32.9k
  mxPullSlot(mxResult);
384
32.9k
}
385
386
void fx_SharedArrayBuffer_prototype_get_byteLength(txMachine* the)
387
154
{
388
154
  txSlot* host = fxCheckSharedArrayBuffer(the, mxThis, "this");
389
154
  txSlot* bufferInfo = host->next; 
390
154
  mxResult->kind = XS_INTEGER_KIND;
391
154
  mxResult->value.integer = bufferInfo->value.bufferInfo.length;
392
154
}
393
394
void fx_SharedArrayBuffer_prototype_get_growable(txMachine* the)
395
1.22k
{
396
1.22k
  txSlot* host = fxCheckSharedArrayBuffer(the, mxThis, "this");
397
1.22k
  txSlot* bufferInfo = host->next;
398
1.22k
  mxResult->kind = XS_BOOLEAN_KIND;
399
1.22k
  mxResult->value.boolean = (bufferInfo->value.bufferInfo.maxLength >= 0) ? 1 : 0;
400
1.22k
}
401
402
void fx_SharedArrayBuffer_prototype_get_maxByteLength(txMachine* the)
403
45
{
404
45
  txSlot* host = fxCheckSharedArrayBuffer(the, mxThis, "this");
405
45
  txSlot* bufferInfo = host->next; 
406
45
  mxResult->kind = XS_INTEGER_KIND;
407
45
  if (bufferInfo->value.bufferInfo.maxLength >= 0)
408
10
    mxResult->value.integer = bufferInfo->value.bufferInfo.maxLength;
409
35
  else
410
35
    mxResult->value.integer = bufferInfo->value.bufferInfo.length;
411
45
}
412
413
void fx_SharedArrayBuffer_prototype_grow(txMachine* the)
414
36
{
415
36
  txSlot* host = fxCheckSharedArrayBuffer(the, mxThis, "this");
416
36
  txSlot* bufferInfo = host->next; 
417
36
  txInteger maxByteLength, oldByteLength, newByteLength;
418
36
  maxByteLength = bufferInfo->value.bufferInfo.maxLength;
419
36
  if (maxByteLength < 0)
420
10
    mxTypeError("this: not resizable");
421
26
  oldByteLength = bufferInfo->value.bufferInfo.length;
422
26
  newByteLength = fxArgToByteLength(the, 0, 0);
423
26
  if (newByteLength < oldByteLength)
424
1
    mxRangeError("newLength < byteLength");
425
25
  if (newByteLength > maxByteLength)
426
1
    mxRangeError("newLength > maxByteLength");
427
25
  mxRangeError("cannot grow SharedArrayBuffer instance");
428
25
}
429
430
void fx_SharedArrayBuffer_prototype_slice(txMachine* the)
431
67
{
432
67
  txSlot* host = fxCheckSharedArrayBuffer(the, mxThis, "this");
433
67
  txSlot* bufferInfo = host->next; 
434
67
  txInteger length = bufferInfo->value.bufferInfo.length;
435
67
  txInteger start = fxArgToIndexInteger(the, 0, 0, length);
436
67
  txInteger stop = fxArgToIndexInteger(the, 1, length, length);
437
67
  txSlot* result;
438
67
  if (stop < start) 
439
21
    stop = start;
440
67
  length = stop - start;
441
67
  mxPushSlot(mxThis);
442
67
  mxGetID(mxID(_constructor));
443
67
  fxToSpeciesConstructor(the, &mxSharedArrayBufferConstructor);
444
67
  mxNew();
445
67
  mxPushInteger(length);
446
67
  mxRunCount(1);
447
67
  mxPullSlot(mxResult);
448
67
  result = fxCheckSharedArrayBuffer(the, mxResult, "result");
449
67
  if (result == host)
450
1
    mxTypeError("result: same SharedArrayBuffer instance");
451
66
  bufferInfo = result->next; 
452
66
  if (bufferInfo->value.bufferInfo.length < length)
453
1
    mxTypeError("result: smaller SharedArrayBuffer instance");
454
65
  c_memcpy(result->value.host.data, ((txByte*)host->value.host.data + start), stop - start);
455
65
}
456
457
void fx_Atomics_add(txMachine* the)
458
3
{
459
3
  mxAtomicsDeclarations(0, 0, 1);
460
3
  fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID);
461
3
  (*dispatch->value.typedArray.atomics->add)(the, host, offset, the->stack, 0);
462
3
  mxPullSlot(mxResult);
463
3
}
464
465
void fx_Atomics_and(txMachine* the)
466
1
{
467
1
  mxAtomicsDeclarations(0, 0, 1);
468
1
  fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID);
469
1
  (*dispatch->value.typedArray.atomics->and)(the, host, offset, the->stack, 0);
470
1
  mxPullSlot(mxResult);
471
1
}
472
473
void fx_Atomics_compareExchange(txMachine* the)
474
2
{
475
2
  mxAtomicsDeclarations(0, 0, 1);
476
2
  fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID);
477
2
  fxPushAtomicsValue(the, 3, dispatch->value.typedArray.dispatch->constructorID);
478
2
  (*dispatch->value.typedArray.atomics->compareExchange)(the, host, offset, the->stack, 0);
479
2
  mxPullSlot(mxResult);
480
2
  mxPop();
481
2
}
482
483
void fx_Atomics_exchange(txMachine* the)
484
2
{
485
2
  mxAtomicsDeclarations(0, 0, 1);
486
2
  fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID);
487
2
  (*dispatch->value.typedArray.atomics->exchange)(the, host, offset, the->stack, 0);
488
2
  mxPullSlot(mxResult);
489
2
}
490
491
void fx_Atomics_isLockFree(txMachine* the)
492
72
{
493
72
  txInteger size = (mxArgc > 0) ? fxToInteger(the, mxArgv(0)) : 0;
494
72
  mxResult->value.boolean = (size == 4) ? 1 : 0;
495
72
  mxResult->kind = XS_BOOLEAN_KIND;
496
72
}
497
498
void fx_Atomics_load(txMachine* the)
499
4
{
500
4
  mxAtomicsDeclarations(0, 0, 0);
501
4
  (*dispatch->value.typedArray.atomics->load)(the, host, offset, mxResult, 0);
502
4
}
503
504
void fx_Atomics_or(txMachine* the)
505
1
{
506
1
  mxAtomicsDeclarations(0, 0, 1);
507
1
  fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID);
508
1
  (*dispatch->value.typedArray.atomics->or)(the, host, offset, the->stack, 0);
509
1
  mxPullSlot(mxResult);
510
1
}
511
512
void fx_Atomics_notify(txMachine* the)
513
66
{
514
66
  mxAtomicsDeclarations(1, 0, 0);
515
66
  txInteger count = ((mxArgc > 2) && !mxIsUndefined(mxArgv(2))) ? fxToInteger(the, mxArgv(2)) : 20;
516
66
  if (count < 0)
517
2
    count = 0;
518
66
  if (host->kind == XS_ARRAY_BUFFER_KIND) {
519
5
    mxResult->value.integer = 0;
520
5
  }
521
61
  else {
522
61
    mxResult->value.integer = fxNotifySharedChunk(the, (txByte*)host->value.host.data + offset, count);
523
61
  }
524
66
  mxResult->kind = XS_INTEGER_KIND;
525
66
}
526
527
void fx_Atomics_store(txMachine* the)
528
48
{
529
48
  mxAtomicsDeclarations(0, 0, 1);
530
48
  fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID);
531
48
  *mxResult = *the->stack;
532
48
  (*dispatch->value.typedArray.atomics->store)(the, host, offset, the->stack, 0);
533
48
  mxPop();
534
48
}
535
536
void fx_Atomics_sub(txMachine* the)
537
4
{
538
4
  mxAtomicsDeclarations(0, 0, 1);
539
4
  fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID);
540
4
  (*dispatch->value.typedArray.atomics->sub)(the, host, offset, the->stack, 0);
541
4
  mxPullSlot(mxResult);
542
4
}
543
544
void fx_Atomics_wait(txMachine* the)
545
23
{
546
23
  mxAtomicsDeclarations(1, 1, 0);
547
23
  txNumber timeout;
548
23
  txInteger result;
549
23
  fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID);
550
23
  timeout = (mxArgc > 3) ? fxToNumber(the, mxArgv(3)) : C_NAN;
551
23
  if (c_isnan(timeout))
552
0
    timeout = C_INFINITY;
553
23
  else if (timeout < 0)
554
0
    timeout = 0;
555
23
  result = (*dispatch->value.typedArray.atomics->wait)(the, host, offset, the->stack, timeout);
556
23
  if (result < 0)
557
0
    mxPushStringX("not-equal");
558
23
  else {
559
23
    result = fxWaitSharedChunk(the, (txByte*)host->value.host.data + offset, timeout, C_NULL);
560
23
    if (result == 0)
561
0
      mxPushStringX("timed-out");
562
23
    else
563
23
      mxPushStringX("ok");
564
23
  }
565
23
  mxPullSlot(mxResult);
566
23
}
567
568
#if mxECMAScript2024
569
void fx_Atomics_waitAsync(txMachine* the)
570
7
{
571
7
  mxAtomicsDeclarations(1, 1, 0);
572
7
  txNumber timeout;
573
7
  txInteger result;
574
7
  txSlot* slot;
575
7
  fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID);
576
7
  timeout = (mxArgc > 3) ? fxToNumber(the, mxArgv(3)) : C_NAN;
577
7
  if (c_isnan(timeout))
578
0
    timeout = C_INFINITY;
579
7
  else if (timeout < 0)
580
1
    timeout = 0;
581
7
  result = (*dispatch->value.typedArray.atomics->wait)(the, host, offset, the->stack, timeout);
582
  
583
7
  mxPush(mxObjectPrototype);
584
7
  slot = fxLastProperty(the, fxNewObjectInstance(the));
585
7
  slot = fxNextBooleanProperty(the, slot, (result <= 0) ? 0 : 1, mxID(_async), XS_NO_FLAG);
586
7
  if (result < 0)
587
1
    fxNextStringXProperty(the, slot, "not-equal", mxID(_value), XS_NO_FLAG);
588
6
  else if (result == 0)
589
1
    fxNextStringXProperty(the, slot, "timed-out", mxID(_value), XS_NO_FLAG);
590
5
  else {
591
5
    txSlot* resolveFunction;
592
5
    txSlot* rejectFunction;
593
5
    mxTemporary(resolveFunction);
594
5
    mxTemporary(rejectFunction);
595
5
    mxPush(mxPromiseConstructor);
596
5
    fxNewPromiseCapability(the, resolveFunction, rejectFunction);
597
5
    fxNextSlotProperty(the, slot, the->stack, mxID(_value), XS_NO_FLAG);
598
5
    mxPop(); // promise
599
5
    fxWaitSharedChunk(the, (txByte*)host->value.host.data + offset, timeout, resolveFunction);
600
5
    mxPop(); // rejectFunction
601
5
    mxPop(); // resolveFunction
602
5
  }
603
7
  mxPullSlot(mxResult);
604
7
}
605
#endif
606
607
void fx_Atomics_xor(txMachine* the)
608
1
{
609
1
  mxAtomicsDeclarations(0, 0, 1);
610
1
  fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID);
611
1
  (*dispatch->value.typedArray.atomics->xor)(the, host, offset, the->stack, 0);
612
1
  mxPullSlot(mxResult);
613
1
}
614
615
#ifdef mxUseDefaultSharedChunks
616
617
#if defined(mxUsePOSIXThreads)
618
  #define mxThreads 1
619
  typedef pthread_cond_t txCondition;
620
  typedef pthread_mutex_t txMutex;
621
  typedef pthread_t txThread;
622
0
  #define mxCreateCondition(CONDITION) pthread_cond_init(CONDITION,NULL)
623
24.8k
  #define mxCreateMutex(MUTEX) pthread_mutex_init(MUTEX,NULL)
624
24.8k
  #define mxCurrentThread() pthread_self()
625
0
  #define mxDeleteCondition(CONDITION) pthread_cond_destroy(CONDITION)
626
24.8k
  #define mxDeleteMutex(MUTEX) pthread_mutex_destroy(MUTEX)
627
24.8k
  #define mxLockMutex(MUTEX) pthread_mutex_lock(MUTEX)
628
24.8k
  #define mxUnlockMutex(MUTEX) pthread_mutex_unlock(MUTEX)
629
0
  #define mxWakeCondition(CONDITION) pthread_cond_signal(CONDITION)
630
#elif defined(mxUseFreeRTOSTasks)
631
  #define mxThreads 1
632
633
  #include "FreeRTOS.h"
634
#if ESP32
635
  #include "freertos/queue.h"
636
  #include "freertos/semphr.h"
637
#else
638
  #include "queue.h"
639
  #include "semphr.h"
640
#endif
641
  typedef TaskHandle_t txCondition;
642
  typedef struct {
643
#if nrf52
644
    SemaphoreHandle_t sem;
645
#else
646
    QueueHandle_t handle;
647
    StaticSemaphore_t buffer;
648
#endif
649
  } txMutex;
650
  typedef TaskHandle_t txThread;
651
  #define mxCreateCondition(CONDITION) *(CONDITION) = xTaskGetCurrentTaskHandle()
652
#if nrf52
653
  #define mxCreateMutex(MUTEX) (MUTEX)->sem = xSemaphoreCreateMutex()
654
#else
655
  #define mxCreateMutex(MUTEX) (MUTEX)->handle = xSemaphoreCreateMutexStatic(&((MUTEX)->buffer))
656
#endif
657
  #define mxCurrentThread() xTaskGetCurrentTaskHandle()
658
  #define mxDeleteCondition(CONDITION) *(CONDITION) = NULL
659
#if nrf52
660
  #define mxDeleteMutex(MUTEX) vSemaphoreDelete((MUTEX)->sem)
661
  #define mxLockMutex(MUTEX) xSemaphoreTake((MUTEX)->sem, portMAX_DELAY)
662
  #define mxUnlockMutex(MUTEX) xSemaphoreGive((MUTEX)->sem)
663
#else
664
  #define mxDeleteMutex(MUTEX) vSemaphoreDelete((MUTEX)->handle)
665
  #define mxLockMutex(MUTEX) xSemaphoreTake((MUTEX)->handle, portMAX_DELAY)
666
  #define mxUnlockMutex(MUTEX) xSemaphoreGive((MUTEX)->handle)
667
#endif
668
  #define mxWakeCondition(CONDITION) xTaskNotifyGive(*(CONDITION));
669
#elif mxWindows
670
  #define mxThreads 1
671
  typedef CONDITION_VARIABLE txCondition;
672
  typedef CRITICAL_SECTION txMutex;
673
  typedef DWORD txThread;
674
  #define mxCreateCondition(CONDITION) InitializeConditionVariable(CONDITION)
675
  #define mxCreateMutex(MUTEX) InitializeCriticalSection(MUTEX)
676
  #define mxCurrentThread() GetCurrentThreadId()
677
  #define mxDeleteCondition(CONDITION) (void)(CONDITION)
678
  #define mxDeleteMutex(MUTEX) DeleteCriticalSection(MUTEX)
679
  #define mxLockMutex(MUTEX) EnterCriticalSection(MUTEX)
680
  #define mxUnlockMutex(MUTEX) LeaveCriticalSection(MUTEX)
681
  #define mxWakeCondition(CONDITION) WakeConditionVariable(CONDITION)
682
#else
683
  #define mxThreads 0
684
  typedef void* txThread;
685
  #define mxCurrentThread() C_NULL
686
#endif
687
688
typedef struct sxSharedChunk txSharedChunk;
689
typedef struct sxSharedCluster txSharedCluster;
690
typedef struct sxSharedWaiter txSharedWaiter;
691
692
typedef void (*txTimerCallback)(void* timer, void *refcon, txInteger refconSize);
693
extern void fxRescheduleTimer(void* timer, txNumber timeout, txNumber interval);
694
extern void* fxScheduleTimer(txNumber timeout, txNumber interval, txTimerCallback callback, void* refcon, txInteger refconSize);
695
extern void fxUnscheduleTimer(void* timer);
696
697
struct sxSharedChunk {
698
#if mxThreads && !defined(mxUseGCCAtomics)
699
  txMutex mutex;
700
#endif
701
  txSize size;
702
  txSize usage;
703
};
704
705
struct sxSharedCluster {
706
  txThread mainThread;
707
  txSize usage;
708
#if mxThreads
709
  txSharedWaiter* first; 
710
  txMutex waiterMutex; 
711
#endif
712
};
713
714
struct sxSharedWaiter {
715
  txSharedWaiter* next;
716
  txMachine* the;
717
  void* data;
718
  void* condition;
719
  void* timer;
720
  txSlot resolve;
721
  txBoolean ok;
722
};
723
724
txSharedCluster* gxSharedCluster = C_NULL;
725
726
void fxInitializeSharedCluster(txMachine* the)
727
24.8k
{
728
24.8k
  if (gxSharedCluster) {
729
0
    gxSharedCluster->usage++;
730
0
  }
731
24.8k
  else {
732
24.8k
    gxSharedCluster = c_calloc(sizeof(txSharedCluster), 1);
733
24.8k
    if (gxSharedCluster) {
734
24.8k
      gxSharedCluster->mainThread = mxCurrentThread();
735
24.8k
      gxSharedCluster->usage++;
736
24.8k
    #if mxThreads
737
24.8k
      mxCreateMutex(&gxSharedCluster->waiterMutex);
738
24.8k
    #endif
739
24.8k
    #ifdef mxInitializeSharedTimers
740
24.8k
      mxInitializeSharedTimers();
741
24.8k
    #endif
742
24.8k
    }
743
24.8k
  }
744
24.8k
}
745
746
void fxTerminateSharedCluster(txMachine* the)
747
24.8k
{
748
24.8k
  if (gxSharedCluster) {
749
24.8k
  #ifdef mxUnscheduleSharedTimer
750
24.8k
    if (the) {
751
24.8k
      txSharedWaiter** address;
752
24.8k
      txSharedWaiter* waiter;
753
24.8k
      mxLockMutex(&gxSharedCluster->waiterMutex);
754
24.8k
      address = &(gxSharedCluster->first);
755
24.8k
      while ((waiter = *address)) {
756
1
        if (waiter->the == the) {
757
1
          *address = waiter->next;
758
1
          if (waiter->timer)
759
1
            mxUnscheduleSharedTimer(waiter->timer);
760
1
          c_free(waiter);         
761
1
        }
762
0
        else
763
0
          address = &(waiter->next);
764
1
      }
765
24.8k
      mxUnlockMutex(&gxSharedCluster->waiterMutex);
766
24.8k
    }
767
24.8k
  #endif
768
24.8k
    gxSharedCluster->usage--;
769
24.8k
    if (gxSharedCluster->usage == 0) {
770
24.8k
    #ifdef mxTerminateSharedTimers
771
24.8k
      mxTerminateSharedTimers();
772
24.8k
    #endif
773
24.8k
    #if mxThreads
774
24.8k
      mxDeleteMutex(&gxSharedCluster->waiterMutex);
775
24.8k
    #endif
776
24.8k
      c_free(gxSharedCluster);
777
24.8k
      gxSharedCluster = C_NULL;
778
24.8k
    }
779
24.8k
  }
780
24.8k
}
781
782
void* fxCreateSharedChunk(txInteger size)
783
32.9k
{
784
32.9k
  txSharedChunk* chunk = c_malloc(sizeof(txSharedChunk) + size);
785
32.9k
  if (chunk) {
786
32.9k
    void* data = (((txByte*)chunk) + sizeof(txSharedChunk));
787
  #if mxThreads && !defined(mxUseGCCAtomics)
788
    mxCreateMutex(&(chunk->mutex));
789
  #endif
790
32.9k
    chunk->size = size;
791
32.9k
    chunk->usage = 1;
792
32.9k
    c_memset(data, 0, size);
793
32.9k
    return data;
794
32.9k
  }
795
0
  return C_NULL;
796
32.9k
}
797
798
void fxLockSharedChunk(void* data)
799
0
{
800
#if mxThreads && !defined(mxUseGCCAtomics)
801
  txSharedChunk* chunk = (txSharedChunk*)(((txByte*)data) - sizeof(txSharedChunk));
802
    mxLockMutex(&(chunk->mutex));
803
#endif
804
0
}
805
806
txInteger fxMeasureSharedChunk(void* data)
807
0
{
808
0
  txSharedChunk* chunk = (txSharedChunk*)(((txByte*)data) - sizeof(txSharedChunk));
809
0
  return chunk->size;
810
0
}
811
812
txInteger fxNotifySharedChunk(txMachine* the, void* data, txInteger count)
813
15
{
814
15
  txInteger result = 0;
815
15
  if (gxSharedCluster) {
816
15
  #if mxThreads
817
15
    txSharedWaiter* first = C_NULL;
818
15
    txSharedWaiter* last = C_NULL;
819
15
    txSharedWaiter** address;
820
15
    txSharedWaiter* waiter;
821
15
    mxLockMutex(&gxSharedCluster->waiterMutex);
822
15
    address = &(gxSharedCluster->first);
823
15
    while ((waiter = *address)) {
824
0
      if (waiter->data == data) {
825
0
        if (count == 0)
826
0
          break;
827
0
        count--;
828
0
        if (first)
829
0
          last->next = waiter;
830
0
        else
831
0
          first = waiter;
832
0
        last = waiter;
833
0
        *address = waiter->next;
834
0
        waiter->next = C_NULL;
835
0
      }
836
0
      else
837
0
        address = &(waiter->next);
838
0
    }
839
15
    waiter = first;
840
15
    while (waiter) {
841
0
      waiter->data = C_NULL;
842
0
      if (waiter->condition) {
843
0
        mxWakeCondition((txCondition*)waiter->condition);
844
0
      }
845
0
      else {
846
0
        waiter->ok = 1;
847
0
      #ifdef mxRescheduleSharedTimer
848
0
        mxRescheduleSharedTimer(waiter->timer, 0, 0);
849
      #else
850
        fxAbort(the, XS_DEAD_STRIP_EXIT);
851
      #endif
852
0
      }
853
0
      result++;
854
0
      waiter = waiter->next;
855
0
    }
856
15
    mxUnlockMutex(&gxSharedCluster->waiterMutex);
857
15
  #endif  
858
15
  }
859
15
  return result;
860
15
}
861
862
void* fxRetainSharedChunk(void* data)
863
0
{
864
0
  txSharedChunk* chunk = (txSharedChunk*)(((txByte*)data) - sizeof(txSharedChunk));
865
0
  txS4 result = 0;
866
0
  txS4 value = 1;
867
0
  txS4* address = &(chunk->usage);
868
#ifndef mxUseGCCAtomics
869
  txBoolean lock = 1;
870
#endif
871
0
  mxAtomicsAdd();
872
0
  if (result == 0)
873
0
    return C_NULL;
874
0
  return data;
875
0
}
876
877
void fxReleaseSharedChunk(void* data)
878
32.9k
{
879
32.9k
  txSharedChunk* chunk = (txSharedChunk*)(((txByte*)data) - sizeof(txSharedChunk));
880
32.9k
  txS4 result = 0;
881
32.9k
  txS4 value = 1;
882
32.9k
  txS4* address = &(chunk->usage);
883
#ifndef mxUseGCCAtomics
884
  txBoolean lock = 1;
885
#endif
886
32.9k
  mxAtomicsSub();
887
32.9k
  if (result == 1) {
888
32.9k
    c_free(chunk);
889
32.9k
  }
890
32.9k
}
891
892
void fxUnlockSharedChunk(void* data)
893
0
{
894
#if mxThreads && !defined(mxUseGCCAtomics)
895
  txSharedChunk* chunk = (txSharedChunk*)(((txByte*)data) - sizeof(txSharedChunk));
896
    mxUnlockMutex(&(chunk->mutex));
897
#endif
898
0
}
899
900
#if mxThreads
901
void fxWaitSharedChunkCallback(void* timer, void* refcon, txInteger refconSize)
902
1
{
903
1
  txSharedWaiter** address = (txSharedWaiter**)refcon;
904
1
  txSharedWaiter* waiter = *address;
905
1
  txSharedWaiter* link;
906
1
  txMachine* the;
907
1
  mxLockMutex(&gxSharedCluster->waiterMutex);
908
1
  address = &(gxSharedCluster->first);
909
2
  while ((link = *address)) {
910
1
    if (link == waiter)
911
1
      *address = link->next;
912
0
    else
913
0
      address = &(link->next);
914
1
  }
915
1
  mxUnlockMutex(&gxSharedCluster->waiterMutex);
916
1
  the = waiter->the;
917
1
  fxBeginHost(waiter->the);
918
1
  mxTry(the) {
919
1
    mxPushUndefined();
920
1
    mxPush(waiter->resolve);
921
1
    mxCall();
922
1
    if (waiter->ok)
923
0
      mxPushStringX("ok");
924
1
    else
925
1
      mxPushStringX("timed-out");
926
1
    mxRunCount(1);
927
1
    mxPop();
928
1
  }
929
1
  mxCatch(the) {
930
0
  }
931
1
  fxForget(the, &waiter->resolve);
932
1
  fxEndHost(the);
933
1
  c_free(waiter);
934
1
}
935
#endif
936
937
txInteger fxWaitSharedChunk(txMachine* the, void* data, txNumber timeout, txSlot* resolveFunction)
938
2
{
939
2
  txInteger result = 1;
940
2
  if (gxSharedCluster) {
941
2
  #if mxThreads
942
2
    txSharedWaiter* waiter;
943
2
    txSharedWaiter** address;
944
2
    txSharedWaiter* link;
945
2
    waiter = c_calloc(1, sizeof(txSharedWaiter));
946
2
    if (!waiter)
947
0
      fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT);
948
2
    waiter->the = the;
949
2
    waiter->data = data;
950
2
    mxLockMutex(&gxSharedCluster->waiterMutex);
951
2
    address = &(gxSharedCluster->first);
952
2
    while ((link = *address))
953
0
      address = &(link->next);
954
2
    *address = waiter;
955
    
956
2
    if (resolveFunction) {
957
2
      mxUnlockMutex(&gxSharedCluster->waiterMutex);
958
2
      waiter->resolve = *resolveFunction;
959
2
      fxRemember(the, &waiter->resolve);
960
2
    #ifdef mxScheduleSharedTimer
961
2
      waiter->timer = mxScheduleSharedTimer(timeout, 0, (txSharedTimerCallback)fxWaitSharedChunkCallback, &waiter, sizeof(txSharedWaiter*));
962
2
      if (!waiter->timer)
963
0
        fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT);
964
    #else
965
      fxAbort(the, XS_DEAD_STRIP_EXIT);
966
    #endif
967
2
    }
968
0
    else if (gxSharedCluster->mainThread != mxCurrentThread()) {
969
0
      txCondition condition;
970
0
      mxCreateCondition(&condition);
971
0
      waiter->condition = &condition;
972
0
      if (timeout == C_INFINITY) {
973
0
      #if defined(mxUsePOSIXThreads)
974
0
        while (waiter->data == data)
975
0
          pthread_cond_wait(&condition, &gxSharedCluster->waiterMutex);
976
      #elif defined(mxUseFreeRTOSTasks)
977
        mxUnlockMutex(&gxSharedCluster->waiterMutex);
978
        ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
979
        mxLockMutex(&gxSharedCluster->waiterMutex);
980
      #else
981
        while (waiter->data == data)
982
          SleepConditionVariableCS(&condition, &gxSharedCluster->waiterMutex, INFINITE);
983
      #endif
984
0
      }
985
0
      else {
986
0
      #if defined(mxUsePOSIXThreads)
987
0
        struct timespec ts;
988
0
        timeout += fxDateNow();
989
0
        ts.tv_sec = c_floor(timeout / 1000);
990
0
        ts.tv_nsec = c_fmod(timeout, 1000) * 1000000;
991
0
        while (waiter->data == data) {
992
0
          result = (pthread_cond_timedwait(&condition, &gxSharedCluster->waiterMutex, &ts) == ETIMEDOUT) ? 0 : 1;
993
0
          if (!result)
994
0
            break;
995
0
        }
996
      #elif defined(mxUseFreeRTOSTasks)
997
        mxUnlockMutex(&gxSharedCluster->waiterMutex);
998
        ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(timeout));
999
        mxLockMutex(&gxSharedCluster->waiterMutex);
1000
        result = (waiter->data == data) ? 0 : 1;
1001
      #else
1002
        timeout += fxDateNow();
1003
        while (waiter->data == data) {
1004
          result = (SleepConditionVariableCS(&condition, &gxSharedCluster->waiterMutex, (DWORD)(timeout - fxDateNow()))) ? 1 : 0;
1005
          if (!result)
1006
            break;
1007
        }
1008
      #endif
1009
0
      }
1010
0
      address = &(gxSharedCluster->first);
1011
0
      while ((link = *address)) {
1012
0
        if (link == waiter)
1013
0
          *address = link->next;
1014
0
        else
1015
0
          address = &(link->next);
1016
0
      }
1017
0
      mxUnlockMutex(&gxSharedCluster->waiterMutex);
1018
0
      c_free(waiter);
1019
0
      mxDeleteCondition(&condition);
1020
0
    }
1021
0
    else {
1022
0
      mxTypeError("main thread cannot wait");
1023
0
    }
1024
2
  #endif  
1025
2
  }
1026
0
  else {
1027
0
    mxTypeError("no shared cluster");
1028
0
  }
1029
2
  return result;
1030
2
}
1031
1032
#endif /* mxUseDefaultSharedChunks */
1033
1034