diff options
author | Konstantin Tokarev <annulen@yandex.ru> | 2016-08-25 19:20:41 +0300 |
---|---|---|
committer | Konstantin Tokarev <annulen@yandex.ru> | 2017-02-02 12:30:55 +0000 |
commit | 6882a04fb36642862b11efe514251d32070c3d65 (patch) | |
tree | b7959826000b061fd5ccc7512035c7478742f7b0 /Source/JavaScriptCore/jit/PCToCodeOriginMap.cpp | |
parent | ab6df191029eeeb0b0f16f127d553265659f739e (diff) | |
download | qtwebkit-6882a04fb36642862b11efe514251d32070c3d65.tar.gz |
Imported QtWebKit TP3 (git b57bc6801f1876c3220d5a4bfea33d620d477443)
Change-Id: I3b1d8a2808782c9f34d50240000e20cb38d3680f
Reviewed-by: Konstantin Tokarev <annulen@yandex.ru>
Diffstat (limited to 'Source/JavaScriptCore/jit/PCToCodeOriginMap.cpp')
-rw-r--r-- | Source/JavaScriptCore/jit/PCToCodeOriginMap.cpp | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/jit/PCToCodeOriginMap.cpp b/Source/JavaScriptCore/jit/PCToCodeOriginMap.cpp new file mode 100644 index 000000000..8676d2de0 --- /dev/null +++ b/Source/JavaScriptCore/jit/PCToCodeOriginMap.cpp @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2016 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 "PCToCodeOriginMap.h" + +#if ENABLE(JIT) + +#include "B3PCToOriginMap.h" +#include "DFGNode.h" +#include "LinkBuffer.h" + +namespace JSC { + +namespace { + +class DeltaCompressionBuilder { +public: + DeltaCompressionBuilder(size_t maxSize) + : m_offset(0) + , m_maxSize(maxSize) + { + m_buffer = static_cast<uint8_t*>(fastMalloc(m_maxSize)); + } + + template <typename T> + void write(T item) + { + RELEASE_ASSERT(m_offset + sizeof(T) <= m_maxSize); + static const uint8_t mask = std::numeric_limits<uint8_t>::max(); + for (unsigned i = 0; i < sizeof(T); i++) { + *(m_buffer + m_offset) = static_cast<uint8_t>(item & mask); + item = item >> (sizeof(uint8_t) * 8); + m_offset += 1; + } + } + + uint8_t* m_buffer; + size_t m_offset; + size_t m_maxSize; +}; + +class DeltaCompresseionReader { +public: + DeltaCompresseionReader(uint8_t* buffer, size_t size) + : m_buffer(buffer) + , m_size(size) + , m_offset(0) + { } + + template <typename T> + T read() + { + RELEASE_ASSERT(m_offset + sizeof(T) <= m_size); + T result = 0; + for (unsigned i = 0; i < sizeof(T); i++) { + uint8_t bitsAsInt8 = *(m_buffer + m_offset); + T bits = static_cast<T>(bitsAsInt8); + bits = bits << (sizeof(uint8_t) * 8 * i); + result |= bits; + m_offset += 1; + } + return result; + } + +private: + uint8_t* m_buffer; + size_t m_size; + size_t m_offset; +}; + +} // anonymous namespace + +PCToCodeOriginMapBuilder::PCToCodeOriginMapBuilder(VM& vm) + : m_vm(vm) + , m_shouldBuildMapping(vm.shouldBuilderPCToCodeOriginMapping()) +{ } + +PCToCodeOriginMapBuilder::PCToCodeOriginMapBuilder(PCToCodeOriginMapBuilder&& other) + : m_vm(other.m_vm) + , m_codeRanges(WTFMove(other.m_codeRanges)) + , m_shouldBuildMapping(other.m_shouldBuildMapping) +{ } + +#if ENABLE(FTL_JIT) +PCToCodeOriginMapBuilder::PCToCodeOriginMapBuilder(VM& vm, B3::PCToOriginMap&& b3PCToOriginMap) + : m_vm(vm) + , m_shouldBuildMapping(vm.shouldBuilderPCToCodeOriginMapping()) +{ + if (!m_shouldBuildMapping) + return; + + for (const B3::PCToOriginMap::OriginRange& originRange : b3PCToOriginMap.ranges()) { + DFG::Node* node = bitwise_cast<DFG::Node*>(originRange.origin.data()); + if (node) + appendItem(originRange.label, node->origin.semantic); + else + appendItem(originRange.label, PCToCodeOriginMapBuilder::defaultCodeOrigin()); + } +} +#endif + +void PCToCodeOriginMapBuilder::appendItem(MacroAssembler::Label label, const CodeOrigin& codeOrigin) +{ + if (!m_shouldBuildMapping) + return; + + if (m_codeRanges.size()) { + if (m_codeRanges.last().end == label) + return; + m_codeRanges.last().end = label; + if (m_codeRanges.last().codeOrigin == codeOrigin || !codeOrigin) + return; + } + + m_codeRanges.append(CodeRange{label, label, codeOrigin}); +} + + +static const uint8_t sentinelPCDelta = 0; +static const int8_t sentinelBytecodeDelta = 0; + +PCToCodeOriginMap::PCToCodeOriginMap(PCToCodeOriginMapBuilder&& builder, LinkBuffer& linkBuffer) +{ + RELEASE_ASSERT(builder.didBuildMapping()); + + if (!builder.m_codeRanges.size()) { + m_pcRangeStart = std::numeric_limits<uintptr_t>::max(); + m_pcRangeEnd = std::numeric_limits<uintptr_t>::max(); + + m_compressedPCBufferSize = 0; + m_compressedPCs = nullptr; + + m_compressedCodeOriginsSize = 0; + m_compressedCodeOrigins = nullptr; + + return; + } + + // We do a final touch-up on the last range here because of how we generate the table. + // The final range (if non empty) would be ignored if we didn't append any (arbitrary) + // range as the last item of the vector. + PCToCodeOriginMapBuilder::CodeRange& last = builder.m_codeRanges.last(); + if (!(last.start == last.end)) + builder.m_codeRanges.append(PCToCodeOriginMapBuilder::CodeRange{ last.end, last.end, last.codeOrigin }); // This range will never actually be found, but it ensures the real last range is found. + + DeltaCompressionBuilder pcCompressor((sizeof(uintptr_t) + sizeof(uint8_t)) * builder.m_codeRanges.size()); + void* lastPCValue = nullptr; + auto buildPCTable = [&] (void* pcValue) { + RELEASE_ASSERT(pcValue > lastPCValue); + uintptr_t delta = bitwise_cast<uintptr_t>(pcValue) - bitwise_cast<uintptr_t>(lastPCValue); + RELEASE_ASSERT(delta != sentinelPCDelta); + lastPCValue = pcValue; + if (delta > std::numeric_limits<uint8_t>::max()) { + pcCompressor.write<uint8_t>(sentinelPCDelta); + pcCompressor.write<uintptr_t>(delta); + return; + } + + pcCompressor.write<uint8_t>(static_cast<uint8_t>(delta)); + }; + + DeltaCompressionBuilder codeOriginCompressor((sizeof(intptr_t) + sizeof(int8_t) + sizeof(int8_t) + sizeof(InlineCallFrame*)) * builder.m_codeRanges.size()); + CodeOrigin lastCodeOrigin(0, nullptr); + auto buildCodeOriginTable = [&] (const CodeOrigin& codeOrigin) { + intptr_t delta = static_cast<intptr_t>(codeOrigin.bytecodeIndex) - static_cast<intptr_t>(lastCodeOrigin.bytecodeIndex); + lastCodeOrigin = codeOrigin; + if (delta > std::numeric_limits<int8_t>::max() || delta < std::numeric_limits<int8_t>::min() || delta == sentinelBytecodeDelta) { + codeOriginCompressor.write<int8_t>(sentinelBytecodeDelta); + codeOriginCompressor.write<intptr_t>(delta); + } else + codeOriginCompressor.write<int8_t>(static_cast<int8_t>(delta)); + + int8_t hasInlineCallFrameByte = codeOrigin.inlineCallFrame ? 1 : 0; + codeOriginCompressor.write<int8_t>(hasInlineCallFrameByte); + if (hasInlineCallFrameByte) + codeOriginCompressor.write<uintptr_t>(bitwise_cast<uintptr_t>(codeOrigin.inlineCallFrame)); + }; + + m_pcRangeStart = bitwise_cast<uintptr_t>(linkBuffer.locationOf(builder.m_codeRanges.first().start).dataLocation()); + m_pcRangeEnd = bitwise_cast<uintptr_t>(linkBuffer.locationOf(builder.m_codeRanges.last().end).dataLocation()); + m_pcRangeEnd -= 1; + + for (unsigned i = 0; i < builder.m_codeRanges.size(); i++) { + PCToCodeOriginMapBuilder::CodeRange& codeRange = builder.m_codeRanges[i]; + void* start = linkBuffer.locationOf(codeRange.start).dataLocation(); + void* end = linkBuffer.locationOf(codeRange.end).dataLocation(); + ASSERT(m_pcRangeStart <= bitwise_cast<uintptr_t>(start)); + ASSERT(m_pcRangeEnd >= bitwise_cast<uintptr_t>(end) - 1); + if (start == end) + ASSERT(i == builder.m_codeRanges.size() - 1); + if (i > 0) + ASSERT(linkBuffer.locationOf(builder.m_codeRanges[i - 1].end).dataLocation() == start); + + buildPCTable(start); + buildCodeOriginTable(codeRange.codeOrigin); + } + + m_compressedPCBufferSize = pcCompressor.m_offset; + m_compressedPCs = static_cast<uint8_t*>(fastRealloc(pcCompressor.m_buffer, m_compressedPCBufferSize)); + + m_compressedCodeOriginsSize = codeOriginCompressor.m_offset; + m_compressedCodeOrigins = static_cast<uint8_t*>(fastRealloc(codeOriginCompressor.m_buffer, m_compressedCodeOriginsSize)); +} + +PCToCodeOriginMap::~PCToCodeOriginMap() +{ + if (m_compressedPCs) + fastFree(m_compressedPCs); + if (m_compressedCodeOrigins) + fastFree(m_compressedCodeOrigins); +} + +double PCToCodeOriginMap::memorySize() +{ + double size = 0; + size += m_compressedPCBufferSize; + size += m_compressedCodeOriginsSize; + return size; +} + +Optional<CodeOrigin> PCToCodeOriginMap::findPC(void* pc) const +{ + uintptr_t pcAsInt = bitwise_cast<uintptr_t>(pc); + if (!(m_pcRangeStart <= pcAsInt && pcAsInt <= m_pcRangeEnd)) + return Nullopt; + + uintptr_t currentPC = 0; + CodeOrigin currentCodeOrigin(0, nullptr); + + DeltaCompresseionReader pcReader(m_compressedPCs, m_compressedPCBufferSize); + DeltaCompresseionReader codeOriginReader(m_compressedCodeOrigins, m_compressedCodeOriginsSize); + while (true) { + uintptr_t previousPC = currentPC; + { + uint8_t value = pcReader.read<uint8_t>(); + uintptr_t delta; + if (value == sentinelPCDelta) + delta = pcReader.read<uintptr_t>(); + else + delta = value; + currentPC += delta; + } + + CodeOrigin previousOrigin = currentCodeOrigin; + { + int8_t value = codeOriginReader.read<int8_t>(); + intptr_t delta; + if (value == sentinelBytecodeDelta) + delta = codeOriginReader.read<intptr_t>(); + else + delta = static_cast<intptr_t>(value); + + currentCodeOrigin.bytecodeIndex = static_cast<unsigned>(static_cast<intptr_t>(currentCodeOrigin.bytecodeIndex) + delta); + + int8_t hasInlineFrame = codeOriginReader.read<int8_t>(); + ASSERT(hasInlineFrame == 0 || hasInlineFrame == 1); + if (hasInlineFrame) + currentCodeOrigin.inlineCallFrame = bitwise_cast<InlineCallFrame*>(codeOriginReader.read<uintptr_t>()); + else + currentCodeOrigin.inlineCallFrame = nullptr; + } + + if (previousPC) { + uintptr_t startOfRange = previousPC; + // We subtract 1 because we generate end points inclusively in this table, even though we are interested in ranges of the form: [previousPC, currentPC) + uintptr_t endOfRange = currentPC - 1; + if (startOfRange <= pcAsInt && pcAsInt <= endOfRange) + return Optional<CodeOrigin>(previousOrigin); // We return previousOrigin here because CodeOrigin's are mapped to the startValue of the range. + } + } + + RELEASE_ASSERT_NOT_REACHED(); + return Nullopt; +} + +} // namespace JSC + +#endif // ENABLE(JIT) |