Coverage Report

Created: 2026-03-16 06:14

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);
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
0
  TYPE result = 0; \
32
0
  txBoolean lock = host->kind == XS_HOST_KIND; \
33
0
  void* data = (lock) ? host->value.host.data : fxCheckAtomicsArrayBufferDetached(the, host, XS_IMMUTABLE); \
34
0
  TYPE* address = (TYPE*)(((txByte*)data) + offset)
35
36
#define mxAtomicsHead1(TYPE,TO) \
37
0
  TYPE result = 0; \
38
0
  TYPE value = (TYPE)TO(the, slot); \
39
0
  txBoolean lock = host->kind == XS_HOST_KIND; \
40
0
  void* data = (lock) ? host->value.host.data : fxCheckAtomicsArrayBufferDetached(the, host, XS_MUTABLE); \
41
0
  TYPE* address = (TYPE*)(((txByte*)data) + offset)
42
43
#define mxAtomicsHead2(TYPE,TO) \
44
0
  TYPE result = (TYPE)TO(the, slot + 1); \
45
0
  TYPE value = (TYPE)TO(the, slot); \
46
0
  txBoolean lock = host->kind == XS_HOST_KIND; \
47
0
  void* data = (lock) ? host->value.host.data : fxCheckAtomicsArrayBufferDetached(the, host, XS_MUTABLE); \
48
0
  TYPE* address = (TYPE*)(((txByte*)data) + offset)
49
50
#ifdef mxUseGCCAtomics
51
0
  #define mxAtomicsCompareExchange() __atomic_compare_exchange(address, &result, &value, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
52
0
  #define mxAtomicsLoad() __atomic_load(address, &result, __ATOMIC_SEQ_CST)
53
0
  #define mxAtomicsAdd() result = __atomic_fetch_add(address, value, __ATOMIC_SEQ_CST)
54
0
  #define mxAtomicsAnd() result = __atomic_fetch_and(address, value, __ATOMIC_SEQ_CST)
55
0
  #define mxAtomicsExchange() __atomic_exchange(address, &value, &result, __ATOMIC_SEQ_CST)
56
0
  #define mxAtomicsOr() result = __atomic_fetch_or(address, value, __ATOMIC_SEQ_CST)
57
0
  #define mxAtomicsStore() __atomic_store(address, &value, __ATOMIC_SEQ_CST)
58
0
  #define mxAtomicsSub() result = __atomic_fetch_sub(address, value, __ATOMIC_SEQ_CST)
59
0
  #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
0
  slot->kind = XS_INTEGER_KIND; \
74
0
  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
0
  return (result != value) ? -1 : (timeout == 0) ? 0 : 1;
94
95
#define mxAtomicsDeclarations(onlyInt32, onlyShared) \
96
0
  txSlot* dispatch = fxCheckAtomicsTypedArray(the, onlyInt32); \
97
0
  txSlot* view = dispatch->next; \
98
0
  txSlot* buffer = view->next; \
99
0
  txSlot* host = fxCheckAtomicsArrayBuffer(the, buffer, onlyShared); \
100
0
  txU2 shift = dispatch->value.typedArray.dispatch->shift; \
101
0
  txInteger length = fxGetDataViewSize(the, view, buffer) >> shift; \
102
0
  txInteger index = fxCheckAtomicsIndex(the, 1, length); \
103
0
  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
0
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
0
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
0
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
0
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
0
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
0
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
0
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
0
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
0
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
0
txInteger fxInt64Wait(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, txNumber timeout) { mxAtomicsHead1(txS8, fxToBigInt64); mxAtomicsLoad(); mxAtomicsTailWait(); }
188
189
void fxBuildAtomics(txMachine* the)
190
6.33k
{
191
6.33k
  txSlot* slot;
192
  
193
6.33k
  mxPush(mxObjectPrototype);
194
6.33k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
195
6.33k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_SharedArrayBuffer_prototype_get_byteLength), C_NULL, mxID(_byteLength), XS_DONT_ENUM_FLAG);
196
6.33k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_SharedArrayBuffer_prototype_get_growable), C_NULL, mxID(_growable), XS_DONT_ENUM_FLAG);
197
6.33k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_SharedArrayBuffer_prototype_get_maxByteLength), C_NULL, mxID(_maxByteLength), XS_DONT_ENUM_FLAG);
198
6.33k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_SharedArrayBuffer_prototype_grow), 1, mxID(_grow), XS_DONT_ENUM_FLAG);
199
6.33k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_SharedArrayBuffer_prototype_slice), 2, mxID(_slice), XS_DONT_ENUM_FLAG);
200
6.33k
  slot = fxNextStringXProperty(the, slot, "SharedArrayBuffer", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
201
6.33k
  mxSharedArrayBufferPrototype = *the->stack;
202
6.33k
  slot = fxBuildHostConstructor(the, mxCallback(fx_SharedArrayBuffer), 1, mxID(_SharedArrayBuffer));
203
6.33k
  mxSharedArrayBufferConstructor = *the->stack;
204
6.33k
  slot = fxLastProperty(the, slot);
205
6.33k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_species_get), C_NULL, mxID(_Symbol_species), XS_DONT_ENUM_FLAG);
206
6.33k
  mxPop();
207
  
208
6.33k
  mxPush(mxObjectPrototype);
