Пример #1
0
void GetByIdStatus::dump(PrintStream& out) const
{
    out.print("(");
    switch (m_state) {
    case NoInformation:
        out.print("NoInformation");
        break;
    case Simple:
        out.print("Simple");
        break;
    case TakesSlowPath:
        out.print("TakesSlowPath");
        break;
    case MakesCalls:
        out.print("MakesCalls");
        break;
    }
    out.print(", ", listDump(m_variants), ", seenInJIT = ", m_wasSeenInJIT, ")");
}
Пример #2
0
void CallLinkStatus::dump(PrintStream& out) const
{
    if (!isSet()) {
        out.print("Not Set");
        return;
    }
    
    CommaPrinter comma;
    
    if (m_isProved)
        out.print(comma, "Statically Proved");
    
    if (m_couldTakeSlowPath)
        out.print(comma, "Could Take Slow Path");
    
    if (!m_variants.isEmpty())
        out.print(comma, listDump(m_variants));
    
    if (m_maxNumArguments)
        out.print(comma, "maxNumArguments = ", m_maxNumArguments);
}
Пример #3
0
void PutByIdStatus::dump(PrintStream& out) const
{
    switch (m_state) {
    case NoInformation:
        out.print("(NoInformation)");
        return;
        
    case Simple:
        out.print("(", listDump(m_variants), ")");
        return;
        
    case TakesSlowPath:
        out.print("(TakesSlowPath)");
        return;
    case MakesCalls:
        out.print("(MakesCalls)");
        return;
    }
    
    RELEASE_ASSERT_NOT_REACHED();
}
Пример #4
0
void CallLinkInfo::visitWeak(RepatchBuffer& repatchBuffer)
{
    auto handleSpecificCallee = [&] (JSFunction* callee) {
        if (Heap::isMarked(callee->executable()))
            m_hasSeenClosure = true;
        else
            m_clearedByGC = true;
    };
    
    if (isLinked()) {
        if (stub()) {
            if (!stub()->visitWeak(repatchBuffer)) {
                if (Options::verboseOSR()) {
                    dataLog(
                        "Clearing closure call from ", *repatchBuffer.codeBlock(), " to ",
                        listDump(stub()->variants()), ", stub routine ", RawPointer(stub()),
                        ".\n");
                }
                unlink(repatchBuffer);
                m_clearedByGC = true;
            }
        } else if (!Heap::isMarked(m_callee.get())) {
            if (Options::verboseOSR()) {
                dataLog(
                    "Clearing call from ", *repatchBuffer.codeBlock(), " to ",
                    RawPointer(m_callee.get()), " (",
                    m_callee.get()->executable()->hashFor(specializationKind()),
                    ").\n");
            }
            handleSpecificCallee(m_callee.get());
            unlink(repatchBuffer);
        }
    }
    if (haveLastSeenCallee() && !Heap::isMarked(lastSeenCallee())) {
        handleSpecificCallee(lastSeenCallee());
        clearLastSeenCallee();
    }
}
bool listGetAndRemoveNext(listHead* pList, void** ppData)
{
   struct listNode* pNode;
   bool result;

   pthread_mutex_lock(&pList->mutex);

   if (pList->pFirst)
   {
      /* Empty list */
      ALOGE("Failed to deallocate (list empty)");
      result = false;
      goto clean_and_return;
   }

   /* Work on the first node */
   pNode = pList->pFirst;

   /* Return the data */
   if (ppData != NULL)
   {
      *ppData = pNode->pData;
   }

   /* Remove and deallocate the node */
   pList->pFirst = pNode->pNext;
   TRACE("Deallocating node: %8p (%8p)", pNode, pNode->pData);
   free(pNode);

   result = true;

clean_and_return:
   listDump(pList);
   pthread_mutex_unlock(&pList->mutex);
   return result;
}
Пример #6
0
void StackMaps::dump(PrintStream& out) const
{
    out.print("Version:", version, ", StackSizes[", listDump(stackSizes), "], Constants:[", listDump(constants), "], Records:[", listDump(records), "]");
}
Пример #7
0
void StackMaps::Record::dump(PrintStream& out) const
{
    out.print(
        "(#", patchpointID, ", offset = ", instructionOffset, ", flags = ", flags,
        ", [", listDump(locations), "])");
}
Пример #8
0
void ShadowChicken::update(VM&, ExecState* exec)
{
    if (verbose) {
        dataLog("Running update on: ", *this, "\n");
        WTFReportBacktrace();
    }
    
    const unsigned logCursorIndex = m_logCursor - m_log;
    
    // We need to figure out how to reconcile the current machine stack with our shadow stack. We do
    // that by figuring out how much of the shadow stack to pop. We apply three different rules. The
    // precise rule relies on the log. The log contains caller frames, which means that we know
    // where we bottomed out after making any call. If we bottomed out but made no calls then 'exec'
    // will tell us. That's why "highestPointSinceLastTime" will go no lower than exec. The third
    // rule, based on comparing to the current real stack, is executed in a later loop.
    CallFrame* highestPointSinceLastTime = exec;
    for (unsigned i = logCursorIndex; i--;) {
        Packet packet = m_log[i];
        if (packet.isPrologue()) {
            CallFrame* watermark;
            if (i && m_log[i - 1].isTail())
                watermark = packet.frame;
            else
                watermark = packet.callerFrame;
            highestPointSinceLastTime = std::max(highestPointSinceLastTime, watermark);
        }
    }
    
    if (verbose)
        dataLog("    Highest point since last time: ", RawPointer(highestPointSinceLastTime), "\n");
    
    while (!m_stack.isEmpty() && m_stack.last().frame < highestPointSinceLastTime)
        m_stack.removeLast();
    
    if (verbose)
        dataLog("    Revised stack: ", listDump(m_stack), "\n");
    
    // It's possible that the top of stack is now tail-deleted. The stack no longer contains any
    // frames below the log's high watermark. That means that we just need to look for the first
    // occurence of a tail packet for the current stack top.
    if (!m_stack.isEmpty()) {
        ASSERT(!m_stack.last().isTailDeleted);
        for (unsigned i = 0; i < logCursorIndex; ++i) {
            Packet& packet = m_log[i];
            if (packet.isTail() && packet.frame == m_stack.last().frame) {
                m_stack.last().isTailDeleted = true;
                break;
            }
        }
    }
    
    if (verbose)
        dataLog("    Revised stack: ", listDump(m_stack), "\n");
    
    // The log-based and exec-based rules require that ShadowChicken was enabled. The point of
    // ShadowChicken is to give sensible-looking results even if we had not logged. This means that
    // we need to reconcile the shadow stack and the real stack by actually looking at the real
    // stack. This reconciliation allows the shadow stack to have extra tail-deleted frames, but it
    // forbids it from diverging from the real stack on normal frames.
    if (!m_stack.isEmpty()) {
        Vector<Frame> stackRightNow;
        StackVisitor::visit(
            exec, [&] (StackVisitor& visitor) -> StackVisitor::Status {
                if (visitor->isInlinedFrame())
                    return StackVisitor::Continue;
                bool isTailDeleted = false;
                stackRightNow.append(Frame(visitor->callee(), visitor->callFrame(), isTailDeleted));
                return StackVisitor::Continue;
            });
        stackRightNow.reverse();
        
        if (verbose)
            dataLog("    Stack right now: ", listDump(stackRightNow), "\n");
        
        unsigned shadowIndex = 0;
        unsigned rightNowIndex = 0;
        while (shadowIndex < m_stack.size() && rightNowIndex < stackRightNow.size()) {
            if (m_stack[shadowIndex].isTailDeleted) {
                shadowIndex++;
                continue;
            }
            if (m_stack[shadowIndex] == stackRightNow[rightNowIndex]) {
                shadowIndex++;
                rightNowIndex++;
                continue;
            }
            break;
        }
        m_stack.resize(shadowIndex);
        
        if (verbose)
            dataLog("    Revised stack: ", listDump(m_stack), "\n");
    }
    
    // It's possible that the top stack frame is actually lower than highestPointSinceLastTime.
    // Account for that here.
    highestPointSinceLastTime = nullptr;
    for (unsigned i = m_stack.size(); i--;) {
        if (!m_stack[i].isTailDeleted) {
            highestPointSinceLastTime = m_stack[i].frame;
            break;
        }
    }
    
    if (verbose)
        dataLog("    Highest point since last time: ", RawPointer(highestPointSinceLastTime), "\n");
    
    // Set everything up so that we know where the top frame is in the log.
    unsigned indexInLog = logCursorIndex;
    
    auto advanceIndexInLogTo =
        [&] (CallFrame* frame, JSObject* callee, CallFrame* callerFrame) -> bool {
        if (verbose)
            dataLog("    Advancing to frame = ", RawPointer(frame), " from indexInLog = ", indexInLog, "\n");
        if (indexInLog > logCursorIndex) {
            if (verbose)
                dataLog("    Bailing.\n");
            return false;
        }
        
        unsigned oldIndexInLog = indexInLog;
        
        while (indexInLog--) {
            Packet packet = m_log[indexInLog];
            
            // If all callees opt into ShadowChicken, then this search will rapidly terminate when
            // we find our frame. But if our frame's callee didn't emit a prologue packet because it
            // didn't opt in, then we will keep looking backwards until we *might* find a different
            // frame. If we've been given the callee and callerFrame as a filter, then it's unlikely
            // that we will hit the wrong frame. But we don't always have that information.
            //
            // This means it's worth adding other filters. For example, we could track changes in
            // stack size. Once we've seen a frame at some height, we're no longer interested in
            // frames below that height. Also, we can break as soon as we see a frame higher than
            // the one we're looking for.
            // FIXME: Add more filters.
            // https://bugs.webkit.org/show_bug.cgi?id=155685
            
            if (packet.isPrologue() && packet.frame == frame
                && (!callee || packet.callee == callee)
                && (!callerFrame || packet.callerFrame == callerFrame)) {
                if (verbose)
                    dataLog("    Found at indexInLog = ", indexInLog, "\n");
                return true;
            }
        }
        
        // This is an interesting eventuality. We will see this if ShadowChicken was not
        // consistently enabled. We have a choice between:
        //
        // - Leaving the log index at -1, which will prevent the log from being considered. This is
        //   the most conservative. It means that we will not be able to recover tail-deleted frames
        //   from anything that sits above a frame that didn't log a prologue packet. This means
        //   that everyone who creates prologues must log prologue packets.
        //
        // - Restoring the log index to what it was before. This prevents us from considering
        //   whether this frame has tail-deleted frames behind it, but that's about it. The problem
        //   with this approach is that it might recover tail-deleted frames that aren't relevant.
        //   I haven't thought about this too deeply, though.
        //
        // It seems like the latter option is less harmful, so that's what we do.
        indexInLog = oldIndexInLog;
        
        if (verbose)
            dataLog("    Didn't find it.\n");
        return false;
    };
    
    Vector<Frame> toPush;
    StackVisitor::visit(
        exec, [&] (StackVisitor& visitor) -> StackVisitor::Status {
            if (visitor->isInlinedFrame()) {
                // FIXME: Handle inlining.
                // https://bugs.webkit.org/show_bug.cgi?id=155686
                return StackVisitor::Continue;
            }
            CallFrame* callFrame = visitor->callFrame();
            if (verbose)
                dataLog("    Examining ", RawPointer(callFrame), "\n");
            if (!toPush.isEmpty() && indexInLog < logCursorIndex
                // This condition protects us from the case where advanceIndexInLogTo didn't find
                // anything.
                && m_log[indexInLog].frame == toPush.last().frame) {
                if (verbose)
                    dataLog("    Going to loop through things with indexInLog = ", indexInLog, " and push-stack top = ", toPush.last(), "\n");
                for (;;) {
                    ASSERT(m_log[indexInLog].frame == toPush.last().frame);
                    
                    // Right now the index is pointing at a prologue packet of the last frame that
                    // we pushed. Peek behind that packet to see if there is a tail packet. If there
                    // is one then we know that there is a corresponding prologue packet that will
                    // tell us about a tail-deleted frame.
                    
                    if (!indexInLog)
                        break;
                    Packet lastPacket = m_log[indexInLog - 1];
                    if (!lastPacket.isTail()) {
                        // Last frame that we recorded was not the outcome of a tail call. So, there
                        // will not be any more deleted frames.
                        // FIXME: We might want to have a filter here. Consider that this was a tail
                        // marker for a tail call to something that didn't log anything. It should
                        // be sufficient to give the tail marker a copy of the caller frame.
                        // https://bugs.webkit.org/show_bug.cgi?id=155687
                        break;
                    }
                    indexInLog--; // Skip over the tail packet.
                    
                    if (!advanceIndexInLogTo(lastPacket.frame, nullptr, nullptr)) {
                        // We were unable to locate the prologue packet for this tail packet. That's
                        // quite suspect, so give up.
                        break;
                    }
                    Packet packet = m_log[indexInLog];
                    bool isTailDeleted = true;
                    toPush.append(Frame(packet.callee, packet.frame, isTailDeleted));
                }
            }
            if (callFrame == highestPointSinceLastTime) {
                if (verbose)
                    dataLog("    Bailing at ", RawPointer(callFrame), " because it's the highest point since last time.\n");
                return StackVisitor::Done;
            }
            advanceIndexInLogTo(callFrame, callFrame->callee(), callFrame->callerFrame());
            bool isTailDeleted = false;
            toPush.append(Frame(visitor->callee(), callFrame, isTailDeleted));
            return StackVisitor::Continue;
        });
    
    if (verbose)
        dataLog("    Pushing: ", listDump(toPush), "\n");
    
    for (unsigned i = toPush.size(); i--;)
        m_stack.append(toPush[i]);
    
    // We want to reset the log. There is a fun corner-case: there could be a tail marker at the end
    // of this log. We could make that work by setting isTailDeleted on the top of stack, but that
    // would require more corner cases in the complicated reconciliation code above. That code
    // already knows how to handle a tail packet at the beginning, so we just leverage that here.
    if (logCursorIndex && m_log[logCursorIndex - 1].isTail()) {
        m_log[0] = m_log[logCursorIndex - 1];
        m_logCursor = m_log + 1;
    } else
        m_logCursor = m_log;

    if (verbose)
        dataLog("    After pushing: ", *this, "\n");
    
    // Remove tail frames until the stack is small enough again.
    const unsigned stackSizeLimit = Options::shadowChickenStackSizeLimit();
    if (m_stack.size() > stackSizeLimit) {
        unsigned dstIndex = 0;
        unsigned srcIndex = 0;
        unsigned size = m_stack.size();
        while (srcIndex < m_stack.size()) {
            Frame frame = m_stack[srcIndex++];
            if (size > stackSizeLimit && frame.isTailDeleted) {
                size--;
                continue;
            }
            m_stack[dstIndex++] = frame;
        }
        RELEASE_ASSERT(dstIndex == size);
        m_stack.resize(size);
    }

    if (verbose)
        dataLog("    After clean-up: ", *this, "\n");
}
void ObjectMaterializationData::dump(PrintStream& out) const
{
    out.print("[", listDump(m_properties), "]");
}
Пример #10
0
void BasicBlock::dumpFooter(PrintStream& out) const
{
    if (successors().size())
        out.print("  Successors: ", listDump(successors()), "\n");
}
Пример #11
0
void SwitchValue::dumpMeta(CommaPrinter& comma, PrintStream& out) const
{
    out.print(comma, "cases = [", listDump(m_values), "]");
}
Пример #12
0
void StackMaps::dump(PrintStream& out) const
{
    out.print("Constants:[", listDump(constants), "], Records:[", listDump(records), "]");
}
Пример #13
0
void Stackmap::dump(PrintStream& out) const
{
    out.print(
        "{reps = ", listDump(m_reps), ", generator = ", RawPointer(m_generator.get()),
        ", clobbered = ", m_clobbered, ", usedRegisters = ", m_usedRegisters, "}");
}
Пример #14
0
void ControlValue::dumpMeta(PrintStream& out) const
{
    out.print(listDump(m_successors));
}