--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -3424,40 +3424,16 @@ class BaseCompiler final : public BaseCo
}
void returnCleanup(bool popStack) {
if (popStack)
fr.popStackBeforeBranch(controlOutermost().stackHeight);
masm.jump(&returnLabel_);
}
- void pop2xI32ForIntMulDiv(RegI32* r0, RegI32* r1) {
-#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
- // srcDest must be eax, and edx will be clobbered.
- need2xI32(specific.eax, specific.edx);
- *r1 = popI32();
- *r0 = popI32ToSpecific(specific.eax);
- freeI32(specific.edx);
-#else
- pop2xI32(r0, r1);
-#endif
- }
-
- void pop2xI64ForIntDiv(RegI64* r0, RegI64* r1) {
-#ifdef JS_CODEGEN_X64
- // srcDest must be rax, and rdx will be clobbered.
- need2xI64(specific.rax, specific.rdx);
- *r1 = popI64();
- *r0 = popI64ToSpecific(specific.rax);
- freeI64(specific.rdx);
-#else
- pop2xI64(r0, r1);
-#endif
- }
-
void checkDivideByZeroI32(RegI32 rhs, RegI32 srcDest, Label* done) {
masm.branchTest32(Assembler::Zero, rhs, rhs, trap(Trap::IntegerDivideByZero));
}
void checkDivideByZeroI64(RegI64 r) {
ScratchI32 scratch(*this);
masm.branchTest64(Assembler::Zero, r, r, scratch, trap(Trap::IntegerDivideByZero));
}
@@ -3484,95 +3460,75 @@ class BaseCompiler final : public BaseCo
masm.jump(done);
} else {
masm.jump(trap(Trap::IntegerOverflow));
}
masm.bind(¬min);
}
#ifndef RABALDR_INT_DIV_I64_CALLOUT
- void quotientI64(RegI64 rhs, RegI64 srcDest, IsUnsigned isUnsigned,
+ void quotientI64(RegI64 rhs, RegI64 srcDest, RegI64 reserved, IsUnsigned isUnsigned,
bool isConst, int64_t c)
{
Label done;
if (!isConst || c == 0)
checkDivideByZeroI64(rhs);
if (!isUnsigned && (!isConst || c == -1))
checkDivideSignedOverflowI64(rhs, srcDest, &done, ZeroOnOverflow(false));
# if defined(JS_CODEGEN_X64)
// The caller must set up the following situation.
MOZ_ASSERT(srcDest.reg == rax);
- MOZ_ASSERT(isAvailableI64(specific.rdx));
+ MOZ_ASSERT(reserved == specific.rdx);
if (isUnsigned) {
masm.xorq(rdx, rdx);
masm.udivq(rhs.reg);
} else {
masm.cqo();
masm.idivq(rhs.reg);
}
# else
MOZ_CRASH("BaseCompiler platform hook: quotientI64");
# endif
masm.bind(&done);
}
- void remainderI64(RegI64 rhs, RegI64 srcDest, IsUnsigned isUnsigned,
+ void remainderI64(RegI64 rhs, RegI64 srcDest, RegI64 reserved, IsUnsigned isUnsigned,
bool isConst, int64_t c)
{
Label done;
if (!isConst || c == 0)
checkDivideByZeroI64(rhs);
if (!isUnsigned && (!isConst || c == -1))
checkDivideSignedOverflowI64(rhs, srcDest, &done, ZeroOnOverflow(true));
# if defined(JS_CODEGEN_X64)
// The caller must set up the following situation.
MOZ_ASSERT(srcDest.reg == rax);
- MOZ_ASSERT(isAvailableI64(specific.rdx));
+ MOZ_ASSERT(reserved == specific.rdx);
if (isUnsigned) {
masm.xorq(rdx, rdx);
masm.udivq(rhs.reg);
} else {
masm.cqo();
masm.idivq(rhs.reg);
}
masm.movq(rdx, rax);
# else
MOZ_CRASH("BaseCompiler platform hook: remainderI64");
# endif
masm.bind(&done);
}
#endif // RABALDR_INT_DIV_I64_CALLOUT
- void pop2xI32ForShiftOrRotate(RegI32* r0, RegI32* r1) {
-#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
- *r1 = popI32(specific.ecx);
- *r0 = popI32();
-#else
- pop2xI32(r0, r1);
-#endif
- }
-
- void pop2xI64ForShiftOrRotate(RegI64* r0, RegI64* r1) {
-#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
- needI32(specific.ecx);
- *r1 = widenI32(specific.ecx);
- *r1 = popI64ToSpecific(*r1);
- *r0 = popI64();
-#else
- pop2xI64(r0, r1);
-#endif
- }
-
RegI32 needRotate64Temp() {
#if defined(JS_CODEGEN_X86)
return needI32();
#elif defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM)
return RegI32::Invalid();
#else
MOZ_CRASH("BaseCompiler platform hook: needRotate64Temp");
#endif
@@ -3599,39 +3555,16 @@ class BaseCompiler final : public BaseCo
return AssemblerX86Shared::HasPOPCNT() ? RegI32::Invalid() : needI32();
#elif defined(JS_CODEGEN_ARM)
return needI32();
#else
MOZ_CRASH("BaseCompiler platform hook: needPopcnt64Temp");
#endif
}
- RegI64 popI32ForSignExtendI64() {
-#if defined(JS_CODEGEN_X86)
- need2xI32(specific.edx, specific.eax);
- RegI32 r0 = popI32ToSpecific(specific.eax);
- RegI64 x0 = specific.edx_eax;
- (void)r0; // x0 is the widening of r0
-#else
- RegI32 r0 = popI32();
- RegI64 x0 = widenI32(r0);
-#endif
- return x0;
- }
-
- RegI64 popI64ForSignExtendI64() {
-#if defined(JS_CODEGEN_X86)
- need2xI32(specific.edx, specific.eax);
- // Low on top, high underneath
- return popI64ToSpecific(specific.edx_eax);
-#else
- return popI64();
-#endif
- }
-
class OutOfLineTruncateF32OrF64ToI32 : public OutOfLineCode
{
AnyReg src;
RegI32 dest;
bool isUnsigned;
BytecodeOffset off;
public:
@@ -4205,61 +4138,16 @@ class BaseCompiler final : public BaseCo
#else
# define ATOMIC_PTR(name, access, tls, ptr) \
MOZ_CRASH("BaseCompiler platform hook: address computation"); \
Address srcAddr
#endif
- void xchg64(MemoryAccessDesc* access, ValType type, WantResult wantResult)
- {
-#if defined(JS_CODEGEN_X86)
- RegI64 rd = specific.edx_eax;
- needI64(rd);
- needI32(specific.ecx);
- // Claim scratch after the need() calls because they may need it to
- // sync.
- ScratchEBX scratch(*this);
- RegI64 rv = specific.ecx_ebx;
-#elif defined(JS_CODEGEN_ARM)
- RegI64 rv = needI64Pair();
- RegI64 rd = needI64Pair();
-#else
- RegI64 rv, rd;
- MOZ_CRASH("BaseCompiler porting interface: xchg64");
-#endif
-
- popI64ToSpecific(rv);
-
- AccessCheck check;
- RegI32 rp = popMemoryAccess(access, &check);
- RegI32 tls = maybeLoadTlsForAccess(check);
- prepareMemoryAccess(access, &check, tls, rp);
- ATOMIC_PTR(srcAddr, access, tls, rp);
-
- masm.atomicExchange64(srcAddr, rv, rd);
-
- if (wantResult)
- pushI64(rd);
- else
- freeI64(rd);
-
- maybeFreeI32(tls);
- freeI32(rp);
-
-#if defined(JS_CODEGEN_X86)
- freeI32(specific.ecx);
-#elif defined(JS_CODEGEN_ARM)
- freeI64(rv);
-#else
- MOZ_CRASH("BaseCompiler porting interface: xchg64");
-#endif
- }
-
RegI32 needAtomicRMWTemp(AtomicOp op, MemoryAccessDesc* access) {
#if defined(JS_CODEGEN_X86)
// Handled specially in atomicRMW
if (access->byteSize() == 1)
return RegI32::Invalid();
#endif
#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
if (op != AtomicFetchAddOp && op != AtomicFetchSubOp)
@@ -4422,23 +4310,137 @@ class BaseCompiler final : public BaseCo
masm.atomicExchange32(srcAddr, rv, rd);
break;
default:
MOZ_CRASH("Bad type for atomic operation");
}
}
////////////////////////////////////////////////////////////
-
- // Generally speaking, ABOVE this point there should be no value
- // stack manipulation (calls to popI32 etc).
-
+ //
+ // Generally speaking, ABOVE this point there should be no
+ // value stack manipulation (calls to popI32 etc).
+ //
+ ////////////////////////////////////////////////////////////
+
+ ////////////////////////////////////////////////////////////
+ //
+ // Platform-specific popping and register targeting.
+ //
+ // These fall into two groups, popping methods for simple needs, and RAII
+ // wrappers for more complex behavior.
+
+ // The simple popping methods pop values into targeted registers; the caller
+ // can free registers using standard functions. These are always called
+ // popXForY where X says something about types and Y something about the
+ // operation being targeted.
+
+ void pop2xI32ForMulDivI32(RegI32* r0, RegI32* r1, RegI32* reserved) {
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
+ // r0 must be eax, and edx will be clobbered.
+ need2xI32(specific.eax, specific.edx);
+ *r1 = popI32();
+ *r0 = popI32ToSpecific(specific.eax);
+ *reserved = specific.edx;
+#else
+ pop2xI32(r0, r1);
+#endif
+ }
+
+ void pop2xI64ForMulI64(RegI64* r0, RegI64* r1, RegI32* temp, RegI64* reserved) {
+#if defined(JS_CODEGEN_X64)
+ // r0 must be rax, and rdx will be clobbered.
+ need2xI64(specific.rax, specific.rdx);
+ *r1 = popI64();
+ *r0 = popI64ToSpecific(specific.rax);
+ *reserved = specific.rdx;
+#elif defined(JS_CODEGEN_X86)
+ // As for x64, though edx is part of r0.
+ need2xI32(specific.eax, specific.edx);
+ *r1 = popI64();
+ *r0 = popI64ToSpecific(specific.edx_eax);
+ *temp = needI32();
+#else
+ pop2xI64(r0, r1);
+ *temp = needI32();
+#endif
+ }
+
+ void pop2xI64ForDivI64(RegI64* r0, RegI64* r1, RegI64* reserved) {
+#ifdef JS_CODEGEN_X64
+ // r0 must be rax, and rdx will be clobbered.
+ need2xI64(specific.rax, specific.rdx);
+ *r1 = popI64();
+ *r0 = popI64ToSpecific(specific.rax);
+ *reserved = specific.rdx;
+#else
+ pop2xI64(r0, r1);
+#endif
+ }
+
+ void pop2xI32ForShiftOrRotate(RegI32* r0, RegI32* r1) {
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
+ // r1 must be ecx for a variable shift.
+ *r1 = popI32(specific.ecx);
+ *r0 = popI32();
+#else
+ pop2xI32(r0, r1);
+#endif
+ }
+
+ void pop2xI64ForShiftOrRotate(RegI64* r0, RegI64* r1) {
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
+ // r1 must be ecx for a variable shift.
+ needI32(specific.ecx);
+ *r1 = popI64ToSpecific(widenI32(specific.ecx));
+ *r0 = popI64();
+#else
+ pop2xI64(r0, r1);
+#endif
+ }
+
+ void popI32ForSignExtendI64(RegI64* r0) {
+#if defined(JS_CODEGEN_X86)
+ // r0 must be edx:eax for cdq
+ need2xI32(specific.edx, specific.eax);
+ *r0 = specific.edx_eax;
+ popI32ToSpecific(specific.eax);
+#else
+ *r0 = widenI32(popI32());
+#endif
+ }
+
+ void popI64ForSignExtendI64(RegI64* r0) {
+#if defined(JS_CODEGEN_X86)
+ // r0 must be edx:eax for cdq
+ need2xI32(specific.edx, specific.eax);
+ // Low on top, high underneath
+ *r0 = popI64ToSpecific(specific.edx_eax);
+#else
+ *r0 = popI64();
+#endif
+ }
+
+ // The RAII wrappers are used because we sometimes have to free partial
+ // registers, as when part of a register is the scratch register that has
+ // been temporarily used, or not free a register at all, as when the
+ // register is the same as the destination register (but only on some
+ // platforms, not on all). These are called PopX{32,64}Regs where X is the
+ // operation being targeted.
+
+ // (To be implemented)
+
+ ////////////////////////////////////////////////////////////
+ //
// Generally speaking, BELOW this point there should be no
- // platform dependencies. We make an exception for x86 register
- // targeting, which is not too hard to keep clean.
+ // platform dependencies. We make very occasional exceptions
+ // when it doesn't become messy and further abstraction is
+ // not desirable.
+ //
+ ////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
//
// Sundry wrappers.
void pop2xI32(RegI32* r0, RegI32* r1) {
*r1 = popI32();
*r0 = popI32();
@@ -4805,16 +4807,19 @@ class BaseCompiler final : public BaseCo
MOZ_MUST_USE bool emitAtomicCmpXchg(ValType type, Scalar::Type viewType);
MOZ_MUST_USE bool emitAtomicLoad(ValType type, Scalar::Type viewType);
MOZ_MUST_USE bool emitAtomicRMW(ValType type, Scalar::Type viewType, AtomicOp op);
MOZ_MUST_USE bool emitAtomicStore(ValType type, Scalar::Type viewType);
MOZ_MUST_USE bool emitWait(ValType type, uint32_t byteSize);
MOZ_MUST_USE bool emitWake();
MOZ_MUST_USE bool emitAtomicXchg(ValType type, Scalar::Type viewType);
+#ifndef JS_64BIT
+ void emitAtomicXchg64(MemoryAccessDesc* access, ValType type, WantResult wantResult);
+#endif
};
void
BaseCompiler::emitAddI32()
{
int32_t c;
if (popConstI32(&c)) {
RegI32 r = popI32();
@@ -4918,44 +4923,32 @@ BaseCompiler::emitSubtractF64()
masm.subDouble(r1, r0);
freeF64(r1);
pushF64(r0);
}
void
BaseCompiler::emitMultiplyI32()
{
- RegI32 r0, r1;
- pop2xI32ForIntMulDiv(&r0, &r1);
+ RegI32 r0, r1, reserved;
+ pop2xI32ForMulDivI32(&r0, &r1, &reserved);
masm.mul32(r1, r0);
+ maybeFreeI32(reserved);
freeI32(r1);
pushI32(r0);
}
void
BaseCompiler::emitMultiplyI64()
{
- RegI64 r0, r1;
+ RegI64 r0, r1, reserved;
RegI32 temp;
-#if defined(JS_CODEGEN_X64)
- // srcDest must be rax, and rdx will be clobbered.
- need2xI64(specific.rax, specific.rdx);
- r1 = popI64();
- r0 = popI64ToSpecific(specific.rax);
- freeI64(specific.rdx);
-#elif defined(JS_CODEGEN_X86)
- need2xI32(specific.eax, specific.edx);
- r1 = popI64();
- r0 = popI64ToSpecific(specific.edx_eax);
- temp = needI32();
-#else
- pop2xI64(&r0, &r1);
- temp = needI32();
-#endif
+ pop2xI64ForMulI64(&r0, &r1, &temp, &reserved);
masm.mul64(r1, r0, temp);
+ maybeFreeI64(reserved);
maybeFreeI32(temp);
freeI64(r1);
pushI64(r0);
}
void
BaseCompiler::emitMultiplyF32()
{
@@ -4989,27 +4982,28 @@ BaseCompiler::emitQuotientI32()
masm.add32(Imm32(c-1), r);
masm.bind(&positive);
masm.rshift32Arithmetic(Imm32(power & 31), r);
pushI32(r);
}
} else {
bool isConst = peekConstI32(&c);
- RegI32 r0, r1;
- pop2xI32ForIntMulDiv(&r0, &r1);
+ RegI32 r0, r1, reserved;
+ pop2xI32ForMulDivI32(&r0, &r1, &reserved);
Label done;
if (!isConst || c == 0)
checkDivideByZeroI32(r1, r0, &done);
if (!isConst || c == -1)
checkDivideSignedOverflowI32(r1, r0, &done, ZeroOnOverflow(false));
masm.quotient32(r1, r0, IsUnsigned(false));
masm.bind(&done);
+ maybeFreeI32(reserved);
freeI32(r1);
pushI32(r0);
}
}
void
BaseCompiler::emitQuotientU32()
{
@@ -5018,25 +5012,26 @@ BaseCompiler::emitQuotientU32()
if (popConstPositivePowerOfTwoI32(&c, &power, 0)) {
if (power != 0) {
RegI32 r = popI32();
masm.rshift32(Imm32(power & 31), r);
pushI32(r);
}
} else {
bool isConst = peekConstI32(&c);
- RegI32 r0, r1;
- pop2xI32ForIntMulDiv(&r0, &r1);
+ RegI32 r0, r1, reserved;
+ pop2xI32ForMulDivI32(&r0, &r1, &reserved);
Label done;
if (!isConst || c == 0)
checkDivideByZeroI32(r1, r0, &done);
masm.quotient32(r1, r0, IsUnsigned(true));
masm.bind(&done);
+ maybeFreeI32(reserved);
freeI32(r1);
pushI32(r0);
}
}
void
BaseCompiler::emitRemainderI32()
{
@@ -5055,52 +5050,54 @@ BaseCompiler::emitRemainderI32()
masm.rshift32Arithmetic(Imm32(power & 31), temp);
masm.lshift32(Imm32(power & 31), temp);
masm.sub32(temp, r);
freeI32(temp);
pushI32(r);
} else {
bool isConst = peekConstI32(&c);
- RegI32 r0, r1;
- pop2xI32ForIntMulDiv(&r0, &r1);
+ RegI32 r0, r1, reserved;
+ pop2xI32ForMulDivI32(&r0, &r1, &reserved);
Label done;
if (!isConst || c == 0)
checkDivideByZeroI32(r1, r0, &done);
if (!isConst || c == -1)
checkDivideSignedOverflowI32(r1, r0, &done, ZeroOnOverflow(true));
masm.remainder32(r1, r0, IsUnsigned(false));
masm.bind(&done);
+ maybeFreeI32(reserved);
freeI32(r1);
pushI32(r0);
}
}
void
BaseCompiler::emitRemainderU32()
{
int32_t c;
uint_fast8_t power;
if (popConstPositivePowerOfTwoI32(&c, &power, 1)) {
RegI32 r = popI32();
masm.and32(Imm32(c-1), r);
pushI32(r);
} else {
bool isConst = peekConstI32(&c);
- RegI32 r0, r1;
- pop2xI32ForIntMulDiv(&r0, &r1);
+ RegI32 r0, r1, reserved;
+ pop2xI32ForMulDivI32(&r0, &r1, &reserved);
Label done;
if (!isConst || c == 0)
checkDivideByZeroI32(r1, r0, &done);
masm.remainder32(r1, r0, IsUnsigned(true));
masm.bind(&done);
+ maybeFreeI32(reserved);
freeI32(r1);
pushI32(r0);
}
}
#ifndef RABALDR_INT_DIV_I64_CALLOUT
void
BaseCompiler::emitQuotientI64()
@@ -5117,19 +5114,20 @@ BaseCompiler::emitQuotientI64()
masm.add64(Imm64(c-1), r);
masm.bind(&positive);
masm.rshift64Arithmetic(Imm32(power & 63), r);
pushI64(r);
}
} else {
bool isConst = peekConstI64(&c);
- RegI64 r0, r1;
- pop2xI64ForIntDiv(&r0, &r1);
- quotientI64(r1, r0, IsUnsigned(false), isConst, c);
+ RegI64 r0, r1, reserved;
+ pop2xI64ForDivI64(&r0, &r1, &reserved);
+ quotientI64(r1, r0, reserved, IsUnsigned(false), isConst, c);
+ maybeFreeI64(reserved);
freeI64(r1);
pushI64(r0);
}
# else
MOZ_CRASH("BaseCompiler platform hook: emitQuotientI64");
# endif
}
@@ -5142,19 +5140,20 @@ BaseCompiler::emitQuotientU64()
if (popConstPositivePowerOfTwoI64(&c, &power, 0)) {
if (power != 0) {
RegI64 r = popI64();
masm.rshift64(Imm32(power & 63), r);
pushI64(r);
}
} else {
bool isConst = peekConstI64(&c);
- RegI64 r0, r1;
- pop2xI64ForIntDiv(&r0, &r1);
- quotientI64(r1, r0, IsUnsigned(true), isConst, c);
+ RegI64 r0, r1, reserved;
+ pop2xI64ForDivI64(&r0, &r1, &reserved);
+ quotientI64(r1, r0, reserved, IsUnsigned(true), isConst, c);
+ maybeFreeI64(reserved);
freeI64(r1);
pushI64(r0);
}
# else
MOZ_CRASH("BaseCompiler platform hook: emitQuotientU64");
# endif
}
@@ -5177,19 +5176,20 @@ BaseCompiler::emitRemainderI64()
masm.rshift64Arithmetic(Imm32(power & 63), temp);
masm.lshift64(Imm32(power & 63), temp);
masm.sub64(temp, r);
freeI64(temp);
pushI64(r);
} else {
bool isConst = peekConstI64(&c);
- RegI64 r0, r1;
- pop2xI64ForIntDiv(&r0, &r1);
- remainderI64(r1, r0, IsUnsigned(false), isConst, c);
+ RegI64 r0, r1, reserved;
+ pop2xI64ForDivI64(&r0, &r1, &reserved);
+ remainderI64(r1, r0, reserved, IsUnsigned(false), isConst, c);
+ maybeFreeI64(reserved);
freeI64(r1);
pushI64(r0);
}
# else
MOZ_CRASH("BaseCompiler platform hook: emitRemainderI64");
# endif
}
@@ -5200,19 +5200,20 @@ BaseCompiler::emitRemainderU64()
int64_t c;
uint_fast8_t power;
if (popConstPositivePowerOfTwoI64(&c, &power, 1)) {
RegI64 r = popI64();
masm.and64(Imm64(c-1), r);
pushI64(r);
} else {
bool isConst = peekConstI64(&c);
- RegI64 r0, r1;
- pop2xI64ForIntDiv(&r0, &r1);
- remainderI64(r1, r0, IsUnsigned(true), isConst, c);
+ RegI64 r0, r1, reserved;
+ pop2xI64ForDivI64(&r0, &r1, &reserved);
+ remainderI64(r1, r0, reserved, IsUnsigned(true), isConst, c);
+ maybeFreeI64(reserved);
freeI64(r1);
pushI64(r0);
}
# else
MOZ_CRASH("BaseCompiler platform hook: emitRemainderU64");
# endif
}
#endif // RABALDR_INT_DIV_I64_CALLOUT
@@ -5831,41 +5832,45 @@ BaseCompiler::emitExtendI32_16()
RegI32 r = popI32();
masm.move16SignExtend(r, r);
pushI32(r);
}
void
BaseCompiler::emitExtendI64_8()
{
- RegI64 r = popI64ForSignExtendI64();
+ RegI64 r;
+ popI64ForSignExtendI64(&r);
masm.move8To64SignExtend(lowPart(r), r);
pushI64(r);
}
void
BaseCompiler::emitExtendI64_16()
{
- RegI64 r = popI64ForSignExtendI64();
+ RegI64 r;
+ popI64ForSignExtendI64(&r);
masm.move16To64SignExtend(lowPart(r), r);
pushI64(r);
}
void
BaseCompiler::emitExtendI64_32()
{
- RegI64 x0 = popI64ForSignExtendI64();
- masm.move32To64SignExtend(lowPart(x0), x0);
- pushI64(x0);
+ RegI64 r;
+ popI64ForSignExtendI64(&r);
+ masm.move32To64SignExtend(lowPart(r), r);
+ pushI64(r);
}
void
BaseCompiler::emitExtendI32ToI64()
{
- RegI64 x0 = popI32ForSignExtendI64();
+ RegI64 x0;
+ popI32ForSignExtendI64(&x0);
masm.move32To64SignExtend(lowPart(x0), x0);
pushI64(x0);
}
void
BaseCompiler::emitExtendU32ToI64()
{
RegI32 r0 = popI32();
@@ -8030,17 +8035,17 @@ BaseCompiler::emitAtomicStore(ValType ty
if (Scalar::byteSize(viewType) <= sizeof(void*))
return storeCommon(&access, type);
MOZ_ASSERT(type == ValType::I64 && Scalar::byteSize(viewType) == 8);
#ifdef JS_64BIT
MOZ_CRASH("Should not happen");
#else
- xchg64(&access, type, WantResult(false));
+ emitAtomicXchg64(&access, type, WantResult(false));
#endif
return true;
}
bool
BaseCompiler::emitAtomicXchg(ValType type, Scalar::Type viewType)
{
@@ -8099,22 +8104,70 @@ BaseCompiler::emitAtomicXchg(ValType typ
masm.atomicExchange64(srcAddr, rv, rd);
pushI64(rd);
maybeFreeI32(tls);
freeI32(rp);
if (rv != rd)
freeI64(rv);
#else
- xchg64(&access, type, WantResult(true));
+ emitAtomicXchg64(&access, type, WantResult(true));
#endif
return true;
}
+#ifndef JS_64BIT
+void
+BaseCompiler::emitAtomicXchg64(MemoryAccessDesc* access, ValType type, WantResult wantResult)
+{
+# if defined(JS_CODEGEN_X86)
+ RegI64 rd = specific.edx_eax;
+ needI64(rd);
+ needI32(specific.ecx);
+ // Claim scratch after the need() calls because they may need it to
+ // sync.
+ ScratchEBX scratch(*this);
+ RegI64 rv = specific.ecx_ebx;
+# elif defined(JS_CODEGEN_ARM)
+ RegI64 rv = needI64Pair();
+ RegI64 rd = needI64Pair();
+# else
+ RegI64 rv, rd;
+ MOZ_CRASH("BaseCompiler porting interface: xchg64");
+# endif
+
+ popI64ToSpecific(rv);
+
+ AccessCheck check;
+ RegI32 rp = popMemoryAccess(access, &check);
+ RegI32 tls = maybeLoadTlsForAccess(check);
+ prepareMemoryAccess(access, &check, tls, rp);
+ ATOMIC_PTR(srcAddr, access, tls, rp);
+
+ masm.atomicExchange64(srcAddr, rv, rd);
+
+ if (wantResult)
+ pushI64(rd);
+ else
+ freeI64(rd);
+
+ maybeFreeI32(tls);
+ freeI32(rp);
+
+# if defined(JS_CODEGEN_X86)
+ freeI32(specific.ecx);
+# elif defined(JS_CODEGEN_ARM)
+ freeI64(rv);
+# else
+ MOZ_CRASH("BaseCompiler porting interface: xchg64");
+# endif
+}
+#endif
+
bool
BaseCompiler::emitWait(ValType type, uint32_t byteSize)
{
uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
Nothing nothing;
LinearMemoryAddress<Nothing> addr;
if (!iter_.readWait(&addr, type, byteSize, ¬hing, ¬hing))