209
6.33k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
210
6.33k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_add), 3, mxID(_add), XS_DONT_ENUM_FLAG);
211
6.33k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_and), 3, mxID(_and), XS_DONT_ENUM_FLAG);
212
6.33k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_compareExchange), 4, mxID(_compareExchange), XS_DONT_ENUM_FLAG);
213
6.33k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_exchange), 3, mxID(_exchange), XS_DONT_ENUM_FLAG);
214
6.33k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_isLockFree), 1, mxID(_isLockFree), XS_DONT_ENUM_FLAG);
215
6.33k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_load), 2, mxID(_load), XS_DONT_ENUM_FLAG);
216
6.33k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_or), 3, mxID(_or), XS_DONT_ENUM_FLAG);
217
6.33k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_notify), 3, mxID(_notify), XS_DONT_ENUM_FLAG);
218
6.33k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_store), 3, mxID(_store), XS_DONT_ENUM_FLAG);
219
6.33k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_sub), 3, mxID(_sub), XS_DONT_ENUM_FLAG);
220
6.33k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_wait), 4, mxID(_wait), XS_DONT_ENUM_FLAG);
221
6.33k
#if mxECMAScript2024
222
6.33k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_waitAsync), 4, mxID(_waitAsync), XS_DONT_ENUM_FLAG);
223
6.33k
#endif
224
6.33k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_notify), 3, mxID(_wake), XS_DONT_ENUM_FLAG);
225
6.33k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_xor), 3, mxID(_xor), XS_DONT_ENUM_FLAG);
226
6.33k
  slot = fxNextStringXProperty(the, slot, "Atomics", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
227
6.33k
  mxPull(mxAtomicsObject);
228
6.33k
}
229
230
txSlot* fxCheckAtomicsArrayBuffer(txMachine* the, txSlot* slot, txBoolean onlyShared)
231
0
{
232
0
  if ((!slot) || (!mxIsReference(slot)))
233
0
    mxTypeError("typedArray.buffer: not an object");
234
0
  slot = slot->value.reference->next;
235
0
  if (slot && (slot->kind == XS_HOST_KIND) && (slot->value.host.variant.destructor == fxReleaseSharedChunk))
236
0
    return slot;
237
0
  if (onlyShared)
238
0
    mxTypeError("typedArray.buffer: not a SharedArrayBuffer instance");
239
0
  if (slot && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_ARRAY_BUFFER_KIND)) {
240
0
    if (slot->value.arrayBuffer.address == C_NULL)
241
0
      mxTypeError("typedArray.buffer: detached");
242
0
    return slot;
243
0
  }
244
0
  mxTypeError("typedArray.buffer: not a SharedArrayBuffer instance, not an ArrayBuffer instance");
245
0
  return C_NULL;
