#include "mozilla/Atomics.h"
#ifdef JS_CODEGEN_ARM
# include "jit/arm/Architecture-arm.h"
#endif
#include "jit/AtomicOperations.h"
#include "jit/IonTypes.h"
#include "jit/MacroAssembler.h"
#include "jit/RegisterSets.h"
#include "jit/MacroAssembler-inl.h"
using namespace js;
using namespace js::jit;
#if defined(JS_CODEGEN_X64)
static const LiveRegisterSet AtomicNonVolatileRegs;
static constexpr Register AtomicPtrReg = IntArgReg0;
static constexpr Register AtomicPtr2Reg = IntArgReg1;
static constexpr Register AtomicValReg = IntArgReg1;
static constexpr Register64 AtomicValReg64(IntArgReg1);
static constexpr Register AtomicVal2Reg = IntArgReg2;
static constexpr Register64 AtomicVal2Reg64(IntArgReg2);
static constexpr Register AtomicTemp = IntArgReg3;
static constexpr Register64 AtomicTemp64(IntArgReg3);
static constexpr Register64 AtomicReturnReg64 = ReturnReg64;
#elif defined(JS_CODEGEN_ARM64)
static const LiveRegisterSet AtomicNonVolatileRegs;
static constexpr Register AtomicPtrReg = IntArgReg4;
static constexpr Register AtomicPtr2Reg = IntArgReg1;
static constexpr Register AtomicValReg = IntArgReg1;
static constexpr Register64 AtomicValReg64(IntArgReg1);
static constexpr Register AtomicVal2Reg = IntArgReg2;
static constexpr Register64 AtomicVal2Reg64(IntArgReg2);
static constexpr Register AtomicTemp = IntArgReg3;
static constexpr Register64 AtomicTemp64(IntArgReg3);
static constexpr Register64 AtomicReturnReg64 = ReturnReg64;
#elif defined(JS_CODEGEN_ARM)
static const LiveRegisterSet AtomicNonVolatileRegs = LiveRegisterSet(
GeneralRegisterSet(
(uint32_t(1) << Registers::r4) | (uint32_t(1) << Registers::r5) |
(uint32_t(1) << Registers::r6) | (uint32_t(1) << Registers::r7) |
(uint32_t(1) << Registers::r8) | (uint32_t(1) << Registers::lr)),
FloatRegisterSet(0));
static constexpr Register AtomicPtrReg = r8;
static constexpr Register AtomicPtr2Reg = r6;
static constexpr Register AtomicTemp = r3;
static constexpr Register AtomicValReg = r6;
static constexpr Register64 AtomicValReg64(r7, r6);
static constexpr Register AtomicVal2Reg = r4;
static constexpr Register64 AtomicVal2Reg64(r5, r4);
static constexpr Register64 AtomicReturnReg64 = ReturnReg64;
#elif defined(JS_CODEGEN_X86)
static const LiveRegisterSet AtomicNonVolatileRegs = LiveRegisterSet(
GeneralRegisterSet((1 << X86Encoding::rbx) | (1 << X86Encoding::rsi)),
FloatRegisterSet(0));
static constexpr Register AtomicPtrReg = esi;
static constexpr Register AtomicPtr2Reg = ebx;
static constexpr Register AtomicValReg = ebx;
static constexpr Register AtomicVal2Reg = ecx;
static constexpr Register AtomicTemp = edx;
static constexpr Register64 AtomicValReg64(edx, eax);
static constexpr Register64 AtomicVal2Reg64(ecx, ebx);
static constexpr Register64 AtomicReturnReg64(edx, eax);
#else
# error "Unsupported platform"
#endif
static constexpr Scalar::Type SIZE8 = Scalar::Uint8;
static constexpr Scalar::Type SIZE16 = Scalar::Uint16;
static constexpr Scalar::Type SIZE32 = Scalar::Uint32;
static constexpr Scalar::Type SIZE64 = Scalar::Int64;
#ifdef JS_64BIT
static constexpr Scalar::Type SIZEWORD = SIZE64;
#else
static constexpr Scalar::Type SIZEWORD = SIZE32;
#endif
static constexpr size_t WORDSIZE =
sizeof(uintptr_t); static constexpr size_t BLOCKSIZE = 8 * WORDSIZE;
static_assert(BLOCKSIZE % WORDSIZE == 0,
"A block is an integral number of words");
static constexpr size_t WORDMASK = WORDSIZE - 1;
static constexpr size_t BLOCKMASK = BLOCKSIZE - 1;
struct ArgIterator {
ABIArgGenerator abi;
unsigned argBase = 0;
};
static void GenGprArg(MacroAssembler& masm, MIRType t, ArgIterator* iter,
Register reg) {
MOZ_ASSERT(t == MIRType::Pointer || t == MIRType::Int32);
ABIArg arg = iter->abi.next(t);
switch (arg.kind()) {
case ABIArg::GPR: {
if (arg.gpr() != reg) {
masm.movePtr(arg.gpr(), reg);
}
break;
}
case ABIArg::Stack: {
Address src(masm.getStackPointer(),
iter->argBase + arg.offsetFromArgBase());
masm.loadPtr(src, reg);
break;
}
default: { MOZ_CRASH("Not possible"); }
}
}
static void GenGpr64Arg(MacroAssembler& masm, ArgIterator* iter,
Register64 reg) {
ABIArg arg = iter->abi.next(MIRType::Int64);
switch (arg.kind()) {
case ABIArg::GPR: {
if (arg.gpr64() != reg) {
masm.move64(arg.gpr64(), reg);
}
break;
}
case ABIArg::Stack: {
Address src(masm.getStackPointer(),
iter->argBase + arg.offsetFromArgBase());
#ifdef JS_64BIT
masm.load64(src, reg);
#else
masm.load32(LowWord(src), reg.low);
masm.load32(HighWord(src), reg.high);
#endif
break;
}
#if defined(JS_CODEGEN_REGISTER_PAIR)
case ABIArg::GPR_PAIR: {
if (arg.gpr64() != reg) {
masm.move32(arg.oddGpr(), reg.high);
masm.move32(arg.evenGpr(), reg.low);
}
break;
}
#endif
default: { MOZ_CRASH("Not possible"); }
}
}
static uint32_t GenPrologue(MacroAssembler& masm, ArgIterator* iter) {
masm.assumeUnreachable("Shouldn't get here");
masm.flushBuffer();
masm.haltingAlign(CodeAlignment);
masm.setFramePushed(0);
uint32_t start = masm.currentOffset();
masm.PushRegsInMask(AtomicNonVolatileRegs);
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
iter->argBase = masm.framePushed();
#elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
iter->argBase = sizeof(void*) + masm.framePushed();
#else
# error "Unsupported platform"
#endif
return start;
}
static void GenEpilogue(MacroAssembler& masm) {
masm.PopRegsInMask(AtomicNonVolatileRegs);
MOZ_ASSERT(masm.framePushed() == 0);
#if defined(JS_CODEGEN_ARM64)
masm.Ret();
#elif defined(JS_CODEGEN_ARM)
masm.mov(lr, pc);
#elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
masm.ret();
#endif
}
#ifndef JS_64BIT
static uint32_t GenNop(MacroAssembler& masm) {
ArgIterator iter;
uint32_t start = GenPrologue(masm, &iter);
GenEpilogue(masm);
return start;
}
#endif
static uint32_t GenFenceSeqCst(MacroAssembler& masm) {
ArgIterator iter;
uint32_t start = GenPrologue(masm, &iter);
masm.memoryBarrier(MembarFull);
GenEpilogue(masm);
return start;
}
static uint32_t GenLoad(MacroAssembler& masm, Scalar::Type size,
Synchronization sync) {
ArgIterator iter;
uint32_t start = GenPrologue(masm, &iter);
GenGprArg(masm, MIRType::Pointer, &iter, AtomicPtrReg);
masm.memoryBarrier(sync.barrierBefore);
Address addr(AtomicPtrReg, 0);
switch (size) {
case SIZE8:
masm.load8ZeroExtend(addr, ReturnReg);
break;
case SIZE16:
masm.load16ZeroExtend(addr, ReturnReg);
break;
case SIZE32:
masm.load32(addr, ReturnReg);
break;
case SIZE64:
#if defined(JS_64BIT)
masm.load64(addr, AtomicReturnReg64);
break;
#else
MOZ_CRASH("64-bit atomic load not available on this platform");
#endif
default:
MOZ_CRASH("Unknown size");
}
masm.memoryBarrier(sync.barrierAfter);
GenEpilogue(masm);
return start;
}
static uint32_t GenStore(MacroAssembler& masm, Scalar::Type size,
Synchronization sync) {
ArgIterator iter;
uint32_t start = GenPrologue(masm, &iter);
GenGprArg(masm, MIRType::Pointer, &iter, AtomicPtrReg);
masm.memoryBarrier(sync.barrierBefore);
Address addr(AtomicPtrReg, 0);
switch (size) {
case SIZE8:
GenGprArg(masm, MIRType::Int32, &iter, AtomicValReg);
masm.store8(AtomicValReg, addr);
break;
case SIZE16:
GenGprArg(masm, MIRType::Int32, &iter, AtomicValReg);
masm.store16(AtomicValReg, addr);
break;
case SIZE32:
GenGprArg(masm, MIRType::Int32, &iter, AtomicValReg);
masm.store32(AtomicValReg, addr);
break;
case SIZE64:
#if defined(JS_64BIT)
GenGpr64Arg(masm, &iter, AtomicValReg64);
masm.store64(AtomicValReg64, addr);
break;
#else
MOZ_CRASH("64-bit atomic store not available on this platform");
#endif
default:
MOZ_CRASH("Unknown size");
}
masm.memoryBarrier(sync.barrierAfter);
GenEpilogue(masm);
return start;
}
enum class CopyDir {
DOWN, UP };
static uint32_t GenCopy(MacroAssembler& masm, Scalar::Type size,
uint32_t unroll, CopyDir direction) {
ArgIterator iter;
uint32_t start = GenPrologue(masm, &iter);
Register dest = AtomicPtrReg;
Register src = AtomicPtr2Reg;
GenGprArg(masm, MIRType::Pointer, &iter, dest);
GenGprArg(masm, MIRType::Pointer, &iter, src);
uint32_t offset = direction == CopyDir::DOWN ? 0 : unroll - 1;
for (uint32_t i = 0; i < unroll; i++) {
switch (size) {
case SIZE8:
masm.load8ZeroExtend(Address(src, offset), AtomicTemp);
masm.store8(AtomicTemp, Address(dest, offset));
break;
case SIZE16:
masm.load16ZeroExtend(Address(src, offset * 2), AtomicTemp);
masm.store16(AtomicTemp, Address(dest, offset * 2));
break;
case SIZE32:
masm.load32(Address(src, offset * 4), AtomicTemp);
masm.store32(AtomicTemp, Address(dest, offset * 4));
break;
case SIZE64:
#if defined(JS_64BIT)
masm.load64(Address(src, offset * 8), AtomicTemp64);
masm.store64(AtomicTemp64, Address(dest, offset * 8));
break;
#else
MOZ_CRASH("64-bit atomic load/store not available on this platform");
#endif
default:
MOZ_CRASH("Unknown size");
}
offset += direction == CopyDir::DOWN ? 1 : -1;
}
GenEpilogue(masm);
return start;
}
static uint32_t GenCmpxchg(MacroAssembler& masm, Scalar::Type size,
Synchronization sync) {
ArgIterator iter;
uint32_t start = GenPrologue(masm, &iter);
GenGprArg(masm, MIRType::Pointer, &iter, AtomicPtrReg);
Address addr(AtomicPtrReg, 0);
switch (size) {
case SIZE8:
case SIZE16:
case SIZE32:
GenGprArg(masm, MIRType::Int32, &iter, AtomicValReg);
GenGprArg(masm, MIRType::Int32, &iter, AtomicVal2Reg);
masm.compareExchange(size, sync, addr, AtomicValReg, AtomicVal2Reg,
ReturnReg);
break;
case SIZE64:
GenGpr64Arg(masm, &iter, AtomicValReg64);
GenGpr64Arg(masm, &iter, AtomicVal2Reg64);
#if defined(JS_CODEGEN_X86)
MOZ_ASSERT(AtomicValReg64 == Register64(edx, eax));
MOZ_ASSERT(AtomicVal2Reg64 == Register64(ecx, ebx));
masm.lock_cmpxchg8b(edx, eax, ecx, ebx, Operand(addr));
MOZ_ASSERT(AtomicReturnReg64 == Register64(edx, eax));
#else
masm.compareExchange64(sync, addr, AtomicValReg64, AtomicVal2Reg64,
AtomicReturnReg64);
#endif
break;
default:
MOZ_CRASH("Unknown size");
}
GenEpilogue(masm);
return start;
}
static uint32_t GenExchange(MacroAssembler& masm, Scalar::Type size,
Synchronization sync) {
ArgIterator iter;
uint32_t start = GenPrologue(masm, &iter);
GenGprArg(masm, MIRType::Pointer, &iter, AtomicPtrReg);
Address addr(AtomicPtrReg, 0);
switch (size) {
case SIZE8:
case SIZE16:
case SIZE32:
GenGprArg(masm, MIRType::Int32, &iter, AtomicValReg);
masm.atomicExchange(size, sync, addr, AtomicValReg, ReturnReg);
break;
case SIZE64:
#if defined(JS_64BIT)
GenGpr64Arg(masm, &iter, AtomicValReg64);
masm.atomicExchange64(sync, addr, AtomicValReg64, AtomicReturnReg64);
break;
#else
MOZ_CRASH("64-bit atomic exchange not available on this platform");
#endif
default:
MOZ_CRASH("Unknown size");
}
GenEpilogue(masm);
return start;
}
static uint32_t GenFetchOp(MacroAssembler& masm, Scalar::Type size, AtomicOp op,
Synchronization sync) {
ArgIterator iter;
uint32_t start = GenPrologue(masm, &iter);
GenGprArg(masm, MIRType::Pointer, &iter, AtomicPtrReg);
Address addr(AtomicPtrReg, 0);
switch (size) {
case SIZE8:
case SIZE16:
case SIZE32: {
#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
Register tmp = op == AtomicFetchAddOp || op == AtomicFetchSubOp
? Register::Invalid()
: AtomicTemp;
#else
Register tmp = AtomicTemp;
#endif
GenGprArg(masm, MIRType::Int32, &iter, AtomicValReg);
masm.atomicFetchOp(size, sync, op, AtomicValReg, addr, tmp, ReturnReg);
break;
}
case SIZE64: {
#if defined(JS_64BIT)
# if defined(JS_CODEGEN_X64)
Register64 tmp = op == AtomicFetchAddOp || op == AtomicFetchSubOp
? Register64::Invalid()
: AtomicTemp64;
# else
Register64 tmp = AtomicTemp64;
# endif
GenGpr64Arg(masm, &iter, AtomicValReg64);
masm.atomicFetchOp64(sync, op, AtomicValReg64, addr, tmp,
AtomicReturnReg64);
break;
#else
MOZ_CRASH("64-bit atomic fetchOp not available on this platform");
#endif
}
default:
MOZ_CRASH("Unknown size");
}
GenEpilogue(masm);
return start;
}
namespace js {
namespace jit {
void (*AtomicFenceSeqCst)();
#ifndef JS_64BIT
void (*AtomicCompilerFence)();
#endif
uint8_t (*AtomicLoad8SeqCst)(const uint8_t* addr);
uint16_t (*AtomicLoad16SeqCst)(const uint16_t* addr);
uint32_t (*AtomicLoad32SeqCst)(const uint32_t* addr);
#ifdef JS_64BIT
uint64_t (*AtomicLoad64SeqCst)(const uint64_t* addr);
#endif
uint8_t (*AtomicLoad8Unsynchronized)(const uint8_t* addr);
uint16_t (*AtomicLoad16Unsynchronized)(const uint16_t* addr);
uint32_t (*AtomicLoad32Unsynchronized)(const uint32_t* addr);
#ifdef JS_64BIT
uint64_t (*AtomicLoad64Unsynchronized)(const uint64_t* addr);
#endif
uint8_t (*AtomicStore8SeqCst)(uint8_t* addr, uint8_t val);
uint16_t (*AtomicStore16SeqCst)(uint16_t* addr, uint16_t val);
uint32_t (*AtomicStore32SeqCst)(uint32_t* addr, uint32_t val);
#ifdef JS_64BIT
uint64_t (*AtomicStore64SeqCst)(uint64_t* addr, uint64_t val);
#endif
uint8_t (*AtomicStore8Unsynchronized)(uint8_t* addr, uint8_t val);
uint16_t (*AtomicStore16Unsynchronized)(uint16_t* addr, uint16_t val);
uint32_t (*AtomicStore32Unsynchronized)(uint32_t* addr, uint32_t val);
#ifdef JS_64BIT
uint64_t (*AtomicStore64Unsynchronized)(uint64_t* addr, uint64_t val);
#endif
static void (*AtomicCopyUnalignedBlockDownUnsynchronized)(uint8_t* dest,
const uint8_t* src);
static void (*AtomicCopyUnalignedBlockUpUnsynchronized)(uint8_t* dest,
const uint8_t* src);
static void (*AtomicCopyUnalignedWordDownUnsynchronized)(uint8_t* dest,
const uint8_t* src);
static void (*AtomicCopyUnalignedWordUpUnsynchronized)(uint8_t* dest,
const uint8_t* src);
static void (*AtomicCopyBlockDownUnsynchronized)(uint8_t* dest,
const uint8_t* src);
static void (*AtomicCopyBlockUpUnsynchronized)(uint8_t* dest,
const uint8_t* src);
static void (*AtomicCopyWordUnsynchronized)(uint8_t* dest, const uint8_t* src);
static void (*AtomicCopyByteUnsynchronized)(uint8_t* dest, const uint8_t* src);
uint8_t (*AtomicCmpXchg8SeqCst)(uint8_t* addr, uint8_t oldval, uint8_t newval);
uint16_t (*AtomicCmpXchg16SeqCst)(uint16_t* addr, uint16_t oldval,
uint16_t newval);
uint32_t (*AtomicCmpXchg32SeqCst)(uint32_t* addr, uint32_t oldval,
uint32_t newval);
uint64_t (*AtomicCmpXchg64SeqCst)(uint64_t* addr, uint64_t oldval,
uint64_t newval);
uint8_t (*AtomicExchange8SeqCst)(uint8_t* addr, uint8_t val);
uint16_t (*AtomicExchange16SeqCst)(uint16_t* addr, uint16_t val);
uint32_t (*AtomicExchange32SeqCst)(uint32_t* addr, uint32_t val);
#ifdef JS_64BIT
uint64_t (*AtomicExchange64SeqCst)(uint64_t* addr, uint64_t val);
#endif
uint8_t (*AtomicAdd8SeqCst)(uint8_t* addr, uint8_t val);
uint16_t (*AtomicAdd16SeqCst)(uint16_t* addr, uint16_t val);
uint32_t (*AtomicAdd32SeqCst)(uint32_t* addr, uint32_t val);
#ifdef JS_64BIT
uint64_t (*AtomicAdd64SeqCst)(uint64_t* addr, uint64_t val);
#endif
uint8_t (*AtomicAnd8SeqCst)(uint8_t* addr, uint8_t val);
uint16_t (*AtomicAnd16SeqCst)(uint16_t* addr, uint16_t val);
uint32_t (*AtomicAnd32SeqCst)(uint32_t* addr, uint32_t val);
#ifdef JS_64BIT
uint64_t (*AtomicAnd64SeqCst)(uint64_t* addr, uint64_t val);
#endif
uint8_t (*AtomicOr8SeqCst)(uint8_t* addr, uint8_t val);
uint16_t (*AtomicOr16SeqCst)(uint16_t* addr, uint16_t val);
uint32_t (*AtomicOr32SeqCst)(uint32_t* addr, uint32_t val);
#ifdef JS_64BIT
uint64_t (*AtomicOr64SeqCst)(uint64_t* addr, uint64_t val);
#endif
uint8_t (*AtomicXor8SeqCst)(uint8_t* addr, uint8_t val);
uint16_t (*AtomicXor16SeqCst)(uint16_t* addr, uint16_t val);
uint32_t (*AtomicXor32SeqCst)(uint32_t* addr, uint32_t val);
#ifdef JS_64BIT
uint64_t (*AtomicXor64SeqCst)(uint64_t* addr, uint64_t val);
#endif
static bool UnalignedAccessesAreOK() {
#ifdef DEBUG
const char* flag = getenv("JS_NO_UNALIGNED_MEMCPY");
if (flag && *flag == '1') return false;
#endif
#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
return true;
#elif defined(JS_CODEGEN_ARM)
return !HasAlignmentFault();
#elif defined(JS_CODEGEN_ARM64)
return true;
#else
# error "Unsupported platform"
#endif
}
void AtomicMemcpyDownUnsynchronized(uint8_t* dest, const uint8_t* src,
size_t nbytes) {
const uint8_t* lim = src + nbytes;
if (nbytes >= WORDSIZE) {
void (*copyBlock)(uint8_t * dest, const uint8_t* src);
void (*copyWord)(uint8_t * dest, const uint8_t* src);
if (((uintptr_t(dest) ^ uintptr_t(src)) & WORDMASK) == 0) {
const uint8_t* cutoff =
(const uint8_t*)JS_ROUNDUP(uintptr_t(src), WORDSIZE);
MOZ_ASSERT(cutoff <= lim); while (src < cutoff) {
AtomicCopyByteUnsynchronized(dest++, src++);
}
copyBlock = AtomicCopyBlockDownUnsynchronized;
copyWord = AtomicCopyWordUnsynchronized;
} else if (UnalignedAccessesAreOK()) {
copyBlock = AtomicCopyBlockDownUnsynchronized;
copyWord = AtomicCopyWordUnsynchronized;
} else {
copyBlock = AtomicCopyUnalignedBlockDownUnsynchronized;
copyWord = AtomicCopyUnalignedWordDownUnsynchronized;
}
const uint8_t* blocklim = src + ((lim - src) & ~BLOCKMASK);
while (src < blocklim) {
copyBlock(dest, src);
dest += BLOCKSIZE;
src += BLOCKSIZE;
}
const uint8_t* wordlim = src + ((lim - src) & ~WORDMASK);
while (src < wordlim) {
copyWord(dest, src);
dest += WORDSIZE;
src += WORDSIZE;
}
}
while (src < lim) {
AtomicCopyByteUnsynchronized(dest++, src++);
}
}
void AtomicMemcpyUpUnsynchronized(uint8_t* dest, const uint8_t* src,
size_t nbytes) {
const uint8_t* lim = src;
src += nbytes;
dest += nbytes;
if (nbytes >= WORDSIZE) {
void (*copyBlock)(uint8_t * dest, const uint8_t* src);
void (*copyWord)(uint8_t * dest, const uint8_t* src);
if (((uintptr_t(dest) ^ uintptr_t(src)) & WORDMASK) == 0) {
const uint8_t* cutoff = (const uint8_t*)(uintptr_t(src) & ~WORDMASK);
MOZ_ASSERT(cutoff >= lim); while (src > cutoff) {
AtomicCopyByteUnsynchronized(--dest, --src);
}
copyBlock = AtomicCopyBlockUpUnsynchronized;
copyWord = AtomicCopyWordUnsynchronized;
} else if (UnalignedAccessesAreOK()) {
copyBlock = AtomicCopyBlockUpUnsynchronized;
copyWord = AtomicCopyWordUnsynchronized;
} else {
copyBlock = AtomicCopyUnalignedBlockUpUnsynchronized;
copyWord = AtomicCopyUnalignedWordUpUnsynchronized;
}
const uint8_t* blocklim = src - ((src - lim) & ~BLOCKMASK);
while (src > blocklim) {
dest -= BLOCKSIZE;
src -= BLOCKSIZE;
copyBlock(dest, src);
}
const uint8_t* wordlim = src - ((src - lim) & ~WORDMASK);
while (src > wordlim) {
dest -= WORDSIZE;
src -= WORDSIZE;
copyWord(dest, src);
}
}
while (src > lim) {
AtomicCopyByteUnsynchronized(--dest, --src);
}
}
static uint8_t* codeSegment;
static uint32_t codeSegmentSize;
bool InitializeJittedAtomics() {
MOZ_ASSERT(!codeSegment);
LifoAlloc lifo(4096);
TempAllocator alloc(&lifo);
JitContext jcx(&alloc);
StackMacroAssembler masm;
uint32_t fenceSeqCst = GenFenceSeqCst(masm);
#ifndef JS_64BIT
uint32_t nop = GenNop(masm);
#endif
Synchronization Full = Synchronization::Full();
Synchronization None = Synchronization::None();
uint32_t load8SeqCst = GenLoad(masm, SIZE8, Full);
uint32_t load16SeqCst = GenLoad(masm, SIZE16, Full);
uint32_t load32SeqCst = GenLoad(masm, SIZE32, Full);
#ifdef JS_64BIT
uint32_t load64SeqCst = GenLoad(masm, SIZE64, Full);
#endif
uint32_t load8Unsynchronized = GenLoad(masm, SIZE8, None);
uint32_t load16Unsynchronized = GenLoad(masm, SIZE16, None);
uint32_t load32Unsynchronized = GenLoad(masm, SIZE32, None);
#ifdef JS_64BIT
uint32_t load64Unsynchronized = GenLoad(masm, SIZE64, None);
#endif
uint32_t store8SeqCst = GenStore(masm, SIZE8, Full);
uint32_t store16SeqCst = GenStore(masm, SIZE16, Full);
uint32_t store32SeqCst = GenStore(masm, SIZE32, Full);
#ifdef JS_64BIT
uint32_t store64SeqCst = GenStore(masm, SIZE64, Full);
#endif
uint32_t store8Unsynchronized = GenStore(masm, SIZE8, None);
uint32_t store16Unsynchronized = GenStore(masm, SIZE16, None);
uint32_t store32Unsynchronized = GenStore(masm, SIZE32, None);
#ifdef JS_64BIT
uint32_t store64Unsynchronized = GenStore(masm, SIZE64, None);
#endif
uint32_t copyUnalignedBlockDownUnsynchronized =
GenCopy(masm, SIZE8, BLOCKSIZE, CopyDir::DOWN);
uint32_t copyUnalignedBlockUpUnsynchronized =
GenCopy(masm, SIZE8, BLOCKSIZE, CopyDir::UP);
uint32_t copyUnalignedWordDownUnsynchronized =
GenCopy(masm, SIZE8, WORDSIZE, CopyDir::DOWN);
uint32_t copyUnalignedWordUpUnsynchronized =
GenCopy(masm, SIZE8, WORDSIZE, CopyDir::UP);
uint32_t copyBlockDownUnsynchronized =
GenCopy(masm, SIZEWORD, BLOCKSIZE / WORDSIZE, CopyDir::DOWN);
uint32_t copyBlockUpUnsynchronized =
GenCopy(masm, SIZEWORD, BLOCKSIZE / WORDSIZE, CopyDir::UP);
uint32_t copyWordUnsynchronized = GenCopy(masm, SIZEWORD, 1, CopyDir::DOWN);
uint32_t copyByteUnsynchronized = GenCopy(masm, SIZE8, 1, CopyDir::DOWN);
uint32_t cmpxchg8SeqCst = GenCmpxchg(masm, SIZE8, Full);
uint32_t cmpxchg16SeqCst = GenCmpxchg(masm, SIZE16, Full);
uint32_t cmpxchg32SeqCst = GenCmpxchg(masm, SIZE32, Full);
uint32_t cmpxchg64SeqCst = GenCmpxchg(masm, SIZE64, Full);
uint32_t exchange8SeqCst = GenExchange(masm, SIZE8, Full);
uint32_t exchange16SeqCst = GenExchange(masm, SIZE16, Full);
uint32_t exchange32SeqCst = GenExchange(masm, SIZE32, Full);
#ifdef JS_64BIT
uint32_t exchange64SeqCst = GenExchange(masm, SIZE64, Full);
#endif
uint32_t add8SeqCst = GenFetchOp(masm, SIZE8, AtomicFetchAddOp, Full);
uint32_t add16SeqCst = GenFetchOp(masm, SIZE16, AtomicFetchAddOp, Full);
uint32_t add32SeqCst = GenFetchOp(masm, SIZE32, AtomicFetchAddOp, Full);
#ifdef JS_64BIT
uint32_t add64SeqCst = GenFetchOp(masm, SIZE64, AtomicFetchAddOp, Full);
#endif
uint32_t and8SeqCst = GenFetchOp(masm, SIZE8, AtomicFetchAndOp, Full);
uint32_t and16SeqCst = GenFetchOp(masm, SIZE16, AtomicFetchAndOp, Full);
uint32_t and32SeqCst = GenFetchOp(masm, SIZE32, AtomicFetchAndOp, Full);
#ifdef JS_64BIT
uint32_t and64SeqCst = GenFetchOp(masm, SIZE64, AtomicFetchAndOp, Full);
#endif
uint32_t or8SeqCst = GenFetchOp(masm, SIZE8, AtomicFetchOrOp, Full);
uint32_t or16SeqCst = GenFetchOp(masm, SIZE16, AtomicFetchOrOp, Full);
uint32_t or32SeqCst = GenFetchOp(masm, SIZE32, AtomicFetchOrOp, Full);
#ifdef JS_64BIT
uint32_t or64SeqCst = GenFetchOp(masm, SIZE64, AtomicFetchOrOp, Full);
#endif
uint32_t xor8SeqCst = GenFetchOp(masm, SIZE8, AtomicFetchXorOp, Full);
uint32_t xor16SeqCst = GenFetchOp(masm, SIZE16, AtomicFetchXorOp, Full);
uint32_t xor32SeqCst = GenFetchOp(masm, SIZE32, AtomicFetchXorOp, Full);
#ifdef JS_64BIT
uint32_t xor64SeqCst = GenFetchOp(masm, SIZE64, AtomicFetchXorOp, Full);
#endif
masm.finish();
if (masm.oom()) {
return false;
}
uint32_t codeLength = masm.bytesNeeded();
size_t roundedCodeLength = JS_ROUNDUP(codeLength, ExecutableCodePageSize);
uint8_t* code = (uint8_t*)AllocateExecutableMemory(
roundedCodeLength, ProtectionSetting::Writable,
MemCheckKind::MakeUndefined);
if (!code) {
return false;
}
memset(code + codeLength, 0, roundedCodeLength - codeLength);
masm.executableCopy(code, false);
ExecutableAllocator::cacheFlush(code, roundedCodeLength);
if (!ExecutableAllocator::makeExecutable(code, roundedCodeLength)) {
DeallocateExecutableMemory(code, roundedCodeLength);
return false;
}
AtomicFenceSeqCst = (void (*)())(code + fenceSeqCst);
#ifndef JS_64BIT
AtomicCompilerFence = (void (*)())(code + nop);
#endif
AtomicLoad8SeqCst = (uint8_t(*)(const uint8_t* addr))(code + load8SeqCst);
AtomicLoad16SeqCst = (uint16_t(*)(const uint16_t* addr))(code + load16SeqCst);
AtomicLoad32SeqCst = (uint32_t(*)(const uint32_t* addr))(code + load32SeqCst);
#ifdef JS_64BIT
AtomicLoad64SeqCst = (uint64_t(*)(const uint64_t* addr))(code + load64SeqCst);
#endif
AtomicLoad8Unsynchronized =
(uint8_t(*)(const uint8_t* addr))(code + load8Unsynchronized);
AtomicLoad16Unsynchronized =
(uint16_t(*)(const uint16_t* addr))(code + load16Unsynchronized);
AtomicLoad32Unsynchronized =
(uint32_t(*)(const uint32_t* addr))(code + load32Unsynchronized);
#ifdef JS_64BIT
AtomicLoad64Unsynchronized =
(uint64_t(*)(const uint64_t* addr))(code + load64Unsynchronized);
#endif
AtomicStore8SeqCst =
(uint8_t(*)(uint8_t * addr, uint8_t val))(code + store8SeqCst);
AtomicStore16SeqCst =
(uint16_t(*)(uint16_t * addr, uint16_t val))(code + store16SeqCst);
AtomicStore32SeqCst =
(uint32_t(*)(uint32_t * addr, uint32_t val))(code + store32SeqCst);
#ifdef JS_64BIT
AtomicStore64SeqCst =
(uint64_t(*)(uint64_t * addr, uint64_t val))(code + store64SeqCst);
#endif
AtomicStore8Unsynchronized =
(uint8_t(*)(uint8_t * addr, uint8_t val))(code + store8Unsynchronized);
AtomicStore16Unsynchronized = (uint16_t(*)(uint16_t * addr, uint16_t val))(
code + store16Unsynchronized);
AtomicStore32Unsynchronized = (uint32_t(*)(uint32_t * addr, uint32_t val))(
code + store32Unsynchronized);
#ifdef JS_64BIT
AtomicStore64Unsynchronized = (uint64_t(*)(uint64_t * addr, uint64_t val))(
code + store64Unsynchronized);
#endif
AtomicCopyUnalignedBlockDownUnsynchronized =
(void (*)(uint8_t * dest, const uint8_t* src))(
code + copyUnalignedBlockDownUnsynchronized);
AtomicCopyUnalignedBlockUpUnsynchronized =
(void (*)(uint8_t * dest, const uint8_t* src))(
code + copyUnalignedBlockUpUnsynchronized);
AtomicCopyUnalignedWordDownUnsynchronized =
(void (*)(uint8_t * dest, const uint8_t* src))(
code + copyUnalignedWordDownUnsynchronized);
AtomicCopyUnalignedWordUpUnsynchronized =
(void (*)(uint8_t * dest, const uint8_t* src))(
code + copyUnalignedWordUpUnsynchronized);
AtomicCopyBlockDownUnsynchronized = (void (*)(
uint8_t * dest, const uint8_t* src))(code + copyBlockDownUnsynchronized);
AtomicCopyBlockUpUnsynchronized = (void (*)(
uint8_t * dest, const uint8_t* src))(code + copyBlockUpUnsynchronized);
AtomicCopyWordUnsynchronized = (void (*)(uint8_t * dest, const uint8_t* src))(
code + copyWordUnsynchronized);
AtomicCopyByteUnsynchronized = (void (*)(uint8_t * dest, const uint8_t* src))(
code + copyByteUnsynchronized);
AtomicCmpXchg8SeqCst = (uint8_t(*)(uint8_t * addr, uint8_t oldval,
uint8_t newval))(code + cmpxchg8SeqCst);
AtomicCmpXchg16SeqCst =
(uint16_t(*)(uint16_t * addr, uint16_t oldval, uint16_t newval))(
code + cmpxchg16SeqCst);
AtomicCmpXchg32SeqCst =
(uint32_t(*)(uint32_t * addr, uint32_t oldval, uint32_t newval))(
code + cmpxchg32SeqCst);
AtomicCmpXchg64SeqCst =
(uint64_t(*)(uint64_t * addr, uint64_t oldval, uint64_t newval))(
code + cmpxchg64SeqCst);
AtomicExchange8SeqCst =
(uint8_t(*)(uint8_t * addr, uint8_t val))(code + exchange8SeqCst);
AtomicExchange16SeqCst =
(uint16_t(*)(uint16_t * addr, uint16_t val))(code + exchange16SeqCst);
AtomicExchange32SeqCst =
(uint32_t(*)(uint32_t * addr, uint32_t val))(code + exchange32SeqCst);
#ifdef JS_64BIT
AtomicExchange64SeqCst =
(uint64_t(*)(uint64_t * addr, uint64_t val))(code + exchange64SeqCst);
#endif
AtomicAdd8SeqCst =
(uint8_t(*)(uint8_t * addr, uint8_t val))(code + add8SeqCst);
AtomicAdd16SeqCst =
(uint16_t(*)(uint16_t * addr, uint16_t val))(code + add16SeqCst);
AtomicAdd32SeqCst =
(uint32_t(*)(uint32_t * addr, uint32_t val))(code + add32SeqCst);
#ifdef JS_64BIT
AtomicAdd64SeqCst =
(uint64_t(*)(uint64_t * addr, uint64_t val))(code + add64SeqCst);
#endif
AtomicAnd8SeqCst =
(uint8_t(*)(uint8_t * addr, uint8_t val))(code + and8SeqCst);
AtomicAnd16SeqCst =
(uint16_t(*)(uint16_t * addr, uint16_t val))(code + and16SeqCst);
AtomicAnd32SeqCst =
(uint32_t(*)(uint32_t * addr, uint32_t val))(code + and32SeqCst);
#ifdef JS_64BIT
AtomicAnd64SeqCst =
(uint64_t(*)(uint64_t * addr, uint64_t val))(code + and64SeqCst);
#endif
AtomicOr8SeqCst = (uint8_t(*)(uint8_t * addr, uint8_t val))(code + or8SeqCst);
AtomicOr16SeqCst =
(uint16_t(*)(uint16_t * addr, uint16_t val))(code + or16SeqCst);
AtomicOr32SeqCst =
(uint32_t(*)(uint32_t * addr, uint32_t val))(code + or32SeqCst);
#ifdef JS_64BIT
AtomicOr64SeqCst =
(uint64_t(*)(uint64_t * addr, uint64_t val))(code + or64SeqCst);
#endif
AtomicXor8SeqCst =
(uint8_t(*)(uint8_t * addr, uint8_t val))(code + xor8SeqCst);
AtomicXor16SeqCst =
(uint16_t(*)(uint16_t * addr, uint16_t val))(code + xor16SeqCst);
AtomicXor32SeqCst =
(uint32_t(*)(uint32_t * addr, uint32_t val))(code + xor32SeqCst);
#ifdef JS_64BIT
AtomicXor64SeqCst =
(uint64_t(*)(uint64_t * addr, uint64_t val))(code + xor64SeqCst);
#endif
codeSegment = code;
codeSegmentSize = roundedCodeLength;
return true;
}
void ShutDownJittedAtomics() {
MOZ_ASSERT(codeSegment);
DeallocateExecutableMemory(codeSegment, codeSegmentSize);
codeSegment = nullptr;
codeSegmentSize = 0;
}
} }