Skip to content

Commit 86b58ee

Browse files
lambdageekkg
andauthored
[mono][mini] Interlocked.CompareExchange and Interlocked.Exchange intrinsics for small types and enums (#106660)
Only arm64, amd64 and WebAssembly. Interpreter, JIT and LLVM AOT. No x86 or arm32. The complication for the 8- and 16-bit operands is that the .NET operand stack is 32-bit. so we have to zero- or sign-extend the inputs and output. I ended up following the same approach as clang: zero-extend "expected" value and then sign-extend the return value of the CAS. One nice consequence is that the LLVM support is essentially free. --- Also this PR makes the intrinsic apply to types that have byte/int/long as the underlying type (bool, enums) not just when the type is literally in the signature --- Also implement interp and jiterp intrinsic for Exchange(int) - this was not available previously. --- Related to #105335 Related to #93488 * [mono][mini][arm64] Interlocked.CompareExchange for byte/sbyte * [sample] fixup HelloWorld to work with full aot * [mini][llvm] support OP_ATOMIC_CAS_U1 * [mini][amd64] support OP_ATOMIC_CAS_U1 * [mini][wasm] support OP_ATOMIC_CAS_U1 in LLVM AOT * make intrinsic must-expand on arm64,amd64,wasm on mono * [interp] MINT_MONO_CMPXCHG_U1 also add mono_atomic_cas_u8 utility function * [mini] CompareExchange(i16/u16) * [mono] must expand CompareExchange(i16/u16) * [interp] Interlocked.CompareExchange(u16/i16) * [mini] zext unsigned CAS results for small types * [interp] signed small CAS ops * [amd64] fixup 8- and 16-bit cmpxchg encoding * fixup u16 win32 atomic * Interlocked.Exchange u1/i1/u2/i2 interp,llvm,amd64,arm64 * [amd64] give u2 CMPXCHG and XCHG one more byte for the 16-bit addressing prefix * If jiterpreter is engaged before the thread is fully initialized, just fail to allocate a table index and generate a warning. This shouldn't happen in prod anyway * Implement cmpxchg atomics natively in jiterpreter * Remove unnecessary jiterp cas helpers * Do cmpxchg result fixups as needed * Add runtime option for jiterpreter atomics * Implement atomic exchanges in the jiterpreter * Interlocked.Exchange(int) for interp and jiterp --------- Co-authored-by: Katelyn Gadd <[email protected]>
1 parent df2d213 commit 86b58ee

24 files changed

+711
-104
lines changed

src/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public static short Exchange(ref short location1, short value) =>
8484
[MethodImpl(MethodImplOptions.AggressiveInlining)]
8585
public static unsafe byte Exchange(ref byte location1, byte value)
8686
{
87-
#if !MONO && (TARGET_X86 || TARGET_AMD64 || TARGET_ARM64)
87+
#if (MONO && (TARGET_AMD64 || TARGET_ARM64 || TARGET_WASM)) || (!MONO && (TARGET_X86 || TARGET_AMD64 || TARGET_ARM64))
8888
return Exchange(ref location1, value); // Must expand intrinsic
8989
#else
9090
// this relies on GC keeping 4B alignment for refs and on subtracting to such alignment being in the same object
@@ -123,7 +123,7 @@ public static unsafe byte Exchange(ref byte location1, byte value)
123123
[CLSCompliant(false)]
124124
public static unsafe ushort Exchange(ref ushort location1, ushort value)
125125
{
126-
#if !MONO && (TARGET_X86 || TARGET_AMD64 || TARGET_ARM64)
126+
#if ((MONO && (TARGET_AMD64 || TARGET_ARM64 || TARGET_WASM)) || !MONO && (TARGET_X86 || TARGET_AMD64 || TARGET_ARM64))
127127
return Exchange(ref location1, value); // Must expand intrinsic
128128
#else
129129
// this relies on GC keeping 4B alignment for refs and on subtracting to such alignment being in the same object
@@ -322,7 +322,7 @@ public static short CompareExchange(ref short location1, short value, short comp
322322
[MethodImpl(MethodImplOptions.AggressiveInlining)]
323323
public static unsafe byte CompareExchange(ref byte location1, byte value, byte comparand)
324324
{
325-
#if !MONO && (TARGET_X86 || TARGET_AMD64 || TARGET_ARM64)
325+
#if (MONO && (TARGET_ARM64 || TARGET_AMD64 || TARGET_WASM)) || (!MONO && (TARGET_X86 || TARGET_AMD64 || TARGET_ARM64))
326326
return CompareExchange(ref location1, value, comparand); // Must expand intrinsic
327327
#else
328328
// this relies on GC keeping 4B alignment for refs and on subtracting to such alignment being in the same object
@@ -365,7 +365,7 @@ public static unsafe byte CompareExchange(ref byte location1, byte value, byte c
365365
[CLSCompliant(false)]
366366
public static unsafe ushort CompareExchange(ref ushort location1, ushort value, ushort comparand)
367367
{
368-
#if !MONO && (TARGET_X86 || TARGET_AMD64 || TARGET_ARM64)
368+
#if (MONO && (TARGET_ARM64 || TARGET_AMD64 || TARGET_WASM)) || (!MONO && (TARGET_X86 || TARGET_AMD64 || TARGET_ARM64))
369369
return CompareExchange(ref location1, value, comparand); // Must expand intrinsic
370370
#else
371371
// this relies on GC keeping 4B alignment for refs and on subtracting to such alignment being in the same object

src/mono/browser/runtime/jiterpreter-opcodes.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,3 +511,73 @@ export const enum WasmSimdOpcode {
511511
i32x4_extadd_pairwise_i16x8_s = 0x7e,
512512
i32x4_extadd_pairwise_i16x8_u = 0x7f,
513513
}
514+
515+
export const enum WasmAtomicOpcode {
516+
memory_atomic_notify = 0x00,
517+
memory_atomic_wait32 = 0x01,
518+
memory_atomic_wait64 = 0x02,
519+
atomic_fence = 0x03,
520+
i32_atomic_load = 0x10,
521+
i64_atomic_load = 0x11,
522+
i32_atomic_load8_u = 0x12,
523+
i32_atomic_load16_u = 0x13,
524+
i64_atomic_load8_u = 0x14,
525+
i64_atomic_load16_u = 0x15,
526+
i64_atomic_load32_u = 0x16,
527+
i32_atomic_store = 0x17,
528+
i64_atomic_store = 0x18,
529+
i32_atomic_store8 = 0x19,
530+
i32_atomic_store16 = 0x1A,
531+
i64_atomic_store8 = 0x1B,
532+
i64_atomic_store16 = 0x1C,
533+
i64_atomic_store32 = 0x1D,
534+
i32_atomic_rmw_add = 0x1E,
535+
i64_atomic_rmw_add = 0x1F,
536+
i32_atomic_rmw8_add_u = 0x20,
537+
i32_atomic_rmw16_add_u = 0x21,
538+
i64_atomic_rmw8_add_u = 0x22,
539+
i64_atomic_rmw16_add_u = 0x23,
540+
i64_atomic_rmw32_add_u = 0x24,
541+
i32_atomic_rmw_sub = 0x25,
542+
i64_atomic_rmw_sub = 0x26,
543+
i32_atomic_rmw8_sub_u = 0x27,
544+
i32_atomic_rmw16_sub_u = 0x28,
545+
i64_atomic_rmw8_sub_u = 0x29,
546+
i64_atomic_rmw16_sub_u = 0x2A,
547+
i64_atomic_rmw32_sub_u = 0x2B,
548+
i32_atomic_rmw_and = 0x2C,
549+
i64_atomic_rmw_and = 0x2D,
550+
i32_atomic_rmw8_and_u = 0x2E,
551+
i32_atomic_rmw16_and_u = 0x2F,
552+
i64_atomic_rmw8_and_u = 0x30,
553+
i64_atomic_rmw16_and_u = 0x31,
554+
i64_atomic_rmw32_and_u = 0x32,
555+
i32_atomic_rmw_or = 0x33,
556+
i64_atomic_rmw_or = 0x34,
557+
i32_atomic_rmw8_or_u = 0x35,
558+
i32_atomic_rmw16_or_u = 0x36,
559+
i64_atomic_rmw8_or_u = 0x37,
560+
i64_atomic_rmw16_or_u = 0x38,
561+
i64_atomic_rmw32_or_u = 0x39,
562+
i32_atomic_rmw_xor = 0x3A,
563+
i64_atomic_rmw_xor = 0x3B,
564+
i32_atomic_rmw8_xor_u = 0x3C,
565+
i32_atomic_rmw16_xor_u = 0x3D,
566+
i64_atomic_rmw8_xor_u = 0x3E,
567+
i64_atomic_rmw16_xor_u = 0x3F,
568+
i64_atomic_rmw32_xor_u = 0x40,
569+
i32_atomic_rmw_xchg = 0x41,
570+
i64_atomic_rmw_xchg = 0x42,
571+
i32_atomic_rmw8_xchg_u = 0x43,
572+
i32_atomic_rmw16_xchg_u = 0x44,
573+
i64_atomic_rmw8_xchg_u = 0x45,
574+
i64_atomic_rmw16_xchg_u = 0x46,
575+
i64_atomic_rmw32_xchg_u = 0x47,
576+
i32_atomic_rmw_cmpxchg = 0x48,
577+
i64_atomic_rmw_cmpxchg = 0x49,
578+
i32_atomic_rmw8_cmpxchg_u = 0x4A,
579+
i32_atomic_rmw16_cmpxchg_u = 0x4B,
580+
i64_atomic_rmw8_cmpxchg_u = 0x4C,
581+
i64_atomic_rmw16_cmpxchg_u = 0x4D,
582+
i64_atomic_rmw32_cmpxchg_u = 0x4E,
583+
}

src/mono/browser/runtime/jiterpreter-support.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import WasmEnableThreads from "consts:wasmEnableThreads";
55
import { NativePointer, ManagedPointer, VoidPtr } from "./types/emscripten";
66
import { Module, mono_assert, runtimeHelpers } from "./globals";
7-
import { WasmOpcode, WasmSimdOpcode, WasmValtype } from "./jiterpreter-opcodes";
7+
import { WasmOpcode, WasmSimdOpcode, WasmAtomicOpcode, WasmValtype } from "./jiterpreter-opcodes";
88
import { MintOpcode } from "./mintops";
99
import cwraps from "./cwraps";
1010
import { mono_log_error, mono_log_info } from "./logging";
@@ -105,6 +105,9 @@ export class WasmBuilder {
105105
nextConstantSlot = 0;
106106
backBranchTraceLevel = 0;
107107

108+
containsSimd!: boolean;
109+
containsAtomics!: boolean;
110+
108111
compressImportNames = false;
109112
lockImports = false;
110113

@@ -153,6 +156,9 @@ export class WasmBuilder {
153156
this.callHandlerReturnAddresses.length = 0;
154157

155158
this.allowNullCheckOptimization = this.options.eliminateNullChecks;
159+
160+
this.containsSimd = false;
161+
this.containsAtomics = false;
156162
}
157163

158164
_push () {
@@ -257,11 +263,18 @@ export class WasmBuilder {
257263

258264
appendSimd (value: WasmSimdOpcode, allowLoad?: boolean) {
259265
this.current.appendU8(WasmOpcode.PREFIX_simd);
260-
// Yes that's right. We're using LEB128 to encode 8-bit opcodes. Why? I don't know
261266
mono_assert(((value | 0) !== 0) || ((value === WasmSimdOpcode.v128_load) && (allowLoad === true)), "Expected non-v128_load simd opcode or allowLoad==true");
267+
// Yes that's right. We're using LEB128 to encode 8-bit opcodes. Why? I don't know
262268
return this.current.appendULeb(value);
263269
}
264270

271+
appendAtomic (value: WasmAtomicOpcode, allowNotify?: boolean) {
272+
this.current.appendU8(WasmOpcode.PREFIX_atomic);
273+
mono_assert(((value | 0) !== 0) || ((value === WasmAtomicOpcode.memory_atomic_notify) && (allowNotify === true)), "Expected non-notify atomic opcode or allowNotify==true");
274+
// Unlike SIMD, the spec appears to say that atomic opcodes are just two sequential bytes with explicit values.
275+
return this.current.appendU8(value);
276+
}
277+
265278
appendU32 (value: number) {
266279
return this.current.appendU32(value);
267280
}
@@ -517,7 +530,7 @@ export class WasmBuilder {
517530
// memtype (limits = 0x03 n:u32 m:u32 => {min n, max m, shared})
518531
this.appendU8(0x02);
519532
this.appendU8(0x03);
520-
// emcc seems to generate this min/max by default
533+
// HACK: emcc seems to generate this min/max by default
521534
this.appendULeb(256);
522535
this.appendULeb(32768);
523536
} else {
@@ -1900,6 +1913,7 @@ export type JiterpreterOptions = {
19001913
enableCallResume: boolean;
19011914
enableWasmEh: boolean;
19021915
enableSimd: boolean;
1916+
enableAtomics: boolean;
19031917
zeroPageOptimization: boolean;
19041918
cprop: boolean;
19051919
// For locations where the jiterpreter heuristic says we will be unable to generate
@@ -1946,6 +1960,7 @@ const optionNames: { [jsName: string]: string } = {
19461960
"enableCallResume": "jiterpreter-call-resume-enabled",
19471961
"enableWasmEh": "jiterpreter-wasm-eh-enabled",
19481962
"enableSimd": "jiterpreter-simd-enabled",
1963+
"enableAtomics": "jiterpreter-atomics-enabled",
19491964
"zeroPageOptimization": "jiterpreter-zero-page-optimization",
19501965
"cprop": "jiterpreter-constant-propagation",
19511966
"enableStats": "jiterpreter-stats-enabled",

src/mono/browser/runtime/jiterpreter-tables.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
import {
5-
WasmOpcode, WasmSimdOpcode, JiterpSpecialOpcode
5+
WasmOpcode, WasmSimdOpcode, WasmAtomicOpcode, JiterpSpecialOpcode
66
} from "./jiterpreter-opcodes";
77
import {
88
MintOpcode, SimdIntrinsic2, SimdIntrinsic3, SimdIntrinsic4
@@ -325,6 +325,24 @@ export const mathIntrinsicTable: { [opcode: number]: [isUnary: boolean, isF32: b
325325
[MintOpcode.MINT_REM_R4]: [false, true, "fmodf"],
326326
};
327327

328+
export const xchgTable: { [opcode: number]: [wasmOpcode: WasmAtomicOpcode, resultFixupOpcode: WasmOpcode, alignmentPower: number] } = {
329+
[MintOpcode.MINT_MONO_EXCHANGE_U1]: [WasmAtomicOpcode.i32_atomic_rmw8_xchg_u, WasmOpcode.unreachable, 0],
330+
[MintOpcode.MINT_MONO_EXCHANGE_I1]: [WasmAtomicOpcode.i32_atomic_rmw8_xchg_u, WasmOpcode.i32_extend_8_s, 0],
331+
[MintOpcode.MINT_MONO_EXCHANGE_U2]: [WasmAtomicOpcode.i32_atomic_rmw16_xchg_u, WasmOpcode.unreachable, 1],
332+
[MintOpcode.MINT_MONO_EXCHANGE_I2]: [WasmAtomicOpcode.i32_atomic_rmw16_xchg_u, WasmOpcode.i32_extend_16_s, 1],
333+
[MintOpcode.MINT_MONO_EXCHANGE_I4]: [WasmAtomicOpcode.i32_atomic_rmw_xchg, WasmOpcode.unreachable, 2],
334+
[MintOpcode.MINT_MONO_EXCHANGE_I8]: [WasmAtomicOpcode.i64_atomic_rmw_xchg, WasmOpcode.unreachable, 3],
335+
};
336+
337+
export const cmpxchgTable: { [opcode: number]: [wasmOpcode: WasmAtomicOpcode, resultFixupOpcode: WasmOpcode, alignmentPower: number] } = {
338+
[MintOpcode.MINT_MONO_CMPXCHG_U1]: [WasmAtomicOpcode.i32_atomic_rmw8_cmpxchg_u, WasmOpcode.unreachable, 0],
339+
[MintOpcode.MINT_MONO_CMPXCHG_I1]: [WasmAtomicOpcode.i32_atomic_rmw8_cmpxchg_u, WasmOpcode.i32_extend_8_s, 0],
340+
[MintOpcode.MINT_MONO_CMPXCHG_U2]: [WasmAtomicOpcode.i32_atomic_rmw16_cmpxchg_u, WasmOpcode.unreachable, 1],
341+
[MintOpcode.MINT_MONO_CMPXCHG_I2]: [WasmAtomicOpcode.i32_atomic_rmw16_cmpxchg_u, WasmOpcode.i32_extend_16_s, 1],
342+
[MintOpcode.MINT_MONO_CMPXCHG_I4]: [WasmAtomicOpcode.i32_atomic_rmw_cmpxchg, WasmOpcode.unreachable, 2],
343+
[MintOpcode.MINT_MONO_CMPXCHG_I8]: [WasmAtomicOpcode.i64_atomic_rmw_cmpxchg, WasmOpcode.unreachable, 3],
344+
};
345+
328346
export const simdCreateSizes = {
329347
[MintOpcode.MINT_SIMD_V128_I1_CREATE]: 1,
330348
[MintOpcode.MINT_SIMD_V128_I2_CREATE]: 2,

src/mono/browser/runtime/jiterpreter-trace-generator.ts

Lines changed: 61 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ import {
5454
bitmaskTable, createScalarTable,
5555
simdExtractTable, simdReplaceTable,
5656
simdLoadTable, simdStoreTable,
57+
xchgTable, cmpxchgTable,
5758
} from "./jiterpreter-tables";
5859
import { mono_log_error, mono_log_info } from "./logging";
5960
import { mono_assert, runtimeHelpers } from "./globals";
@@ -244,7 +245,6 @@ export function generateWasmBody (
244245
): number {
245246
const abort = <MintOpcodePtr><any>0;
246247
let isFirstInstruction = true, isConditionallyExecuted = false,
247-
containsSimd = false,
248248
pruneOpcodes = false, hasEmittedUnreachable = false;
249249
let result = 0,
250250
prologueOpcodeCounter = 0,
@@ -1465,26 +1465,6 @@ export function generateWasmBody (
14651465
break;
14661466
}
14671467

1468-
case MintOpcode.MINT_MONO_CMPXCHG_I4:
1469-
builder.local("pLocals");
1470-
append_ldloc(builder, getArgU16(ip, 2), WasmOpcode.i32_load); // dest
1471-
append_ldloc(builder, getArgU16(ip, 3), WasmOpcode.i32_load); // newVal
1472-
append_ldloc(builder, getArgU16(ip, 4), WasmOpcode.i32_load); // expected
1473-
builder.callImport("cmpxchg_i32");
1474-
append_stloc_tail(builder, getArgU16(ip, 1), WasmOpcode.i32_store);
1475-
break;
1476-
case MintOpcode.MINT_MONO_CMPXCHG_I8:
1477-
// because i64 values can't pass through JS cleanly (c.f getRawCwrap and
1478-
// EMSCRIPTEN_KEEPALIVE), we pass addresses of newVal, expected and the return value
1479-
// to the helper function. The "dest" for the compare-exchange is already a
1480-
// pointer, so load it normally
1481-
append_ldloc(builder, getArgU16(ip, 2), WasmOpcode.i32_load); // dest
1482-
append_ldloca(builder, getArgU16(ip, 3), 0); // newVal
1483-
append_ldloca(builder, getArgU16(ip, 4), 0); // expected
1484-
append_ldloca(builder, getArgU16(ip, 1), 8); // oldVal
1485-
builder.callImport("cmpxchg_i64");
1486-
break;
1487-
14881468
case MintOpcode.MINT_LOG2_I4:
14891469
case MintOpcode.MINT_LOG2_I8: {
14901470
const isI64 = (opcode === MintOpcode.MINT_LOG2_I8);
@@ -1647,13 +1627,19 @@ export function generateWasmBody (
16471627
(opcode >= MintOpcode.MINT_SIMD_V128_LDC) &&
16481628
(opcode <= MintOpcode.MINT_SIMD_INTRINS_P_PPP)
16491629
) {
1630+
builder.containsSimd = true;
16501631
if (!emit_simd(builder, ip, opcode, opname, simdIntrinsArgCount, simdIntrinsIndex))
16511632
ip = abort;
1652-
else {
1653-
containsSimd = true;
1633+
else
16541634
// We need to do dreg invalidation differently for simd, especially to handle ldc
16551635
skipDregInvalidation = true;
1656-
}
1636+
} else if (
1637+
(opcode >= MintOpcode.MINT_MONO_MEMORY_BARRIER) &&
1638+
(opcode <= MintOpcode.MINT_MONO_CMPXCHG_I8)
1639+
) {
1640+
builder.containsAtomics = true;
1641+
if (!emit_atomics(builder, ip, opcode))
1642+
ip = abort;
16571643
} else if (opcodeValue === 0) {
16581644
// This means it was explicitly marked as no-value in the opcode value table
16591645
// so we can just skip over it. This is done for things like nops.
@@ -1740,7 +1726,7 @@ export function generateWasmBody (
17401726
// HACK: Traces containing simd will be *much* shorter than non-simd traces,
17411727
// which will cause both the heuristic and our length requirement outside
17421728
// to reject them. For now, just add a big constant to the length
1743-
if (containsSimd)
1729+
if (builder.containsSimd)
17441730
result += 10240;
17451731
return result;
17461732
}
@@ -3963,3 +3949,53 @@ function emit_simd_4 (builder: WasmBuilder, ip: MintOpcodePtr, index: SimdIntrin
39633949
return false;
39643950
}
39653951
}
3952+
3953+
function emit_atomics (
3954+
builder: WasmBuilder, ip: MintOpcodePtr, opcode: number
3955+
) {
3956+
if (!builder.options.enableAtomics)
3957+
return false;
3958+
3959+
// FIXME: memory barrier might be worthwhile to implement
3960+
// FIXME: We could probably unify most of the xchg/cmpxchg implementation into one implementation
3961+
3962+
const xchg = xchgTable[opcode];
3963+
if (xchg) {
3964+
const is64 = xchg[2] > 2;
3965+
// TODO: Generate alignment check to produce a better runtime error when address is not aligned?
3966+
builder.local("pLocals"); // stloc head
3967+
append_ldloc_cknull(builder, getArgU16(ip, 2), ip, true); // address
3968+
append_ldloc(builder, getArgU16(ip, 3), is64 ? WasmOpcode.i64_load : WasmOpcode.i32_load); // replacement
3969+
builder.appendAtomic(xchg[0], false);
3970+
builder.appendMemarg(0, xchg[2]);
3971+
// Fixup the result if necessary
3972+
if (xchg[1] !== WasmOpcode.unreachable)
3973+
builder.appendU8(xchg[1]);
3974+
// store old value
3975+
append_stloc_tail(builder, getArgU16(ip, 1), is64 ? WasmOpcode.i64_store : WasmOpcode.i32_store);
3976+
return true;
3977+
}
3978+
3979+
const cmpxchg = cmpxchgTable[opcode];
3980+
if (cmpxchg) {
3981+
const is64 = cmpxchg[2] > 2;
3982+
// TODO: Generate alignment check to produce a better runtime error when address is not aligned?
3983+
builder.local("pLocals"); // stloc head
3984+
append_ldloc_cknull(builder, getArgU16(ip, 2), ip, true); // address
3985+
// FIXME: Do these loads need to be sized? I think it's well-defined even if there are garbage bytes in the i32,
3986+
// based on language from the spec that looks like this: 'expected wrapped from i32 to i8, 8-bit compare equal'
3987+
append_ldloc(builder, getArgU16(ip, 4), is64 ? WasmOpcode.i64_load : WasmOpcode.i32_load); // expected
3988+
append_ldloc(builder, getArgU16(ip, 3), is64 ? WasmOpcode.i64_load : WasmOpcode.i32_load); // replacement
3989+
builder.appendAtomic(cmpxchg[0], false);
3990+
builder.appendMemarg(0, cmpxchg[2]);
3991+
// Fixup the result if necessary
3992+
if (cmpxchg[1] !== WasmOpcode.unreachable)
3993+
builder.appendU8(cmpxchg[1]);
3994+
// store old value
3995+
append_stloc_tail(builder, getArgU16(ip, 1), is64 ? WasmOpcode.i64_store : WasmOpcode.i32_store);
3996+
return true;
3997+
}
3998+
3999+
return false;
4000+
}
4001+

src/mono/browser/runtime/jiterpreter.ts

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -283,8 +283,6 @@ function getTraceImports () {
283283
importDef("array_rank", getRawCwrap("mono_jiterp_get_array_rank")),
284284
["a_elesize", "array_rank", getRawCwrap("mono_jiterp_get_array_element_size")],
285285
importDef("stfld_o", getRawCwrap("mono_jiterp_set_object_field")),
286-
importDef("cmpxchg_i32", getRawCwrap("mono_jiterp_cas_i32")),
287-
importDef("cmpxchg_i64", getRawCwrap("mono_jiterp_cas_i64")),
288286
["stelemr_tc", "stelemr", getRawCwrap("mono_jiterp_stelem_ref")],
289287
importDef("fma", getRawCwrap("fma")),
290288
importDef("fmaf", getRawCwrap("fmaf")),
@@ -629,25 +627,6 @@ function initialize_builder (builder: WasmBuilder) {
629627
},
630628
WasmValtype.void, true
631629
);
632-
builder.defineType(
633-
"cmpxchg_i32",
634-
{
635-
"dest": WasmValtype.i32,
636-
"newVal": WasmValtype.i32,
637-
"expected": WasmValtype.i32,
638-
},
639-
WasmValtype.i32, true
640-
);
641-
builder.defineType(
642-
"cmpxchg_i64",
643-
{
644-
"dest": WasmValtype.i32,
645-
"newVal": WasmValtype.i32,
646-
"expected": WasmValtype.i32,
647-
"oldVal": WasmValtype.i32,
648-
},
649-
WasmValtype.void, true
650-
);
651630
builder.defineType(
652631
"stelemr",
653632
{
@@ -896,7 +875,12 @@ function generate_wasm (
896875
} catch (exc: any) {
897876
threw = true;
898877
rejected = false;
899-
mono_log_error(`${methodFullName || traceName} code generation failed: ${exc} ${exc.stack}`);
878+
let desc = builder.containsSimd
879+
? " (simd)"
880+
: "";
881+
if (builder.containsAtomics)
882+
desc += " (atomics)";
883+
mono_log_error(`${methodFullName || traceName}${desc} code generation failed: ${exc} ${exc.stack}`);
900884
recordFailure();
901885
return 0;
902886
} finally {

0 commit comments

Comments
 (0)