246
0
}
247
248
void* fxCheckAtomicsArrayBufferDetached(txMachine* the, txSlot* slot, txBoolean mutable)
249
0
{
250
0
  if (slot->value.arrayBuffer.address == C_NULL)
251
0
    mxTypeError("typedArray.buffer: detached");
252
0
  if (mutable && (slot->flag & XS_DONT_SET_FLAG))
253
0
    mxTypeError("typedArray.buffer: read-only");
254
0
  return slot->value.arrayBuffer.address;
255
0
}
256
257
txInteger fxCheckAtomicsIndex(txMachine* the, txInteger i, txInteger length)
258
0
{
259
0
  txSlot *slot = (mxArgc > i) ? mxArgv(i) : C_NULL;
260
0
  if (slot && (XS_INTEGER_KIND == slot->kind)) {
261
0
    int index = slot->value.integer;
262
0
    if ((0 <= index) && (index < length))
263
0
      return index;
264
0
  }
265
266
0
  txNumber index = slot ? c_trunc(fxToNumber(the, slot)) : C_NAN; 
267
0
  if (c_isnan(index))
268
0
    index = 0;
269
0
  if (index < 0)
270
0
    mxRangeError("invalid index");
271
0
  else if (index >= length)
272
0
    mxRangeError("invalid index");
273
0
  return (txInteger)index;
274
0
}
275
276
txSlot* fxCheckAtomicsTypedArray(txMachine* the, txBoolean onlyInt32)
277
0
{
278
0
  txSlot* slot = (mxArgc > 0) ? mxArgv(0) : C_NULL;
279
0
  txID id;
280
0
  if ((!slot) || (!mxIsReference(slot)))
281
0
    mxTypeError("typedArray: not an object");
282
0
  slot = slot->value.reference->next;
283
0
  if ((!slot) || ((slot->kind != XS_TYPED_ARRAY_KIND)))
284
0
    mxTypeError("typedArray: not a TypedArray instance");
285
0
  id = slot->value.typedArray.dispatch->constructorID;
286
0
  if (onlyInt32) {
287
0
    if ((id != _Int32Array) && (id != _BigInt64Array))
288
0
      mxTypeError("typedArray: not an Int32Array instance");
289
0
  }
290
0
  else {
291
0
    if (id == _Float32Array)
292
0
      mxTypeError("typedArray: Float32Array instance");
293
0
    else if (id == _Float64Array)
294
0
      mxTypeError("typedArray: Float64Array instance");
295
0
    else if (id == _Uint8ClampedArray)
296
0
      mxTypeError("typedArray: Uint8ClampedArray instance");
297
0
  #if mxFloat16
298
0
    else if (id == _Float16Array)
299
0
      mxTypeError("typedArray: Float16Array instance");
300
0
  #endif
301
0
  }
302
0
  return slot;
303
0
}
304
305
txSlot* fxCheckSharedArrayBuffer(txMachine* the, txSlot* slot, txString which)
306
0
{
307
0
  if ((!slot) || (!mxIsReference(slot)))
308
0
    mxTypeError("%s: not an object", which);
309
0
  slot = slot->value.reference->next;
310
0
  if ((!slot) || (slot->kind != XS_HOST_KIND) || (slot->value.host.variant.destructor != fxReleaseSharedChunk))
311
0
    mxTypeError("%s: not a SharedArrayBuffer instance", which);
312
0
  return slot;
313
0
}
314
315
void fxPushAtomicsValue(txMachine* the, int i, txID id)
316
0
{
317
0
  txSlot* slot;
318
0
  if (mxArgc > i)
319
0
    mxPushSlot(mxArgv(i));
320
0
  else
321
0
    mxPushUndefined();
322
0
  slot = the->stack;
323
0
  if ((id == _BigInt64Array) || (id == _BigUint64Array))
324
0
    fxBigIntCoerce(the, slot);
325
0
  else if (XS_INTEGER_KIND != slot->kind) {
326
0
    txNumber value;
327
0
    fxNumberCoerce(the, slot);
328
0
    value = c_trunc(slot->value.number); 
329
0
    if (c_isnan(value) || (value == -0))
330
0
      value = 0;
331
0
    slot->value.number = value;
332
0
  }
333
0
}
334
335
336
void fx_SharedArrayBuffer(txMachine* the)
337
0
{
338
0
  txSlot* instance;
339
0
  txS8 byteLength;
340
0
  txS8 maxByteLength = -1;
341
0
  txSlot* property;
342
0
  if (mxIsUndefined(mxTarget))
343
0
    mxTypeError("call: SharedArrayBuffer");
344
0
  byteLength = fxArgToSafeByteLength(the, 0, 0);
345
0
  if ((mxArgc > 1) && mxIsReference(mxArgv(1))) {
346
0
    mxPushSlot(mxArgv(1));
347
0
    mxGetID(mxID(_maxByteLength));
348
0
    mxPullSlot(mxArgv(1));
349
0
    maxByteLength = fxArgToSafeByteLength(the, 1, -1);
350
0
  }
351
0
  if (maxByteLength >= 0) {
352
0
    if (byteLength > maxByteLength)
353
0
      mxRangeError("byteLength > maxByteLength");
354
0
  }
355
0
  mxPushSlot(mxTarget);
356
0
  fxGetPrototypeFromConstructor(the, &mxSharedArrayBufferPrototype);
357
0
  instance = fxNewSlot(the);
358
0
  instance->kind = XS_INSTANCE_KIND;
359
0
  instance->value.instance.garbage = C_NULL;
360
0
  instance->value.instance.prototype = the->stack->value.reference;
361
0
  the->stack->value.reference = instance;
362
0
  the->stack->kind = XS_REFERENCE_KIND;
363
0
  if (byteLength > 0x7FFFFFFF)
364
0
    mxRangeError("byteLength too big");
365
0
  if (maxByteLength > 0x7FFFFFFF)
366
0
    mxRangeError("maxByteLength too big");
367
0
  property = instance->next = fxNewSlot(the);
368
0
  property->flag = XS_INTERNAL_FLAG;
369
0
  property->kind = XS_HOST_KIND;
370
0
  property->value.host.data = fxCreateSharedChunk((txInteger)byteLength);
371
0
  if (!property->value.host.data) {
372
0
    property->value.host.variant.destructor = NULL;
373
0
    mxRangeError("cannot allocate SharedArrayBuffer instance");
374
0
  }
375
0
  property->value.host.variant.destructor = fxReleaseSharedChunk;
376
0
  property = property->next = fxNewSlot(the);
377
0
  property->flag = XS_INTERNAL_FLAG;
378
0
  property->kind = XS_BUFFER_INFO_KIND;
379
0
  property->value.bufferInfo.length = (txInteger)byteLength;
380
0
  property->value.bufferInfo.maxLength = (txInteger)maxByteLength;
381
0
  mxPullSlot(mxResult);
382
0
}
383
384
void fx_SharedArrayBuffer_prototype_get_byteLength(txMachine* the)
385
0
{
386
0
  txSlot* host = fxCheckSharedArrayBuffer(the, mxThis, "this");
387
0
  txSlot* bufferInfo = host->next; 
388
0
  mxResult->kind = XS_INTEGER_KIND;
389
0
  mxResult->value.integer = bufferInfo->value.bufferInfo.length;
390
0
}
391
392
void fx_SharedArrayBuffer_prototype_get_growable(txMachine* the)
393
0
{
394
0
  txSlot* host = fxCheckSharedArrayBuffer(the, mxThis, "this");
395
0
  txSlot* bufferInfo = host->next;
396
0
  mxResult->kind = XS_BOOLEAN_KIND;
397
0
  mxResult->value.boolean = (bufferInfo->value.bufferInfo.maxLength >= 0) ? 1 : 0;
398
0
}
399
400
void fx_SharedArrayBuffer_prototype_get_maxByteLength(txMachine* the)
401
0
{
402
0
  txSlot* host = fxCheckSharedArrayBuffer(the, mxThis, "this");
403
0
  txSlot* bufferInfo = host->next; 
404
0
  mxResult->kind = XS_INTEGER_KIND;
405
0
  if (bufferInfo->value.bufferInfo.maxLength >= 0)
406
0
    mxResult->value.integer = bufferInfo->value.bufferInfo.maxLength;
407
0
  else
408
0
    mxResult->value.integer = bufferInfo->value.bufferInfo.length;
409
0
}
410
411
void fx_SharedArrayBuffer_prototype_grow(txMachine* the)
412
0
{
413
0
  txSlot* host = fxCheckSharedArrayBuffer(the, mxThis, "this");
414
0
  txSlot* bufferInfo = host->next; 
415
0
  txInteger maxByteLength, oldByteLength, newByteLength;
416
0
  maxByteLength = bufferInfo->value.bufferInfo.maxLength;
417
0
  if (maxByteLength < 0)
418
0
    mxTypeError("this: not resizable");
419
0
  oldByteLength = bufferInfo->value.bufferInfo.length;
420
0
  newByteLength = fxArgToByteLength(the, 0, 0);
421
0
  if (newByteLength < oldByteLength)
422
0
    mxRangeError("newLength < byteLength");
423
0
  if (newByteLength > maxByteLength)
424
0
    mxRangeError("newLength > maxByteLength");
425
0
  mxRangeError("cannot grow SharedArrayBuffer instance");
426
0
}
427
428
void fx_SharedArrayBuffer_prototype_slice(txMachine* the)
429
0
{
430
0
  txSlot* host = fxCheckSharedArrayBuffer(the, mxThis, "this");
431
0
  txSlot* bufferInfo = host->next; 
432
0
  txInteger length = bufferInfo->value.bufferInfo.length;
433
0
  txInteger start = fxArgToIndexInteger(the, 0, 0, length);
434
0
  txInteger stop = fxArgToIndexInteger(the, 1, length, length);
435
0
  txSlot* result;
436
0
  if (stop < start) 
437
0
    stop = start;
438
0
  length = stop - start;
439
0
  mxPushSlot(mxThis);
440
0
  mxGetID(mxID(_constructor));
441
0
  fxToSpeciesConstructor(the, &mxSharedArrayBufferConstructor);
442
0
  mxNew();
443
0
  mxPushInteger(length);
444
0
  mxRunCount(1);
445
0
  mxPullSlot(mxResult);
446
0
  result = fxCheckSharedArrayBuffer(the, mxResult, "result");
447
0
  if (result == host)
448
0
    mxTypeError("result: same SharedArrayBuffer instance");
449
0
  bufferInfo = result->next; 
450
0
  if (bufferInfo->value.bufferInfo.length < length)
451
0
    mxTypeError("result: smaller SharedArrayBuffer instance");
452
0
  c_memcpy(result->value.host.data, ((txByte*)host->value.host.data + start), stop - start);
453
0
}
454
455
void fx_Atomics_add(txMachine* the)
456
0
{
457
0
  mxAtomicsDeclarations(0, 0);
458
0
  fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID);
