summaryrefslogtreecommitdiffstats
path: root/js/src/jit/x86-shared/Assembler-x86-shared.cpp
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /js/src/jit/x86-shared/Assembler-x86-shared.cpp
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'js/src/jit/x86-shared/Assembler-x86-shared.cpp')
-rw-r--r--js/src/jit/x86-shared/Assembler-x86-shared.cpp350
1 files changed, 350 insertions, 0 deletions
diff --git a/js/src/jit/x86-shared/Assembler-x86-shared.cpp b/js/src/jit/x86-shared/Assembler-x86-shared.cpp
new file mode 100644
index 000000000..8d761c138
--- /dev/null
+++ b/js/src/jit/x86-shared/Assembler-x86-shared.cpp
@@ -0,0 +1,350 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gc/Marking.h"
+#include "jit/Disassembler.h"
+#include "jit/JitCompartment.h"
+#if defined(JS_CODEGEN_X86)
+# include "jit/x86/MacroAssembler-x86.h"
+#elif defined(JS_CODEGEN_X64)
+# include "jit/x64/MacroAssembler-x64.h"
+#else
+# error "Wrong architecture. Only x86 and x64 should build this file!"
+#endif
+
+#ifdef _MSC_VER
+# include <intrin.h> // for __cpuid
+# if defined(_M_X64) && (_MSC_FULL_VER >= 160040219)
+# include <immintrin.h> // for _xgetbv
+# endif
+#endif
+
+using namespace js;
+using namespace js::jit;
+
+void
+AssemblerX86Shared::copyJumpRelocationTable(uint8_t* dest)
+{
+ if (jumpRelocations_.length())
+ memcpy(dest, jumpRelocations_.buffer(), jumpRelocations_.length());
+}
+
+void
+AssemblerX86Shared::copyDataRelocationTable(uint8_t* dest)
+{
+ if (dataRelocations_.length())
+ memcpy(dest, dataRelocations_.buffer(), dataRelocations_.length());
+}
+
+void
+AssemblerX86Shared::copyPreBarrierTable(uint8_t* dest)
+{
+ if (preBarriers_.length())
+ memcpy(dest, preBarriers_.buffer(), preBarriers_.length());
+}
+
+static void
+TraceDataRelocations(JSTracer* trc, uint8_t* buffer, CompactBufferReader& reader)
+{
+ while (reader.more()) {
+ size_t offset = reader.readUnsigned();
+ void* ptr = X86Encoding::GetPointer(buffer + offset);
+
+#ifdef JS_PUNBOX64
+ // All pointers on x64 will have the top bits cleared. If those bits
+ // are not cleared, this must be a Value.
+ uintptr_t word = reinterpret_cast<uintptr_t>(ptr);
+ if (word >> JSVAL_TAG_SHIFT) {
+ Value v = Value::fromRawBits(word);
+ TraceManuallyBarrieredEdge(trc, &v, "jit-masm-value");
+ if (word != v.asRawBits()) {
+ // Only update the code if the Value changed, because the code
+ // is not writable if we're not moving objects.
+ X86Encoding::SetPointer(buffer + offset, v.bitsAsPunboxPointer());
+ }
+ continue;
+ }
+#endif
+
+ // No barrier needed since these are constants.
+ gc::Cell* cellPtr = reinterpret_cast<gc::Cell*>(ptr);
+ TraceManuallyBarrieredGenericPointerEdge(trc, &cellPtr, "jit-masm-ptr");
+ if (cellPtr != ptr)
+ X86Encoding::SetPointer(buffer + offset, cellPtr);
+ }
+}
+
+
+void
+AssemblerX86Shared::TraceDataRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader)
+{
+ ::TraceDataRelocations(trc, code->raw(), reader);
+}
+
+void
+AssemblerX86Shared::trace(JSTracer* trc)
+{
+ for (size_t i = 0; i < jumps_.length(); i++) {
+ RelativePatch& rp = jumps_[i];
+ if (rp.kind == Relocation::JITCODE) {
+ JitCode* code = JitCode::FromExecutable((uint8_t*)rp.target);
+ TraceManuallyBarrieredEdge(trc, &code, "masmrel32");
+ MOZ_ASSERT(code == JitCode::FromExecutable((uint8_t*)rp.target));
+ }
+ }
+ if (dataRelocations_.length()) {
+ CompactBufferReader reader(dataRelocations_);
+ ::TraceDataRelocations(trc, masm.data(), reader);
+ }
+}
+
+void
+AssemblerX86Shared::executableCopy(void* buffer)
+{
+ masm.executableCopy(buffer);
+
+ // Crash diagnostics for bug 1124397. Check the code buffer has not been
+ // poisoned with 0xE5 bytes.
+ static const size_t MinPoisoned = 16;
+ const uint8_t* bytes = (const uint8_t*)buffer;
+ size_t len = size();
+
+ for (size_t i = 0; i < len; i += MinPoisoned) {
+ if (bytes[i] != 0xE5)
+ continue;
+
+ size_t startOffset = i;
+ while (startOffset > 0 && bytes[startOffset - 1] == 0xE5)
+ startOffset--;
+
+ size_t endOffset = i;
+ while (endOffset + 1 < len && bytes[endOffset + 1] == 0xE5)
+ endOffset++;
+
+ if (endOffset - startOffset < MinPoisoned)
+ continue;
+
+ volatile uintptr_t dump[5];
+ blackbox = dump;
+ blackbox[0] = uintptr_t(0xABCD4321);
+ blackbox[1] = uintptr_t(len);
+ blackbox[2] = uintptr_t(startOffset);
+ blackbox[3] = uintptr_t(endOffset);
+ blackbox[4] = uintptr_t(0xFFFF8888);
+ MOZ_CRASH("Corrupt code buffer");
+ }
+}
+
+void
+AssemblerX86Shared::processCodeLabels(uint8_t* rawCode)
+{
+ for (size_t i = 0; i < codeLabels_.length(); i++) {
+ CodeLabel label = codeLabels_[i];
+ Bind(rawCode, label.patchAt(), rawCode + label.target()->offset());
+ }
+}
+
+AssemblerX86Shared::Condition
+AssemblerX86Shared::InvertCondition(Condition cond)
+{
+ switch (cond) {
+ case Zero:
+ return NonZero;
+ case NonZero:
+ return Zero;
+ case LessThan:
+ return GreaterThanOrEqual;
+ case LessThanOrEqual:
+ return GreaterThan;
+ case GreaterThan:
+ return LessThanOrEqual;
+ case GreaterThanOrEqual:
+ return LessThan;
+ case Above:
+ return BelowOrEqual;
+ case AboveOrEqual:
+ return Below;
+ case Below:
+ return AboveOrEqual;
+ case BelowOrEqual:
+ return Above;
+ default:
+ MOZ_CRASH("unexpected condition");
+ }
+}
+
+AssemblerX86Shared::Condition
+AssemblerX86Shared::UnsignedCondition(Condition cond)
+{
+ switch (cond) {
+ case Zero:
+ case NonZero:
+ return cond;
+ case LessThan:
+ case Below:
+ return Below;
+ case LessThanOrEqual:
+ case BelowOrEqual:
+ return BelowOrEqual;
+ case GreaterThan:
+ case Above:
+ return Above;
+ case AboveOrEqual:
+ case GreaterThanOrEqual:
+ return AboveOrEqual;
+ default:
+ MOZ_CRASH("unexpected condition");
+ }
+}
+
+AssemblerX86Shared::Condition
+AssemblerX86Shared::ConditionWithoutEqual(Condition cond)
+{
+ switch (cond) {
+ case LessThan:
+ case LessThanOrEqual:
+ return LessThan;
+ case Below:
+ case BelowOrEqual:
+ return Below;
+ case GreaterThan:
+ case GreaterThanOrEqual:
+ return GreaterThan;
+ case Above:
+ case AboveOrEqual:
+ return Above;
+ default:
+ MOZ_CRASH("unexpected condition");
+ }
+}
+
+void
+AssemblerX86Shared::verifyHeapAccessDisassembly(uint32_t begin, uint32_t end,
+ const Disassembler::HeapAccess& heapAccess)
+{
+#ifdef DEBUG
+ if (masm.oom())
+ return;
+ Disassembler::VerifyHeapAccess(masm.data() + begin, masm.data() + end, heapAccess);
+#endif
+}
+
+CPUInfo::SSEVersion CPUInfo::maxSSEVersion = UnknownSSE;
+CPUInfo::SSEVersion CPUInfo::maxEnabledSSEVersion = UnknownSSE;
+bool CPUInfo::avxPresent = false;
+bool CPUInfo::avxEnabled = false;
+bool CPUInfo::popcntPresent = false;
+bool CPUInfo::needAmdBugWorkaround = false;
+
+static uintptr_t
+ReadXGETBV()
+{
+ // We use a variety of low-level mechanisms to get at the xgetbv
+ // instruction, including spelling out the xgetbv instruction as bytes,
+ // because older compilers and assemblers may not recognize the instruction
+ // by name.
+ size_t xcr0EAX = 0;
+#if defined(_XCR_XFEATURE_ENABLED_MASK)
+ xcr0EAX = _xgetbv(_XCR_XFEATURE_ENABLED_MASK);
+#elif defined(__GNUC__)
+ // xgetbv returns its results in %eax and %edx, and for our purposes here,
+ // we're only interested in the %eax value.
+ asm(".byte 0x0f, 0x01, 0xd0" : "=a"(xcr0EAX) : "c"(0) : "%edx");
+#elif defined(_MSC_VER) && defined(_M_IX86)
+ __asm {
+ xor ecx, ecx
+ _asm _emit 0x0f _asm _emit 0x01 _asm _emit 0xd0
+ mov xcr0EAX, eax
+ }
+#endif
+ return xcr0EAX;
+}
+
+void
+CPUInfo::SetSSEVersion()
+{
+ int flagsEAX = 0;
+ int flagsECX = 0;
+ int flagsEDX = 0;
+
+#ifdef _MSC_VER
+ int cpuinfo[4];
+ __cpuid(cpuinfo, 1);
+ flagsEAX = cpuinfo[0];
+ flagsECX = cpuinfo[2];
+ flagsEDX = cpuinfo[3];
+#elif defined(__GNUC__)
+# ifdef JS_CODEGEN_X64
+ asm (
+ "movl $0x1, %%eax;"
+ "cpuid;"
+ : "=a" (flagsEAX), "=c" (flagsECX), "=d" (flagsEDX)
+ :
+ : "%ebx"
+ );
+# else
+ // On x86, preserve ebx. The compiler needs it for PIC mode.
+ // Some older processors don't fill the ecx register with cpuid, so clobber
+ // it before calling cpuid, so that there's no risk of picking random bits
+ // indicating SSE3/SSE4 are present.
+ asm (
+ "xor %%ecx, %%ecx;"
+ "movl $0x1, %%eax;"
+ "pushl %%ebx;"
+ "cpuid;"
+ "popl %%ebx;"
+ : "=a" (flagsEAX), "=c" (flagsECX), "=d" (flagsEDX)
+ :
+ :
+ );
+# endif
+#else
+# error "Unsupported compiler"
+#endif
+
+ static const int SSEBit = 1 << 25;
+ static const int SSE2Bit = 1 << 26;
+ static const int SSE3Bit = 1 << 0;
+ static const int SSSE3Bit = 1 << 9;
+ static const int SSE41Bit = 1 << 19;
+ static const int SSE42Bit = 1 << 20;
+
+ if (flagsECX & SSE42Bit) maxSSEVersion = SSE4_2;
+ else if (flagsECX & SSE41Bit) maxSSEVersion = SSE4_1;
+ else if (flagsECX & SSSE3Bit) maxSSEVersion = SSSE3;
+ else if (flagsECX & SSE3Bit) maxSSEVersion = SSE3;
+ else if (flagsEDX & SSE2Bit) maxSSEVersion = SSE2;
+ else if (flagsEDX & SSEBit) maxSSEVersion = SSE;
+ else maxSSEVersion = NoSSE;
+
+ if (maxEnabledSSEVersion != UnknownSSE)
+ maxSSEVersion = Min(maxSSEVersion, maxEnabledSSEVersion);
+
+ static const int AVXBit = 1 << 28;
+ static const int XSAVEBit = 1 << 27;
+ avxPresent = (flagsECX & AVXBit) && (flagsECX & XSAVEBit) && avxEnabled;
+
+ // If the hardware supports AVX, check whether the OS supports it too.
+ if (avxPresent) {
+ size_t xcr0EAX = ReadXGETBV();
+ static const int xcr0SSEBit = 1 << 1;
+ static const int xcr0AVXBit = 1 << 2;
+ avxPresent = (xcr0EAX & xcr0SSEBit) && (xcr0EAX & xcr0AVXBit);
+ }
+
+ static const int POPCNTBit = 1 << 23;
+
+ popcntPresent = (flagsECX & POPCNTBit);
+
+ // Check if we need to work around an AMD CPU bug (see bug 1281759).
+ // We check for family 20 models 0-2. Intel doesn't use family 20 at
+ // this point, so this should only match AMD CPUs.
+ unsigned family = ((flagsEAX >> 20) & 0xff) + ((flagsEAX >> 8) & 0xf);
+ unsigned model = (((flagsEAX >> 16) & 0xf) << 4) + ((flagsEAX >> 4) & 0xf);
+ needAmdBugWorkaround = (family == 20 && model <= 2);
+}
+
+volatile uintptr_t* blackbox = nullptr;