]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - ftl/FTLStackMaps.cpp
JavaScriptCore-7600.1.4.9.tar.gz
[apple/javascriptcore.git] / ftl / FTLStackMaps.cpp
diff --git a/ftl/FTLStackMaps.cpp b/ftl/FTLStackMaps.cpp
new file mode 100644 (file)
index 0000000..a8ce12b
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2013, 2014 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 "FTLStackMaps.h"
+
+#if ENABLE(FTL_JIT)
+
+#include "FTLLocation.h"
+#include <wtf/CommaPrinter.h>
+#include <wtf/DataLog.h>
+#include <wtf/ListDump.h>
+
+namespace JSC { namespace FTL {
+
+template<typename T>
+T readObject(StackMaps::ParseContext& context)
+{
+    T result;
+    result.parse(context);
+    return result;
+}
+
+void StackMaps::Constant::parse(StackMaps::ParseContext& context)
+{
+    integer = context.view->read<int64_t>(context.offset, true);
+}
+
+void StackMaps::Constant::dump(PrintStream& out) const
+{
+    out.printf("0x%016llx", static_cast<unsigned long long>(integer));
+}
+
+void StackMaps::StackSize::parse(StackMaps::ParseContext& context)
+{
+    switch (context.version) {
+    case 0:
+        functionOffset = context.view->read<uint32_t>(context.offset, true);
+        size = context.view->read<uint32_t>(context.offset, true);
+        break;
+        
+    default:
+        functionOffset = context.view->read<uint64_t>(context.offset, true);
+        size = context.view->read<uint64_t>(context.offset, true);
+        break;
+    }
+}
+
+void StackMaps::StackSize::dump(PrintStream& out) const
+{
+    out.print("(off:", functionOffset, ", size:", size, ")");
+}
+
+void StackMaps::Location::parse(StackMaps::ParseContext& context)
+{
+    kind = static_cast<Kind>(context.view->read<uint8_t>(context.offset, true));
+    size = context.view->read<uint8_t>(context.offset, true);
+    dwarfReg = DWARFRegister(context.view->read<uint16_t>(context.offset, true));
+    this->offset = context.view->read<int32_t>(context.offset, true);
+}
+
+void StackMaps::Location::dump(PrintStream& out) const
+{
+    out.print("(", kind, ", ", dwarfReg, ", off:", offset, ", size:", size, ")");
+}
+
+GPRReg StackMaps::Location::directGPR() const
+{
+    return FTL::Location::forStackmaps(nullptr, *this).directGPR();
+}
+
+void StackMaps::Location::restoreInto(
+    MacroAssembler& jit, StackMaps& stackmaps, char* savedRegisters, GPRReg result) const
+{
+    FTL::Location::forStackmaps(&stackmaps, *this).restoreInto(jit, savedRegisters, result);
+}
+
+void StackMaps::LiveOut::parse(StackMaps::ParseContext& context)
+{
+    dwarfReg = DWARFRegister(context.view->read<uint16_t>(context.offset, true)); // regnum
+    context.view->read<uint8_t>(context.offset, true); // reserved
+    size = context.view->read<uint8_t>(context.offset, true); // size in bytes
+}
+
+void StackMaps::LiveOut::dump(PrintStream& out) const
+{
+    out.print("(", dwarfReg, ", ", size, ")");
+}
+
+bool StackMaps::Record::parse(StackMaps::ParseContext& context)
+{
+    int64_t id = context.view->read<int64_t>(context.offset, true);
+    ASSERT(static_cast<int32_t>(id) == id);
+    patchpointID = static_cast<uint32_t>(id);
+    if (static_cast<int32_t>(patchpointID) < 0)
+        return false;
+    
+    instructionOffset = context.view->read<uint32_t>(context.offset, true);
+    flags = context.view->read<uint16_t>(context.offset, true);
+    
+    unsigned length = context.view->read<uint16_t>(context.offset, true);
+    while (length--)
+        locations.append(readObject<Location>(context));
+    
+    if (context.version >= 1)
+        context.view->read<uint16_t>(context.offset, true); // padding
+
+    unsigned numLiveOuts = context.view->read<uint16_t>(context.offset, true);
+    while (numLiveOuts--)
+        liveOuts.append(readObject<LiveOut>(context));
+
+    if (context.version >= 1) {
+        if (context.offset & 7) {
+            ASSERT(!(context.offset & 3));
+            context.view->read<uint32_t>(context.offset, true); // padding
+        }
+    }
+    
+    return true;
+}
+
+void StackMaps::Record::dump(PrintStream& out) const
+{
+    out.print(
+        "(#", patchpointID, ", offset = ", instructionOffset, ", flags = ", flags,
+        ", locations = [", listDump(locations), "], liveOuts = [",
+        listDump(liveOuts), "])");
+}
+
+RegisterSet StackMaps::Record::locationSet() const
+{
+    RegisterSet result;
+    for (unsigned i = locations.size(); i--;) {
+        Reg reg = locations[i].dwarfReg.reg();
+        if (!reg)
+            continue;
+        result.set(reg);
+    }
+    return result;
+}
+
+RegisterSet StackMaps::Record::liveOutsSet() const
+{
+    RegisterSet result;
+    for (unsigned i = liveOuts.size(); i--;) {
+        LiveOut liveOut = liveOuts[i];
+        Reg reg = liveOut.dwarfReg.reg();
+        // FIXME: Either assert that size is not greater than sizeof(pointer), or actually
+        // save the high bits of registers.
+        // https://bugs.webkit.org/show_bug.cgi?id=130885
+        if (!reg) {
+            dataLog("Invalid liveOuts entry in: ", *this, "\n");
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+        result.set(reg);
+    }
+    return result;
+}
+
+RegisterSet StackMaps::Record::usedRegisterSet() const
+{
+    RegisterSet result;
+    result.merge(locationSet());
+    result.merge(liveOutsSet());
+    return result;
+}
+
+bool StackMaps::parse(DataView* view)
+{
+    ParseContext context;
+    context.offset = 0;
+    context.view = view;
+    
+    version = context.version = context.view->read<uint8_t>(context.offset, true);
+
+    context.view->read<uint8_t>(context.offset, true); // Reserved
+    context.view->read<uint8_t>(context.offset, true); // Reserved
+    context.view->read<uint8_t>(context.offset, true); // Reserved
+
+    uint32_t numFunctions;
+    uint32_t numConstants;
+    uint32_t numRecords;
+    
+    numFunctions = context.view->read<uint32_t>(context.offset, true);
+    if (context.version >= 1) {
+        numConstants = context.view->read<uint32_t>(context.offset, true);
+        numRecords = context.view->read<uint32_t>(context.offset, true);
+    }
+    while (numFunctions--)
+        stackSizes.append(readObject<StackSize>(context));
+    
+    if (!context.version)
+        numConstants = context.view->read<uint32_t>(context.offset, true);
+    while (numConstants--)
+        constants.append(readObject<Constant>(context));
+    
+    if (!context.version)
+        numRecords = context.view->read<uint32_t>(context.offset, true);
+    while (numRecords--) {
+        Record record;
+        if (!record.parse(context))
+            return false;
+        records.append(record);
+    }
+    
+    return true;
+}
+
+void StackMaps::dump(PrintStream& out) const
+{
+    out.print("Version:", version, ", StackSizes[", listDump(stackSizes), "], Constants:[", listDump(constants), "], Records:[", listDump(records), "]");
+}
+
+void StackMaps::dumpMultiline(PrintStream& out, const char* prefix) const
+{
+    out.print(prefix, "Version: ", version, "\n");
+    out.print(prefix, "StackSizes:\n");
+    for (unsigned i = 0; i < stackSizes.size(); ++i)
+        out.print(prefix, "    ", stackSizes[i], "\n");
+    out.print(prefix, "Constants:\n");
+    for (unsigned i = 0; i < constants.size(); ++i)
+        out.print(prefix, "    ", constants[i], "\n");
+    out.print(prefix, "Records:\n");
+    for (unsigned i = 0; i < records.size(); ++i)
+        out.print(prefix, "    ", records[i], "\n");
+}
+
+StackMaps::RecordMap StackMaps::computeRecordMap() const
+{
+    RecordMap result;
+    for (unsigned i = records.size(); i--;)
+        result.add(records[i].patchpointID, Vector<Record>()).iterator->value.append(records[i]);
+    return result;
+}
+
+unsigned StackMaps::stackSize() const
+{
+    RELEASE_ASSERT(stackSizes.size() == 1);
+
+    return stackSizes[0].size;
+}
+
+} } // namespace JSC::FTL
+
+namespace WTF {
+
+using namespace JSC::FTL;
+
+void printInternal(PrintStream& out, StackMaps::Location::Kind kind)
+{
+    switch (kind) {
+    case StackMaps::Location::Unprocessed:
+        out.print("Unprocessed");
+        return;
+    case StackMaps::Location::Register:
+        out.print("Register");
+        return;
+    case StackMaps::Location::Direct:
+        out.print("Direct");
+        return;
+    case StackMaps::Location::Indirect:
+        out.print("Indirect");
+        return;
+    case StackMaps::Location::Constant:
+        out.print("Constant");
+        return;
+    case StackMaps::Location::ConstantIndex:
+        out.print("ConstantIndex");
+        return;
+    }
+    dataLog("Unrecognized kind: ", static_cast<int>(kind), "\n");
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+} // namespace WTF
+
+#endif // ENABLE(FTL_JIT)
+