459
0
  (*dispatch->value.typedArray.atomics->add)(the, host, offset, the->stack, 0);
460
0
  mxPullSlot(mxResult);
461
0
}
462
463
void fx_Atomics_and(txMachine* the)
464
0
{
465
0
  mxAtomicsDeclarations(0, 0);
466
0
  fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID);
467
0
  (*dispatch->value.typedArray.atomics->and)(the, host, offset, the->stack, 0);
468
0
  mxPullSlot(mxResult);
469
0
}
470
471
void fx_Atomics_compareExchange(txMachine* the)
472
0
{
473
0
  mxAtomicsDeclarations(0, 0);
474
0
  fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID);
475
0
  fxPushAtomicsValue(the, 3, dispatch->value.typedArray.dispatch->constructorID);
476
0
  (*dispatch->value.typedArray.atomics->compareExchange)(the, host, offset, the->stack, 0);
477
0
  mxPullSlot(mxResult);
478
0
  mxPop();
479
0
}
480
481
void fx_Atomics_exchange(txMachine* the)
482
0
{
483
0
  mxAtomicsDeclarations(0, 0);
484
0
  fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID);
485
0
  (*dispatch->value.typedArray.atomics->exchange)(the, host, offset, the->stack, 0);
486
0
  mxPullSlot(mxResult);
487
0
}
488
489
void fx_Atomics_isLockFree(txMachine* the)
490
0
{
491
0
  txInteger size = (mxArgc > 0) ? fxToInteger(the, mxArgv(0)) : 0;
492
0
  mxResult->value.boolean = (size == 4) ? 1 : 0;
493
0
  mxResult->kind = XS_BOOLEAN_KIND;
494
0
}
495
496
void fx_Atomics_load(txMachine* the)
497
0
{
498
0
  mxAtomicsDeclarations(0, 0);
499
0
  (*dispatch->value.typedArray.atomics->load)(the, host, offset, mxResult, 0);
500
0
}
501
502
void fx_Atomics_or(txMachine* the)
503
0
{
504
0
  mxAtomicsDeclarations(0, 0);
505
0
  fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID);
506
0
  (*dispatch->value.typedArray.atomics->or)(the, host, offset, the->stack, 0);
507
0
  mxPullSlot(mxResult);
508
0
}
509
510
void fx_Atomics_notify(txMachine* the)
511
0
{
512
0
  mxAtomicsDeclarations(1, 0);
513
0
  txInteger count = ((mxArgc > 2) && !mxIsUndefined(mxArgv(2))) ? fxToInteger(the, mxArgv(2)) : 20;
514
0
  if (count < 0)
515
0
    count = 0;
516
0
  if (host->kind == XS_ARRAY_BUFFER_KIND) {
517
0
    mxResult->value.integer = 0;
518
0
  }
519
0
  else {
520
0
    mxResult->value.integer = fxNotifySharedChunk(the, (txByte*)host->value.host.data + offset, count);
521
0
  }
522
0
  mxResult->kind = XS_INTEGER_KIND;
523
0
}
524
525
void fx_Atomics_store(txMachine* the)
526
0
{
527
0
  mxAtomicsDeclarations(0, 0);
528
0
  fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID);
529
0
  *mxResult = *the->stack;
530
0
  (*dispatch->value.typedArray.atomics->store)(the, host, offset, the->stack, 0);
531
0
  mxPop();
