diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-06-20 13:01:08 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-06-20 13:01:08 +0200 |
commit | 49233e234e5c787396cadb2cea33b31ae0cd65c1 (patch) | |
tree | 5410cb9a8fd53168bb60d62c54b654d86f03c38d /Source/JavaScriptCore/assembler | |
parent | b211c645d8ab690f713515dfdc84d80b11c27d2c (diff) | |
download | qtwebkit-49233e234e5c787396cadb2cea33b31ae0cd65c1.tar.gz |
Imported WebKit commit 3a8c29f35d00659d2ce7a0ccdfa8304f14e82327 (http://svn.webkit.org/repository/webkit/trunk@120813)
New snapshot with Windows build fixes
Diffstat (limited to 'Source/JavaScriptCore/assembler')
-rw-r--r-- | Source/JavaScriptCore/assembler/ARMv7Assembler.h | 49 | ||||
-rw-r--r-- | Source/JavaScriptCore/assembler/AbstractMacroAssembler.h | 24 | ||||
-rw-r--r-- | Source/JavaScriptCore/assembler/AssemblerBuffer.h | 4 | ||||
-rw-r--r-- | Source/JavaScriptCore/assembler/LinkBuffer.cpp | 231 | ||||
-rw-r--r-- | Source/JavaScriptCore/assembler/LinkBuffer.h | 198 | ||||
-rw-r--r-- | Source/JavaScriptCore/assembler/MacroAssemblerARM.h | 18 | ||||
-rw-r--r-- | Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h | 24 | ||||
-rw-r--r-- | Source/JavaScriptCore/assembler/MacroAssemblerCodeRef.h | 9 | ||||
-rw-r--r-- | Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h | 18 | ||||
-rw-r--r-- | Source/JavaScriptCore/assembler/MacroAssemblerSH4.h | 21 | ||||
-rw-r--r-- | Source/JavaScriptCore/assembler/MacroAssemblerX86.h | 11 | ||||
-rw-r--r-- | Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h | 10 | ||||
-rw-r--r-- | Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h | 8 | ||||
-rw-r--r-- | Source/JavaScriptCore/assembler/X86Assembler.h | 53 |
14 files changed, 490 insertions, 188 deletions
diff --git a/Source/JavaScriptCore/assembler/ARMv7Assembler.h b/Source/JavaScriptCore/assembler/ARMv7Assembler.h index 0cbe799b4..95c812c94 100644 --- a/Source/JavaScriptCore/assembler/ARMv7Assembler.h +++ b/Source/JavaScriptCore/assembler/ARMv7Assembler.h @@ -483,6 +483,12 @@ public: JumpLinkType m_linkType : 8; Condition m_condition : 16; }; + + ARMv7Assembler() + : m_indexOfLastWatchpoint(INT_MIN) + , m_indexOfTailOfLastWatchpoint(INT_MIN) + { + } private: @@ -1820,10 +1826,25 @@ public: { m_formatter.oneWordOp8Imm8(OP_NOP_T1, 0); } + + AssemblerLabel labelForWatchpoint() + { + AssemblerLabel result = m_formatter.label(); + if (static_cast<int>(result.m_offset) != m_indexOfLastWatchpoint) + result = label(); + m_indexOfLastWatchpoint = result.m_offset; + m_indexOfTailOfLastWatchpoint = result.m_offset + maxJumpReplacementSize(); + return result; + } AssemblerLabel label() { - return m_formatter.label(); + AssemblerLabel result = m_formatter.label(); + while (UNLIKELY(static_cast<int>(result.m_offset) < m_indexOfTailOfLastWatchpoint)) { + nop(); + result = m_formatter.label(); + } + return result; } AssemblerLabel align(int alignment) @@ -2067,6 +2088,30 @@ public: { return reinterpret_cast<void*>(readInt32(where)); } + + static void replaceWithJump(void* instructionStart, void* to) + { + ASSERT(!(bitwise_cast<uintptr_t>(instructionStart) & 1)); + ASSERT(!(bitwise_cast<uintptr_t>(to) & 1)); + uint16_t* ptr = reinterpret_cast<uint16_t*>(instructionStart) + 2; + + // Ensure that we're not in one of those errata-triggering thingies. If we are, then + // prepend a nop. + bool spansTwo4K = ((reinterpret_cast<intptr_t>(ptr) & 0xfff) == 0x002); + + if (spansTwo4K) { + ptr[-2] = OP_NOP_T1; + ptr++; + } + + linkJumpT4(ptr, to); + cacheFlush(ptr - 2, sizeof(uint16_t) * 2); + } + + static ptrdiff_t maxJumpReplacementSize() + { + return 6; + } unsigned debugOffset() { return m_formatter.debugOffset(); } @@ -2604,6 +2649,8 @@ private: Vector<LinkRecord> m_jumpsToLink; Vector<int32_t> m_offsets; + int m_indexOfLastWatchpoint; + int m_indexOfTailOfLastWatchpoint; }; } // namespace JSC diff --git a/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h b/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h index a0039cb52..27b8a58d1 100644 --- a/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h +++ b/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2012 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -48,6 +48,7 @@ namespace JSC { class LinkBuffer; class RepatchBuffer; +class Watchpoint; namespace DFG { class CorrectableJumpPoint; } @@ -70,7 +71,6 @@ public: // The following types are used as operands to MacroAssembler operations, // describing immediate and memory operands to the instructions to be planted. - enum Scale { TimesOne, TimesTwo, @@ -279,6 +279,7 @@ public: friend class Jump; friend class MacroAssemblerCodeRef; friend class LinkBuffer; + friend class Watchpoint; public: Label() @@ -559,6 +560,13 @@ public: return Label(this); } + Label watchpointLabel() + { + Label result; + result.m_label = m_assembler.labelForWatchpoint(); + return result; + } + Label align() { m_assembler.align(16); @@ -655,18 +663,6 @@ protected: { return AssemblerType::readPointer(dataLabelPtr.dataLocation()); } - - static void unreachableForPlatform() - { -#if COMPILER(CLANG) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wmissing-noreturn" - ASSERT_NOT_REACHED(); -#pragma clang diagnostic pop -#else - ASSERT_NOT_REACHED(); -#endif - } }; } // namespace JSC diff --git a/Source/JavaScriptCore/assembler/AssemblerBuffer.h b/Source/JavaScriptCore/assembler/AssemblerBuffer.h index d1deef234..6bc1b3924 100644 --- a/Source/JavaScriptCore/assembler/AssemblerBuffer.h +++ b/Source/JavaScriptCore/assembler/AssemblerBuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2012 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,11 +28,11 @@ #if ENABLE(ASSEMBLER) +#include "ExecutableAllocator.h" #include "JITCompilationEffort.h" #include "JSGlobalData.h" #include "stdint.h" #include <string.h> -#include <jit/ExecutableAllocator.h> #include <wtf/Assertions.h> #include <wtf/FastMalloc.h> #include <wtf/StdLibExtras.h> diff --git a/Source/JavaScriptCore/assembler/LinkBuffer.cpp b/Source/JavaScriptCore/assembler/LinkBuffer.cpp new file mode 100644 index 000000000..58030ba7d --- /dev/null +++ b/Source/JavaScriptCore/assembler/LinkBuffer.cpp @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "LinkBuffer.h" + +#if ENABLE(ASSEMBLER) + +#include "Options.h" + +namespace JSC { + +LinkBuffer::CodeRef LinkBuffer::finalizeCodeWithoutDisassembly() +{ + performFinalization(); + + return CodeRef(m_executableMemory); +} + +LinkBuffer::CodeRef LinkBuffer::finalizeCodeWithDisassembly(const char* format, ...) +{ + ASSERT(Options::showDisassembly); + + CodeRef result = finalizeCodeWithoutDisassembly(); + + dataLog("Generated JIT code for "); + va_list argList; + va_start(argList, format); + WTF::dataLogV(format, argList); + va_end(argList); + dataLog(":\n"); + + dataLog(" Code at [%p, %p):\n", result.code().executableAddress(), static_cast<char*>(result.code().executableAddress()) + result.size()); + if (!tryToDisassemble(result.code(), m_size, " ", WTF::dataFile())) + dataLog(" <no disassembly available>"); + + return result; +} + +void LinkBuffer::linkCode(void* ownerUID, JITCompilationEffort effort) +{ + ASSERT(!m_code); +#if !ENABLE(BRANCH_COMPACTION) + m_executableMemory = m_assembler->m_assembler.executableCopy(*m_globalData, ownerUID, effort); + if (!m_executableMemory) + return; + m_code = m_executableMemory->start(); + m_size = m_assembler->m_assembler.codeSize(); + ASSERT(m_code); +#else + m_initialSize = m_assembler->m_assembler.codeSize(); + m_executableMemory = m_globalData->executableAllocator.allocate(*m_globalData, m_initialSize, ownerUID, effort); + if (!m_executableMemory) + return; + m_code = (uint8_t*)m_executableMemory->start(); + ASSERT(m_code); + ExecutableAllocator::makeWritable(m_code, m_initialSize); + uint8_t* inData = (uint8_t*)m_assembler->unlinkedCode(); + uint8_t* outData = reinterpret_cast<uint8_t*>(m_code); + int readPtr = 0; + int writePtr = 0; + Vector<LinkRecord>& jumpsToLink = m_assembler->jumpsToLink(); + unsigned jumpCount = jumpsToLink.size(); + for (unsigned i = 0; i < jumpCount; ++i) { + int offset = readPtr - writePtr; + ASSERT(!(offset & 1)); + + // Copy the instructions from the last jump to the current one. + size_t regionSize = jumpsToLink[i].from() - readPtr; + uint16_t* copySource = reinterpret_cast_ptr<uint16_t*>(inData + readPtr); + uint16_t* copyEnd = reinterpret_cast_ptr<uint16_t*>(inData + readPtr + regionSize); + uint16_t* copyDst = reinterpret_cast_ptr<uint16_t*>(outData + writePtr); + ASSERT(!(regionSize % 2)); + ASSERT(!(readPtr % 2)); + ASSERT(!(writePtr % 2)); + while (copySource != copyEnd) + *copyDst++ = *copySource++; + m_assembler->recordLinkOffsets(readPtr, jumpsToLink[i].from(), offset); + readPtr += regionSize; + writePtr += regionSize; + + // Calculate absolute address of the jump target, in the case of backwards + // branches we need to be precise, forward branches we are pessimistic + const uint8_t* target; + if (jumpsToLink[i].to() >= jumpsToLink[i].from()) + target = outData + jumpsToLink[i].to() - offset; // Compensate for what we have collapsed so far + else + target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to()); + + JumpLinkType jumpLinkType = m_assembler->computeJumpType(jumpsToLink[i], outData + writePtr, target); + // Compact branch if we can... + if (m_assembler->canCompact(jumpsToLink[i].type())) { + // Step back in the write stream + int32_t delta = m_assembler->jumpSizeDelta(jumpsToLink[i].type(), jumpLinkType); + if (delta) { + writePtr -= delta; + m_assembler->recordLinkOffsets(jumpsToLink[i].from() - delta, readPtr, readPtr - writePtr); + } + } + jumpsToLink[i].setFrom(writePtr); + } + // Copy everything after the last jump + memcpy(outData + writePtr, inData + readPtr, m_initialSize - readPtr); + m_assembler->recordLinkOffsets(readPtr, m_initialSize, readPtr - writePtr); + + for (unsigned i = 0; i < jumpCount; ++i) { + uint8_t* location = outData + jumpsToLink[i].from(); + uint8_t* target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to()); + m_assembler->link(jumpsToLink[i], location, target); + } + + jumpsToLink.clear(); + m_size = writePtr + m_initialSize - readPtr; + m_executableMemory->shrink(m_size); + +#if DUMP_LINK_STATISTICS + dumpLinkStatistics(m_code, m_initialSize, m_size); +#endif +#if DUMP_CODE + dumpCode(m_code, m_size); +#endif +#endif +} + +void LinkBuffer::performFinalization() +{ +#ifndef NDEBUG + ASSERT(!m_completed); + ASSERT(isValid()); + m_completed = true; +#endif + +#if ENABLE(BRANCH_COMPACTION) + ExecutableAllocator::makeExecutable(code(), m_initialSize); +#else + ExecutableAllocator::makeExecutable(code(), m_size); +#endif + MacroAssembler::cacheFlush(code(), m_size); +} + +#if DUMP_LINK_STATISTICS +void LinkBuffer::dumpLinkStatistics(void* code, size_t initializeSize, size_t finalSize) +{ + static unsigned linkCount = 0; + static unsigned totalInitialSize = 0; + static unsigned totalFinalSize = 0; + linkCount++; + totalInitialSize += initialSize; + totalFinalSize += finalSize; + dataLog("link %p: orig %u, compact %u (delta %u, %.2f%%)\n", + code, static_cast<unsigned>(initialSize), static_cast<unsigned>(finalSize), + static_cast<unsigned>(initialSize - finalSize), + 100.0 * (initialSize - finalSize) / initialSize); + dataLog("\ttotal %u: orig %u, compact %u (delta %u, %.2f%%)\n", + linkCount, totalInitialSize, totalFinalSize, totalInitialSize - totalFinalSize, + 100.0 * (totalInitialSize - totalFinalSize) / totalInitialSize); +} +#endif + +#if DUMP_CODE +void LinkBuffer::dumpCode(void* code, size_t size) +{ +#if CPU(ARM_THUMB2) + // Dump the generated code in an asm file format that can be assembled and then disassembled + // for debugging purposes. For example, save this output as jit.s: + // gcc -arch armv7 -c jit.s + // otool -tv jit.o + static unsigned codeCount = 0; + unsigned short* tcode = static_cast<unsigned short*>(code); + size_t tsize = size / sizeof(short); + char nameBuf[128]; + snprintf(nameBuf, sizeof(nameBuf), "_jsc_jit%u", codeCount++); + dataLog("\t.syntax unified\n" + "\t.section\t__TEXT,__text,regular,pure_instructions\n" + "\t.globl\t%s\n" + "\t.align 2\n" + "\t.code 16\n" + "\t.thumb_func\t%s\n" + "# %p\n" + "%s:\n", nameBuf, nameBuf, code, nameBuf); + + for (unsigned i = 0; i < tsize; i++) + dataLog("\t.short\t0x%x\n", tcode[i]); +#elif CPU(ARM_TRADITIONAL) + // gcc -c jit.s + // objdump -D jit.o + static unsigned codeCount = 0; + unsigned int* tcode = static_cast<unsigned int*>(code); + size_t tsize = size / sizeof(unsigned int); + char nameBuf[128]; + snprintf(nameBuf, sizeof(nameBuf), "_jsc_jit%u", codeCount++); + dataLog("\t.globl\t%s\n" + "\t.align 4\n" + "\t.code 32\n" + "\t.text\n" + "# %p\n" + "%s:\n", nameBuf, code, nameBuf); + + for (unsigned i = 0; i < tsize; i++) + dataLog("\t.long\t0x%x\n", tcode[i]); +#endif +} +#endif + +} // namespace JSC + +#endif // ENABLE(ASSEMBLER) + + diff --git a/Source/JavaScriptCore/assembler/LinkBuffer.h b/Source/JavaScriptCore/assembler/LinkBuffer.h index eff320d57..c6e003142 100644 --- a/Source/JavaScriptCore/assembler/LinkBuffer.h +++ b/Source/JavaScriptCore/assembler/LinkBuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2010, 2012 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -193,13 +193,13 @@ public: return applyOffset(label.m_label).m_offset; } - // Upon completion of all patching 'finalizeCode()' should be called once to complete generation of the code. - CodeRef finalizeCode() - { - performFinalization(); - - return CodeRef(m_executableMemory); - } + // Upon completion of all patching 'FINALIZE_CODE()' should be called once to + // complete generation of the code. Alternatively, call + // finalizeCodeWithoutDisassembly() directly if you have your own way of + // displaying disassembly. + + CodeRef finalizeCodeWithoutDisassembly(); + CodeRef finalizeCodeWithDisassembly(const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3); CodePtr trampolineAt(Label label) { @@ -231,169 +231,16 @@ private: return m_code; } - void linkCode(void* ownerUID, JITCompilationEffort effort) - { - ASSERT(!m_code); -#if !ENABLE(BRANCH_COMPACTION) - m_executableMemory = m_assembler->m_assembler.executableCopy(*m_globalData, ownerUID, effort); - if (!m_executableMemory) - return; - m_code = m_executableMemory->start(); - m_size = m_assembler->m_assembler.codeSize(); - ASSERT(m_code); -#else - m_initialSize = m_assembler->m_assembler.codeSize(); - m_executableMemory = m_globalData->executableAllocator.allocate(*m_globalData, m_initialSize, ownerUID, effort); - if (!m_executableMemory) - return; - m_code = (uint8_t*)m_executableMemory->start(); - ASSERT(m_code); - ExecutableAllocator::makeWritable(m_code, m_initialSize); - uint8_t* inData = (uint8_t*)m_assembler->unlinkedCode(); - uint8_t* outData = reinterpret_cast<uint8_t*>(m_code); - int readPtr = 0; - int writePtr = 0; - Vector<LinkRecord>& jumpsToLink = m_assembler->jumpsToLink(); - unsigned jumpCount = jumpsToLink.size(); - for (unsigned i = 0; i < jumpCount; ++i) { - int offset = readPtr - writePtr; - ASSERT(!(offset & 1)); - - // Copy the instructions from the last jump to the current one. - size_t regionSize = jumpsToLink[i].from() - readPtr; - uint16_t* copySource = reinterpret_cast_ptr<uint16_t*>(inData + readPtr); - uint16_t* copyEnd = reinterpret_cast_ptr<uint16_t*>(inData + readPtr + regionSize); - uint16_t* copyDst = reinterpret_cast_ptr<uint16_t*>(outData + writePtr); - ASSERT(!(regionSize % 2)); - ASSERT(!(readPtr % 2)); - ASSERT(!(writePtr % 2)); - while (copySource != copyEnd) - *copyDst++ = *copySource++; - m_assembler->recordLinkOffsets(readPtr, jumpsToLink[i].from(), offset); - readPtr += regionSize; - writePtr += regionSize; - - // Calculate absolute address of the jump target, in the case of backwards - // branches we need to be precise, forward branches we are pessimistic - const uint8_t* target; - if (jumpsToLink[i].to() >= jumpsToLink[i].from()) - target = outData + jumpsToLink[i].to() - offset; // Compensate for what we have collapsed so far - else - target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to()); - - JumpLinkType jumpLinkType = m_assembler->computeJumpType(jumpsToLink[i], outData + writePtr, target); - // Compact branch if we can... - if (m_assembler->canCompact(jumpsToLink[i].type())) { - // Step back in the write stream - int32_t delta = m_assembler->jumpSizeDelta(jumpsToLink[i].type(), jumpLinkType); - if (delta) { - writePtr -= delta; - m_assembler->recordLinkOffsets(jumpsToLink[i].from() - delta, readPtr, readPtr - writePtr); - } - } - jumpsToLink[i].setFrom(writePtr); - } - // Copy everything after the last jump - memcpy(outData + writePtr, inData + readPtr, m_initialSize - readPtr); - m_assembler->recordLinkOffsets(readPtr, m_initialSize, readPtr - writePtr); - - for (unsigned i = 0; i < jumpCount; ++i) { - uint8_t* location = outData + jumpsToLink[i].from(); - uint8_t* target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to()); - m_assembler->link(jumpsToLink[i], location, target); - } - - jumpsToLink.clear(); - m_size = writePtr + m_initialSize - readPtr; - m_executableMemory->shrink(m_size); - -#if DUMP_LINK_STATISTICS - dumpLinkStatistics(m_code, m_initialSize, m_size); -#endif -#if DUMP_CODE - dumpCode(m_code, m_size); -#endif -#endif - } + void linkCode(void* ownerUID, JITCompilationEffort); - void performFinalization() - { -#ifndef NDEBUG - ASSERT(!m_completed); - ASSERT(isValid()); - m_completed = true; -#endif - -#if ENABLE(BRANCH_COMPACTION) - ExecutableAllocator::makeExecutable(code(), m_initialSize); -#else - ExecutableAllocator::makeExecutable(code(), m_size); -#endif - MacroAssembler::cacheFlush(code(), m_size); - } + void performFinalization(); #if DUMP_LINK_STATISTICS - static void dumpLinkStatistics(void* code, size_t initialSize, size_t finalSize) - { - static unsigned linkCount = 0; - static unsigned totalInitialSize = 0; - static unsigned totalFinalSize = 0; - linkCount++; - totalInitialSize += initialSize; - totalFinalSize += finalSize; - dataLog("link %p: orig %u, compact %u (delta %u, %.2f%%)\n", - code, static_cast<unsigned>(initialSize), static_cast<unsigned>(finalSize), - static_cast<unsigned>(initialSize - finalSize), - 100.0 * (initialSize - finalSize) / initialSize); - dataLog("\ttotal %u: orig %u, compact %u (delta %u, %.2f%%)\n", - linkCount, totalInitialSize, totalFinalSize, totalInitialSize - totalFinalSize, - 100.0 * (totalInitialSize - totalFinalSize) / totalInitialSize); - } + static void dumpLinkStatistics(void* code, size_t initialSize, size_t finalSize); #endif #if DUMP_CODE - static void dumpCode(void* code, size_t size) - { -#if CPU(ARM_THUMB2) - // Dump the generated code in an asm file format that can be assembled and then disassembled - // for debugging purposes. For example, save this output as jit.s: - // gcc -arch armv7 -c jit.s - // otool -tv jit.o - static unsigned codeCount = 0; - unsigned short* tcode = static_cast<unsigned short*>(code); - size_t tsize = size / sizeof(short); - char nameBuf[128]; - snprintf(nameBuf, sizeof(nameBuf), "_jsc_jit%u", codeCount++); - dataLog("\t.syntax unified\n" - "\t.section\t__TEXT,__text,regular,pure_instructions\n" - "\t.globl\t%s\n" - "\t.align 2\n" - "\t.code 16\n" - "\t.thumb_func\t%s\n" - "# %p\n" - "%s:\n", nameBuf, nameBuf, code, nameBuf); - - for (unsigned i = 0; i < tsize; i++) - dataLog("\t.short\t0x%x\n", tcode[i]); -#elif CPU(ARM_TRADITIONAL) - // gcc -c jit.s - // objdump -D jit.o - static unsigned codeCount = 0; - unsigned int* tcode = static_cast<unsigned int*>(code); - size_t tsize = size / sizeof(unsigned int); - char nameBuf[128]; - snprintf(nameBuf, sizeof(nameBuf), "_jsc_jit%u", codeCount++); - dataLog("\t.globl\t%s\n" - "\t.align 4\n" - "\t.code 32\n" - "\t.text\n" - "# %p\n" - "%s:\n", nameBuf, code, nameBuf); - - for (unsigned i = 0; i < tsize; i++) - dataLog("\t.long\t0x%x\n", tcode[i]); -#endif - } + static void dumpCode(void* code, size_t); #endif RefPtr<ExecutableMemoryHandle> m_executableMemory; @@ -410,6 +257,27 @@ private: #endif }; +// Use this to finalize code, like so: +// +// CodeRef code = FINALIZE_CODE(linkBuffer, ("my super thingy number %d", number)); +// +// Which, in disassembly mode, will print: +// +// Generated JIT code for my super thingy number 42: +// Code at [0x123456, 0x234567]: +// 0x123456: mov $0, 0 +// 0x12345a: ret +// +// ... and so on. +// +// Note that the dataLogArgumentsForHeading are only evaluated when showDisassembly +// is true, so you can hide expensive disassembly-only computations inside there. + +#define FINALIZE_CODE(linkBufferReference, dataLogArgumentsForHeading) \ + (UNLIKELY(Options::showDisassembly) \ + ? ((linkBufferReference).finalizeCodeWithDisassembly dataLogArgumentsForHeading) \ + : (linkBufferReference).finalizeCodeWithoutDisassembly()) + } // namespace JSC #endif // ENABLE(ASSEMBLER) diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerARM.h b/Source/JavaScriptCore/assembler/MacroAssemblerARM.h index 1775cb4cf..8ea29e3a0 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerARM.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerARM.h @@ -514,6 +514,13 @@ public: return branchTest32(cond, ARMRegisters::S1, mask); } + Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1)) + { + move(TrustedImmPtr(address.m_ptr), ARMRegisters::S1); + load8(Address(ARMRegisters::S1), ARMRegisters::S1); + return branchTest32(cond, ARMRegisters::S1, mask); + } + Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask) { ASSERT((cond == Zero) || (cond == NonZero)); @@ -1010,6 +1017,17 @@ public: return FunctionPtr(reinterpret_cast<void(*)()>(ARMAssembler::readCallTarget(call.dataLocation()))); } + static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination) + { + ASSERT_NOT_REACHED(); + } + + static ptrdiff_t maxJumpReplacementSize() + { + ASSERT_NOT_REACHED(); + return 0; + } + protected: ARMAssembler::Condition ARMCondition(RelationalCondition cond) { diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h b/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h index 3b62cb5be..6c0feffcf 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h @@ -608,7 +608,7 @@ public: void load8Signed(ImplicitAddress, RegisterID) { - unreachableForPlatform(); + UNREACHABLE_FOR_PLATFORM(); } void load8(BaseIndex address, RegisterID dest) @@ -674,7 +674,7 @@ public: void load16Signed(ImplicitAddress, RegisterID) { - unreachableForPlatform(); + UNREACHABLE_FOR_PLATFORM(); } DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) @@ -1186,6 +1186,16 @@ public: { m_assembler.nop(); } + + static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination) + { + ARMv7Assembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation()); + } + + static ptrdiff_t maxJumpReplacementSize() + { + return ARMv7Assembler::maxJumpReplacementSize(); + } // Forwards / external control flow operations: // @@ -1356,6 +1366,14 @@ public: return branchTest32(cond, addressTempRegister, mask); } + Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1)) + { + // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/ + move(TrustedImmPtr(address.m_ptr), addressTempRegister); + load8(Address(addressTempRegister), addressTempRegister); + return branchTest32(cond, addressTempRegister, mask); + } + void jump(RegisterID target) { m_assembler.bx(target); @@ -1679,12 +1697,14 @@ public: protected: ALWAYS_INLINE Jump jump() { + m_assembler.label(); // Force nop-padding if we're in the middle of a watchpoint. moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister); return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpNoConditionFixedSize : ARMv7Assembler::JumpNoCondition); } ALWAYS_INLINE Jump makeBranch(ARMv7Assembler::Condition cond) { + m_assembler.label(); // Force nop-padding if we're in the middle of a watchpoint. m_assembler.it(cond, true, true); moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister); return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpConditionFixedSize : ARMv7Assembler::JumpCondition, cond); diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerCodeRef.h b/Source/JavaScriptCore/assembler/MacroAssemblerCodeRef.h index ac62c4221..a1b3a8338 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerCodeRef.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerCodeRef.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2012 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,7 +26,9 @@ #ifndef MacroAssemblerCodeRef_h #define MacroAssemblerCodeRef_h +#include "Disassembler.h" #include "ExecutableAllocator.h" +#include <wtf/DataLog.h> #include <wtf/PassRefPtr.h> #include <wtf/RefPtr.h> #include <wtf/UnusedParam.h> @@ -367,6 +369,11 @@ public: return m_executableMemory->sizeInBytes(); } + bool tryToDisassemble(const char* prefix) const + { + return JSC::tryToDisassemble(m_codePtr, size(), prefix, WTF::dataFile()); + } + bool operator!() const { return !m_codePtr; } private: diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h b/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h index f9c3457b5..5adcf9b4e 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h @@ -1149,6 +1149,13 @@ public: return branchTest32(cond, dataTempRegister, mask); } + Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1)) + { + move(TrustedImmPtr(address.m_ptr), dataTempRegister); + load8(Address(dataTempRegister), dataTempRegister); + return branchTest32(cond, dataTempRegister, mask); + } + Jump jump() { return branchEqual(MIPSRegisters::zero, MIPSRegisters::zero); @@ -1868,6 +1875,17 @@ public: return FunctionPtr(reinterpret_cast<void(*)()>(MIPSAssembler::readCallTarget(call.dataLocation()))); } + static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination) + { + ASSERT_NOT_REACHED(); + } + + static ptrdiff_t maxJumpReplacementSize() + { + ASSERT_NOT_REACHED(); + return 0; + } + private: // If m_fixedWidth is true, we will generate a fixed number of instructions. // Otherwise, we can emit any number of instructions. diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerSH4.h b/Source/JavaScriptCore/assembler/MacroAssemblerSH4.h index c132ad642..badf35f81 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerSH4.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerSH4.h @@ -1293,6 +1293,16 @@ void or32(TrustedImm32 imm, RegisterID src, RegisterID dest) return jmp; } + Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1)) + { + RegisterID addressTempRegister = claimScratch(); + move(TrustedImmPtr(address.m_ptr), addressTempRegister); + load8(Address(addressTempRegister), addressTempRegister); + Jump jmp = branchTest32(cond, addressTempRegister, mask); + releaseScratch(addressTempRegister); + return jmp; + } + void signExtend32ToPtr(RegisterID src, RegisterID dest) { if (src != dest) @@ -1971,6 +1981,17 @@ void or32(TrustedImm32 imm, RegisterID src, RegisterID dest) return FunctionPtr(reinterpret_cast<void(*)()>(SH4Assembler::readCallTarget(call.dataLocation()))); } + static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination) + { + ASSERT_NOT_REACHED(); + } + + static ptrdiff_t maxJumpReplacementSize() + { + ASSERT_NOT_REACHED(); + return 0; + } + protected: SH4Assembler::Condition SH4Condition(RelationalCondition cond) { diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerX86.h b/Source/JavaScriptCore/assembler/MacroAssemblerX86.h index 088fe196b..3ea40c967 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerX86.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerX86.h @@ -51,6 +51,7 @@ public: using MacroAssemblerX86Common::loadDouble; using MacroAssemblerX86Common::storeDouble; using MacroAssemblerX86Common::convertInt32ToDouble; + using MacroAssemblerX86Common::branchTest8; void add32(TrustedImm32 imm, RegisterID src, RegisterID dest) { @@ -165,6 +166,16 @@ public: m_assembler.movl_i32r(initialValue.asIntptr(), dest); return DataLabelPtr(this); } + + Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1)) + { + ASSERT(mask.m_value >= -128 && mask.m_value <= 255); + if (mask.m_value == -1) + m_assembler.cmpb_im(0, address.m_ptr); + else + m_assembler.testb_im(mask.m_value, address.m_ptr); + return Jump(m_assembler.jCC(x86Condition(cond))); + } Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0)) { diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h b/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h index e398dcdad..432489dbc 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h @@ -1408,6 +1408,16 @@ public: m_assembler.nop(); } + static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination) + { + X86Assembler::replaceWithJump(instructionStart.executableAddress(), destination.executableAddress()); + } + + static ptrdiff_t maxJumpReplacementSize() + { + return X86Assembler::maxJumpReplacementSize(); + } + protected: X86Assembler::Condition x86Condition(RelationalCondition cond) { diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h b/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h index 41479f996..fa95b335b 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2012 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -513,6 +513,12 @@ public: MacroAssemblerX86Common::move(addr, scratchRegister); return MacroAssemblerX86Common::branchTest8(cond, BaseIndex(scratchRegister, address.base, TimesOne), mask); } + + Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1)) + { + MacroAssemblerX86Common::move(TrustedImmPtr(address.m_ptr), scratchRegister); + return MacroAssemblerX86Common::branchTest8(cond, Address(scratchRegister), mask); + } static bool supportsFloatingPoint() { return true; } // See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate() diff --git a/Source/JavaScriptCore/assembler/X86Assembler.h b/Source/JavaScriptCore/assembler/X86Assembler.h index ff8d25bcd..8c5606972 100644 --- a/Source/JavaScriptCore/assembler/X86Assembler.h +++ b/Source/JavaScriptCore/assembler/X86Assembler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2012 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -247,6 +247,8 @@ private: public: X86Assembler() + : m_indexOfLastWatchpoint(INT_MIN) + , m_indexOfTailOfLastWatchpoint(INT_MIN) { } @@ -798,6 +800,14 @@ public: m_formatter.oneByteOp(OP_GROUP1_EbIb, GROUP1_OP_CMP, base, index, scale, offset); m_formatter.immediate8(imm); } + +#if CPU(X86) + void cmpb_im(int imm, const void* addr) + { + m_formatter.oneByteOp(OP_GROUP1_EbIb, GROUP1_OP_CMP, addr); + m_formatter.immediate8(imm); + } +#endif void cmpl_im(int imm, int offset, RegisterID base, RegisterID index, int scale) { @@ -948,6 +958,14 @@ public: m_formatter.immediate8(imm); } +#if CPU(X86) + void testb_im(int imm, const void* addr) + { + m_formatter.oneByteOp(OP_GROUP3_EbIb, GROUP3_OP_TEST, addr); + m_formatter.immediate8(imm); + } +#endif + void testl_i32m(int imm, int offset, RegisterID base, RegisterID index, int scale) { m_formatter.oneByteOp(OP_GROUP3_EvIz, GROUP3_OP_TEST, base, index, scale, offset); @@ -1702,10 +1720,25 @@ public: { return m_formatter.codeSize(); } + + AssemblerLabel labelForWatchpoint() + { + AssemblerLabel result = m_formatter.label(); + if (static_cast<int>(result.m_offset) != m_indexOfLastWatchpoint) + result = label(); + m_indexOfLastWatchpoint = result.m_offset; + m_indexOfTailOfLastWatchpoint = result.m_offset + maxJumpReplacementSize(); + return result; + } AssemblerLabel label() { - return m_formatter.label(); + AssemblerLabel result = m_formatter.label(); + while (UNLIKELY(static_cast<int>(result.m_offset) < m_indexOfTailOfLastWatchpoint)) { + nop(); + result = m_formatter.label(); + } + return result; } AssemblerLabel align(int alignment) @@ -1787,6 +1820,20 @@ public: return reinterpret_cast<void**>(where)[-1]; } + static void replaceWithJump(void* instructionStart, void* to) + { + uint8_t* ptr = reinterpret_cast<uint8_t*>(instructionStart); + uint8_t* dstPtr = reinterpret_cast<uint8_t*>(to); + intptr_t distance = (intptr_t)(dstPtr - (ptr + 5)); + ptr[0] = static_cast<uint8_t>(OP_JMP_rel32); + *reinterpret_cast<int32_t*>(ptr + 1) = static_cast<int32_t>(distance); + } + + static ptrdiff_t maxJumpReplacementSize() + { + return 5; + } + static unsigned getCallReturnOffset(AssemblerLabel call) { ASSERT(call.isSet()); @@ -2339,6 +2386,8 @@ private: AssemblerBuffer m_buffer; } m_formatter; + int m_indexOfLastWatchpoint; + int m_indexOfTailOfLastWatchpoint; }; } // namespace JSC |