532
0
}
533
534
void fx_Atomics_sub(txMachine* the)
535
0
{
536
0
  mxAtomicsDeclarations(0, 0);
537
0
  fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID);
538
0
  (*dispatch->value.typedArray.atomics->sub)(the, host, offset, the->stack, 0);
539
0
  mxPullSlot(mxResult);
540
0
}
541
542
void fx_Atomics_wait(txMachine* the)
543
0
{
544
0
  mxAtomicsDeclarations(1, 1);
545
0
  txNumber timeout;
546
0
  txInteger result;
547
0
  fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID);
548
0
  timeout = (mxArgc > 3) ? fxToNumber(the, mxArgv(3)) : C_NAN;
549
0
  if (c_isnan(timeout))
550
0
    timeout = C_INFINITY;
551
0
  else if (timeout < 0)
552
0
    timeout = 0;
553
0
  result = (*dispatch->value.typedArray.atomics->wait)(the, host, offset, the->stack, timeout);
554
0
  if (result < 0)
555
0
    mxPushStringX("not-equal");
556
0
  else {
557
0
    result = fxWaitSharedChunk(the, (txByte*)host->value.host.data + offset, timeout, C_NULL);
558
0
    if (result == 0)
559
0
      mxPushStringX("timed-out");
560
0
    else
561
0
      mxPushStringX("ok");
562
0
  }
563
0
  mxPullSlot(mxResult);
564
0
}
565
566
#if mxECMAScript2024
567
void fx_Atomics_waitAsync(txMachine* the)
568
0
{
569
0
  mxAtomicsDeclarations(1, 1);
570
0
  txNumber timeout;
571
0
  txInteger result;
572
0
  txSlot* slot;
573
0
  fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID);
574
0
  timeout = (mxArgc > 3) ? fxToNumber(the, mxArgv(3)) : C_NAN;
575
0
  if (c_isnan(timeout))
576
0
    timeout = C_INFINITY;
577
0
  else if (timeout < 0)
578
0
    timeout = 0;
579
0
  result = (*dispatch->value.typedArray.atomics->wait)(the, host, offset, the->stack, timeout);
580
  
581
0
  mxPush(mxObjectPrototype);
582
0
  slot = fxLastProperty(the, fxNewObjectInstance(the));
583
0
  slot = fxNextBooleanProperty(the, slot, (result <= 0) ? 0 : 1, mxID(_async), XS_NO_FLAG);
584
0
  if (result < 0)
585
0
    fxNextStringXProperty(the, slot, "not-equal", mxID(_value), XS_NO_FLAG);
586
0
  else if (result == 0)
587
0
    fxNextStringXProperty(the, slot, "timed-out", mxID(_value), XS_NO_FLAG);
588
0
  else {
589
0
    txSlot* resolveFunction;
590
0
    txSlot* rejectFunction;
591
0
    mxTemporary(resolveFunction);
592
0
    mxTemporary(rejectFunction);
593
0
    mxPush(mxPromiseConstructor);
594
0
    fxNewPromiseCapability(the, resolveFunction, rejectFunction);
595
0
    fxNextSlotProperty(the, slot, the->stack, mxID(_value), XS_NO_FLAG);
596
0
    mxPop(); // promise
597
0
    fxWaitSharedChunk(the, (txByte*)host->value.host.data + offset, timeout, resolveFunction);
598
0
    mxPop(); // rejectFunction
599
0
    mxPop(); // resolveFunction
600
0
  }
601
0
  mxPullSlot(mxResult);
602
0
}
603
#endif
604
605
void fx_Atomics_xor(txMachine* the)
606
0
{
607
0
  mxAtomicsDeclarations(0, 0);
608
0
  fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID);
609
0
  (*dispatch->value.typedArray.atomics->xor)(the, host, offset, the->stack, 0);
610
0
  mxPullSlot(mxResult);
611
0
}
612
613
#ifdef mxUseDefaultSharedChunks
614
615
#if defined(mxUsePOSIXThreads)
616
  #define mxThreads 1
617
  typedef pthread_cond_t txCondition;
618
  typedef pthread_mutex_t txMutex;
619
  typedef pthread_t txThread;
620
0
  #define mxCreateCondition(CONDITION) pthread_cond_init(CONDITION,NULL)
621
6.33k
  #define mxCreateMutex(MUTEX) pthread_mutex_init(MUTEX,NULL)
622
6.33k
  #define mxCurrentThread() pthread_self()
623
0
  #define mxDeleteCondition(CONDITION) pthread_cond_destroy(CONDITION)
624
6.33k
  #define mxDeleteMutex(MUTEX) pthread_mutex_destroy(MUTEX)
625
6.33k
  #define mxLockMutex(MUTEX) pthread_mutex_lock(MUTEX)
626
6.33k
  #define mxUnlockMutex(MUTEX) pthread_mutex_unlock(MUTEX)
627
0
  #define mxWakeCondition(CONDITION) pthread_cond_signal(CONDITION)
628
#elif defined(mxUseFreeRTOSTasks)
629
  #define mxThreads 1
630
631
  #include "FreeRTOS.h"
632
#if ESP32
633
  #include "freertos/queue.h"
634
  #include "freertos/semphr.h"
635
#else
636
  #include "queue.h"
637
  #include "semphr.h"
638
#endif
639
  typedef TaskHandle_t txCondition;
640
  typedef struct {
641
#if nrf52
642
    SemaphoreHandle_t sem;
643
#else
644
    QueueHandle_t handle;
645
    StaticSemaphore_t buffer;
646
#endif
647
  } txMutex;
648
  typedef TaskHandle_t txThread;
649
  #define mxCreateCondition(CONDITION) *(CONDITION) = xTaskGetCurrentTaskHandle()
650
#if nrf52
651
  #define mxCreateMutex(MUTEX) (MUTEX)->sem = xSemaphoreCreateMutex()
652
#else
653
  #define mxCreateMutex(MUTEX) (MUTEX)->handle = xSemaphoreCreateMutexStatic(&((MUTEX)->buffer))
654
#endif
655
  #define mxCurrentThread() xTaskGetCurrentTaskHandle()
656
  #define mxDeleteCondition(CONDITION) *(CONDITION) = NULL
657
#if nrf52
658
  #define mxDeleteMutex(MUTEX) vSemaphoreDelete((MUTEX)->sem)
659
  #define mxLockMutex(MUTEX) xSemaphoreTake((MUTEX)->sem, portMAX_DELAY)
660
  #define mxUnlockMutex(MUTEX) xSemaphoreGive((MUTEX)->sem)
661
#else
662
  #define mxDeleteMutex(MUTEX) vSemaphoreDelete((MUTEX)->handle)
663
  #define mxLockMutex(MUTEX) xSemaphoreTake((MUTEX)->handle, portMAX_DELAY)
664
  #define mxUnlockMutex(MUTEX) xSemaphoreGive((MUTEX)->handle)
665
#endif
666
  #define mxWakeCondition(CONDITION) xTaskNotifyGive(*(CONDITION));
667
#elif mxWindows
668
  #define mxThreads 1
669
  typedef CONDITION_VARIABLE txCondition;
670
  typedef CRITICAL_SECTION txMutex;
671
  typedef DWORD txThread;
672
  #define mxCreateCondition(CONDITION) InitializeConditionVariable(CONDITION)
673
  #define mxCreateMutex(MUTEX) InitializeCriticalSection(MUTEX)
674
  #define mxCurrentThread() GetCurrentThreadId()
675
  #define mxDeleteCondition(CONDITION) (void)(CONDITION)
676
  #define mxDeleteMutex(MUTEX) DeleteCriticalSection(MUTEX)
677
  #define mxLockMutex(MUTEX) EnterCriticalSection(MUTEX)
678
  #define mxUnlockMutex(MUTEX) LeaveCriticalSection(MUTEX)
679
  #define mxWakeCondition(CONDITION) WakeConditionVariable(CONDITION)
680
#else
681
  #define mxThreads 0
682
  typedef void* txThread;
683
  #define mxCurrentThread() C_NULL
684
#endif
685
686
typedef struct sxSharedChunk txSharedChunk;
687
typedef struct sxSharedCluster txSharedCluster;
688
typedef struct sxSharedWaiter txSharedWaiter;
689
690
typedef void (*txTimerCallback)(void* timer, void *refcon, txInteger refconSize);
691
extern void fxRescheduleTimer(void* timer, txNumber timeout, txNumber interval);
692
extern void* fxScheduleTimer(txNumber timeout, txNumber interval, txTimerCallback callback, void* refcon, txInteger refconSize);
693
extern void fxUnscheduleTimer(void* timer);
694
695
struct sxSharedChunk {
696
#if mxThreads && !defined(mxUseGCCAtomics)
697
  txMutex mutex;
698
#endif
699
  txSize size;
700
  txSize usage;
701
};
702
703
struct sxSharedCluster {
704
  txThread mainThread;
705
  txSize usage;
706
#if mxThreads
707
  txSharedWaiter* first; 
708
  txMutex waiterMutex; 
709
#endif
710
};
711
712
struct sxSharedWaiter {
713
  txSharedWaiter* next;
714
  txMachine* the;
715
  void* data;
716
  void* condition;
717
  void* timer;
718
  txSlot resolve;
719
  txBoolean ok;
720
};
721
722
txSharedCluster* gxSharedCluster = C_NULL;
723
724
void fxInitializeSharedCluster(txMachine* the)
725
6.33k
{
726
6.33k
  if (gxSharedCluster) {
727
0
    gxSharedCluster->usage++;
728
0
  }
729
6.33k
  else {
730
6.33k
    gxSharedCluster = c_calloc(sizeof(txSharedCluster), 1);
731
6.33k
    if (gxSharedCluster) {
732
6.33k
      gxSharedCluster->mainThread = mxCurrentThread();
733
6.33k
      gxSharedCluster->usage++;
734
6.33k
    #if mxThreads
735
6.33k
      mxCreateMutex(&gxSharedCluster->waiterMutex);
736
6.33k
    #endif
737
6.33k
    #ifdef mxInitializeSharedTimers
738
6.33k
      mxInitializeSharedTimers();
739
6.33k
    #endif
740
6.33k
    }
741
6.33k
  }
742
6.33k
}
743
744
void fxTerminateSharedCluster(txMachine* the)
745
6.33k
{
746
6.33k
  if (gxSharedCluster) {
747
6.33k
  #ifdef mxUnscheduleSharedTimer
748
6.33k
    if (the) {
749
6.33k
      txSharedWaiter** address;
750
6.33k
      txSharedWaiter* waiter;
751
6.33k
      mxLockMutex(&gxSharedCluster->waiterMutex);
752
6.33k
      address = &(gxSharedCluster->first);
753
6.33k
      while ((waiter = *address)) {
754
0
        if (waiter->the == the) {
755
0
          *address = waiter->next;
756
0
          if (waiter->timer)
757
0
            mxUnscheduleSharedTimer(waiter->timer);
758
0
          c_free(waiter);         
759
0
        }
760
0
        else
761
0
          address = &(waiter->next);
762
0
      }
763
6.33k
      mxUnlockMutex(&gxSharedCluster->waiterMutex);
764
6.33k
    }
765
6.33k
  #endif
766
6.33k
    gxSharedCluster->usage--;
767
6.33k
    if (gxSharedCluster->usage == 0) {
768
6.33k
    #ifdef mxTerminateSharedTimers
769
6.33k
      mxTerminateSharedTimers();
770
6.33k
    #endif
771
6.33k
    #if mxThreads
772
6.33k
      mxDeleteMutex(&gxSharedCluster->waiterMutex);
773
6.33k
    #endif
774
6.33k
      c_free(gxSharedCluster);
775
6.33k
      gxSharedCluster = C_NULL;
776
6.33k
    }
777
6.33k
  }
778
6.33k
}
779
780
void* fxCreateSharedChunk(txInteger size)
781
0
{
782
0
  txSharedChunk* chunk = c_malloc(sizeof(txSharedChunk) + size);
783
0
  if (chunk) {
784
0
    void* data = (((txByte*)chunk) + sizeof(txSharedChunk));
785
  #if mxThreads && !defined(mxUseGCCAtomics)
786
    mxCreateMutex(&(chunk->mutex));
787
  #endif
788
0
    chunk->size = size;
789
0
    chunk->usage = 1;
790
0
    c_memset(data, 0, size);
791
0
    return data;
792
0
  }
793
0
  return C_NULL;
794
0
}
795
796
void fxLockSharedChunk(void* data)
797
0
{
798
#if mxThreads && !defined(mxUseGCCAtomics)
799
  txSharedChunk* chunk = (txSharedChunk*)(((txByte*)data) - sizeof(txSharedChunk));
800
    mxLockMutex(&(chunk->mutex));
801
#endif
802
0
}
803
804
txInteger fxMeasureSharedChunk(void* data)
805
0
{
806
0
  txSharedChunk* chunk = (txSharedChunk*)(((txByte*)data) - sizeof(txSharedChunk));
807
0
  return chunk->size;
808
0
}
809
810
txInteger fxNotifySharedChunk(txMachine* the, void* data, txInteger count)
811
0
{
812
0
  txInteger result = 0;
813
0
  if (gxSharedCluster) {
814
0
  #if mxThreads
815
0
    txSharedWaiter* first = C_NULL;
816
0
    txSharedWaiter* last = C_NULL;
817
0
    txSharedWaiter** address;
818
0
    txSharedWaiter* waiter;
819
0
    mxLockMutex(&gxSharedCluster->waiterMutex);
820
0
    address = &(gxSharedCluster->first);
821
0
    while ((waiter = *address)) {
822
0
      if (waiter->data == data) {
823
0
        if (count == 0)
824
0
          break;
825
0
        count--;
826
0
        if (first)
827
0
          last->next = waiter;
828
0
        else
829
0
          first = waiter;
830
0
        last = waiter;
831
0
        *address = waiter->next;
832
0
        waiter->next = C_NULL;
833
0
      }
834
0
      else
835
0
        address = &(waiter->next);
836
0
    }
837
0
    waiter = first;
838
0
    while (waiter) {
839
0
      waiter->data = C_NULL;
840
0
      if (waiter->condition) {
841
0
        mxWakeCondition((txCondition*)waiter->condition);
842
0
      }
843
0
      else {
844
0
        waiter->ok = 1;
845
0
      #ifdef mxRescheduleSharedTimer
846
0
        mxRescheduleSharedTimer(waiter->timer, 0, 0);
847
      #else
848
        fxAbort(the, XS_DEAD_STRIP_EXIT);
849
      #endif
850
0
      }
851
0
      result++;
852
0
      waiter = waiter->next;
853
0
    }
854
0
    mxUnlockMutex(&gxSharedCluster->waiterMutex);
855
0
  #endif  
856
0
  }
857
0
  return result;
858
0
}
859
860
void* fxRetainSharedChunk(void* data)
861
0
{
862
0
  txSharedChunk* chunk = (txSharedChunk*)(((txByte*)data) - sizeof(txSharedChunk));
863
0
  txS4 result = 0;
864
0
  txS4 value = 1;
865
0
  txS4* address = &(chunk->usage);
866
#ifndef mxUseGCCAtomics
867
  txBoolean lock = 1;
868
#endif
869
0
  mxAtomicsAdd();
870
0
  if (result == 0)
871
0
    return C_NULL;
872
0
  return data;
873
0
}
874
875
void fxReleaseSharedChunk(void* data)
876
0
{
877
0
  txSharedChunk* chunk = (txSharedChunk*)(((txByte*)data) - sizeof(txSharedChunk));
878
0
  txS4 result = 0;
879
0
  txS4 value = 1;
880
0
  txS4* address = &(chunk->usage);
881
#ifndef mxUseGCCAtomics
882
  txBoolean lock = 1;
883
#endif
884
0
  mxAtomicsSub();
885
0
  if (result == 1) {
886
0
    c_free(chunk);
887
0
  }
888
0
}
889
890
void fxUnlockSharedChunk(void* data)
891
0
{
892
#if mxThreads && !defined(mxUseGCCAtomics)
893
  txSharedChunk* chunk = (txSharedChunk*)(((txByte*)data) - sizeof(txSharedChunk));
894
    mxUnlockMutex(&(chunk->mutex));
895
#endif
896
0
}
897
898
#if mxThreads
899
void fxWaitSharedChunkCallback(void* timer, void* refcon, txInteger refconSize)
900
0
{
901
0
  txSharedWaiter** address = (txSharedWaiter**)refcon;
902
0
  txSharedWaiter* waiter = *address;
903
0
  txSharedWaiter* link;
904
0
  txMachine* the;
905
0
  mxLockMutex(&gxSharedCluster->waiterMutex);
906
0
  address = &(gxSharedCluster->first);
907
0
  while ((link = *address)) {
908
0
    if (link == waiter)
909
0
      *address = link->next;
910
0
    else
911
0
      address = &(link->next);
912
0
  }
913
0
  mxUnlockMutex(&gxSharedCluster->waiterMutex);
914
0
  the = waiter->the;
915
0
  fxBeginHost(waiter->the);
916
0
  mxTry(the) {
917
0
    mxPushUndefined();
918
0
    mxPush(waiter->resolve);
919
0
    mxCall();
920
0
    if (waiter->ok)
921
0
      mxPushStringX("ok");
922
0
    else
923
0
      mxPushStringX("timed-out");
924
0
    mxRunCount(1);
925
0
    mxPop();
926
0
  }
927
0
  mxCatch(the) {
928
0
  }
929
0
  fxForget(the, &waiter->resolve);
930
0
  fxEndHost(the);
931
0
  c_free(waiter);
932
0
}
933
#endif
934
935
txInteger fxWaitSharedChunk(txMachine* the, void* data, txNumber timeout, txSlot* resolveFunction)
936
0
{
937
0
  txInteger result = 1;
938
0
  if (gxSharedCluster) {
939
0
  #if mxThreads
940
0
    txSharedWaiter* waiter;
941
0
    txSharedWaiter** address;
942
0
    txSharedWaiter* link;
943
0
    waiter = c_calloc(1, sizeof(txSharedWaiter));
944
0
    if (!waiter)
945
0
      fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT);
946
0
    waiter->the = the;
947
0
    waiter->data = data;
948
0
    mxLockMutex(&gxSharedCluster->waiterMutex);
949
0
    address = &(gxSharedCluster->first);
950
0
    while ((link = *address))
951
0
      address = &(link->next);
952
0
    *address = waiter;
953
    
954
0
    if (resolveFunction) {
955
0
      mxUnlockMutex(&gxSharedCluster->waiterMutex);
956
0
      waiter->resolve = *resolveFunction;
957
0
      fxRemember(the, &waiter->resolve);
958
0
    #ifdef mxScheduleSharedTimer
959
0
      waiter->timer = mxScheduleSharedTimer(timeout, 0, (txSharedTimerCallback)fxWaitSharedChunkCallback, &waiter, sizeof(txSharedWaiter*));
960
0
      if (!waiter->timer)
961
0
        fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT);
962
    #else
963
      fxAbort(the, XS_DEAD_STRIP_EXIT);
964
    #endif
965
0
    }
966
0
    else if (gxSharedCluster->mainThread != mxCurrentThread()) {
967
0
      txCondition condition;
968
0
      mxCreateCondition(&condition);
969
0
      waiter->condition = &condition;
970
0
      if (timeout == C_INFINITY) {
971
0
      #if defined(mxUsePOSIXThreads)
972
0
        while (waiter->data == data)
973
0
          pthread_cond_wait(&condition, &gxSharedCluster->waiterMutex);
974
      #elif defined(mxUseFreeRTOSTasks)
975
        mxUnlockMutex(&gxSharedCluster->waiterMutex);
976
        ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
977
        mxLockMutex(&gxSharedCluster->waiterMutex);
978
      #else
979
        while (waiter->data == data)
980
          SleepConditionVariableCS(&condition, &gxSharedCluster->waiterMutex, INFINITE);
981
      #endif
982
0
      }
983
0
      else {
984
0
      #if defined(mxUsePOSIXThreads)
985
0
        struct timespec ts;
986
0
        timeout += fxDateNow();
987
0
        ts.tv_sec = c_floor(timeout / 1000);
988
0
        ts.tv_nsec = c_fmod(timeout, 1000) * 1000000;
989
0
        while (waiter->data == data) {
990
0
          result = (pthread_cond_timedwait(&condition, &gxSharedCluster->waiterMutex, &ts) == ETIMEDOUT) ? 0 : 1;
991
0
          if (!result)
992
0
            break;
993
0
        }
994
      #elif defined(mxUseFreeRTOSTasks)
995
        mxUnlockMutex(&gxSharedCluster->waiterMutex);
996
        ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(timeout));
997
        mxLockMutex(&gxSharedCluster->waiterMutex);
998
        result = (waiter->data == data) ? 0 : 1;
999
      #else
1000
        timeout += fxDateNow();
1001
        while (waiter->data == data) {
1002
          result = (SleepConditionVariableCS(&condition, &gxSharedCluster->waiterMutex, (DWORD)(timeout - fxDateNow()))) ? 1 : 0;
1003
          if (!result)
1004
            break;
1005
        }
1006
      #endif
1007
0
      }
1008
0
      address = &(gxSharedCluster->first);
1009
0
      while ((link = *address)) {
1010
0
        if (link == waiter)
1011
0
          *address = link->next;
1012
0
        else
1013
0
          address = &(link->next);
1014
0
      }
1015
0
      mxUnlockMutex(&gxSharedCluster->waiterMutex);
1016
0
      c_free(waiter);
1017
0
      mxDeleteCondition(&condition);
1018
0
    }
1019
0
    else {
1020
0
      mxTypeError("main thread cannot wait");
1021
0
    }
1022
0
  #endif  
1023
0
  }
1024
0
  else {
1025
0
    mxTypeError("no shared cluster");
1026
0
  }
1027
0
  return result;
1028
0
}
1029
1030
#endif /* mxUseDefaultSharedChunks */
1031
1032