Changeset 146552 in webkit


Ignore:
Timestamp:
Mar 21, 2013 6:56:17 PM (11 years ago)
Author:
mark.lam@apple.com
Message:

Source/JavaScriptCore: Fix O(n2) op_debug bytecode charPosition to column computation.
https://bugs.webkit.org/show_bug.cgi?id=112957.

Reviewed by Geoffrey Garen.

The previous algorithm does a linear reverse scan of the source string
to find the line start for any given char position. This results in a
O(n2) algortithm when the source string has no line breaks.

The new algorithm computes a line start column table for a
SourceProvider on first use. This line start table is used to fix up
op_debug's charPosition operand into a column operand when an
UnlinkedCodeBlock is linked into a CodeBlock. The initialization of
the line start table is O(n), and the CodeBlock column fix up is
O(log(n)).

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock): - do column fix up.

  • interpreter/Interpreter.cpp:

(JSC::Interpreter::debug): - no need to do column fixup anymore.

  • interpreter/Interpreter.h:
  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::LLINT_SLOW_PATH_DECL):

  • parser/SourceProvider.cpp:

(JSC::SourceProvider::lineStarts):
(JSC::charPositionExtractor):
(JSC::SourceProvider::charPositionToColumnNumber):

  • initialize line start column table if needed.
  • look up line start for the given char position.
  • parser/SourceProvider.h:

Source/WTF: Introducing String::findNextLineStart().
https://bugs.webkit.org/show_bug.cgi?id=112957.

Reviewed by Geoffrey Garen.

This is replaces String::reverseFindLineTerminator() in the JSC
debugger's code for computing column numbers.

  • wtf/text/StringImpl.cpp:

(WTF::StringImpl::findNextLineStart):

  • wtf/text/StringImpl.h:

(WTF::findNextLineStart):

  • wtf/text/WTFString.h:

(WTF::String::findNextLineStart):

Location:
trunk/Source
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r146548 r146552  
     12013-03-21  Mark Lam  <mark.lam@apple.com>
     2
     3        Fix O(n^2) op_debug bytecode charPosition to column computation.
     4        https://bugs.webkit.org/show_bug.cgi?id=112957.
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        The previous algorithm does a linear reverse scan of the source string
     9        to find the line start for any given char position. This results in a
     10        O(n^2) algortithm when the source string has no line breaks.
     11
     12        The new algorithm computes a line start column table for a
     13        SourceProvider on first use. This line start table is used to fix up
     14        op_debug's charPosition operand into a column operand when an
     15        UnlinkedCodeBlock is linked into a CodeBlock. The initialization of
     16        the line start table is O(n), and the CodeBlock column fix up is
     17        O(log(n)).
     18
     19        * bytecode/CodeBlock.cpp:
     20        (JSC::CodeBlock::dumpBytecode):
     21        (JSC::CodeBlock::CodeBlock): - do column fix up.
     22        * interpreter/Interpreter.cpp:
     23        (JSC::Interpreter::debug): - no need to do column fixup anymore.
     24        * interpreter/Interpreter.h:
     25        * jit/JITStubs.cpp:
     26        (JSC::DEFINE_STUB_FUNCTION):
     27        * llint/LLIntSlowPaths.cpp:
     28        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
     29        * parser/SourceProvider.cpp:
     30        (JSC::SourceProvider::lineStarts):
     31        (JSC::charPositionExtractor):
     32        (JSC::SourceProvider::charPositionToColumnNumber):
     33        - initialize line start column table if needed.
     34        - look up line start for the given char position.
     35        * parser/SourceProvider.h:
     36
    1372013-03-21  Filip Pizlo  <fpizlo@apple.com>
    238
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r146318 r146552  
    14741474            int firstLine = (++it)->u.operand;
    14751475            int lastLine = (++it)->u.operand;
    1476             int charPosition = (++it)->u.operand;
    1477             out.printf("[%4d] debug\t\t %s, %d, %d, %d", location, debugHookName(debugHookID), firstLine, lastLine, charPosition);
     1476            int column = (++it)->u.operand;
     1477            out.printf("[%4d] debug\t\t %s, %d, %d, %d", location, debugHookName(debugHookID), firstLine, lastLine, column);
    14781478            break;
    14791479        }
     
    20042004            break;
    20052005        }
     2006
     2007        case op_debug: {
     2008            size_t charPosition = pc[i + 4].u.operand;
     2009            size_t actualCharPosition = charPosition + m_sourceOffset;
     2010            size_t column = m_source->charPositionToColumnNumber(actualCharPosition);
     2011            instructions[i + 4] = column;
     2012            break;
     2013        }
     2014
    20062015        default:
    20072016            break;
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp

    r146318 r146552  
    13341334}
    13351335
    1336 NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHookID, int firstLine, int lastLine, int charPosition)
     1336NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHookID, int firstLine, int lastLine, int column)
    13371337{
    13381338    Debugger* debugger = callFrame->dynamicGlobalObject()->debugger();
    13391339    if (!debugger)
    13401340        return;
    1341 
    1342     CodeBlock* codeBlock = callFrame->codeBlock();
    1343     size_t actualCharPosition = charPosition + codeBlock->sourceOffset();
    1344 
    1345     SourceProvider* provider = codeBlock->source();
    1346     String source = provider->source();
    1347     size_t lineTerminatorPosition = source.reverseFindLineTerminator(actualCharPosition);
    1348     int column;
    1349     if (lineTerminatorPosition != notFound)
    1350         column = actualCharPosition - (lineTerminatorPosition + 1);
    1351     else
    1352         column = actualCharPosition;
    13531341
    13541342    switch (debugHookID) {
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.h

    r146318 r146552  
    231231
    232232        NEVER_INLINE HandlerInfo* throwException(CallFrame*&, JSValue&, unsigned bytecodeOffset);
    233         NEVER_INLINE void debug(CallFrame*, DebugHookID, int firstLine, int lastLine, int charPosition);
     233        NEVER_INLINE void debug(CallFrame*, DebugHookID, int firstLine, int lastLine, int column);
    234234        static const String getTraceLine(CallFrame*, StackFrameCodeType, const String&, int);
    235235        JS_EXPORT_PRIVATE static void getStackTrace(JSGlobalData*, Vector<StackFrame>& results);
  • trunk/Source/JavaScriptCore/jit/JITStubs.cpp

    r146318 r146552  
    34693469    int firstLine = stackFrame.args[1].int32();
    34703470    int lastLine = stackFrame.args[2].int32();
    3471     int charPosition = stackFrame.args[3].int32();
    3472 
    3473     stackFrame.globalData->interpreter->debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine, charPosition);
     3471    int column = stackFrame.args[3].int32();
     3472
     3473    stackFrame.globalData->interpreter->debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine, column);
    34743474}
    34753475
  • trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp

    r146318 r146552  
    16381638    int firstLine = pc[2].u.operand;
    16391639    int lastLine = pc[3].u.operand;
    1640     int charPosition = pc[4].u.operand;
    1641 
    1642     globalData.interpreter->debug(exec, static_cast<DebugHookID>(debugHookID), firstLine, lastLine, charPosition);
     1640    int column = pc[4].u.operand;
     1641
     1642    globalData.interpreter->debug(exec, static_cast<DebugHookID>(debugHookID), firstLine, lastLine, column);
    16431643   
    16441644    LLINT_END();
  • trunk/Source/JavaScriptCore/parser/SourceProvider.cpp

    r144122 r146552  
    2626#include "config.h"
    2727#include "SourceProvider.h"
     28#include <wtf/StdLibExtras.h>
    2829#include <wtf/TCSpinLock.h>
    2930
     
    4243}
    4344
     45Vector<size_t>& SourceProvider::lineStarts()
     46{
     47    if (!m_lineStarts) {
     48        m_lineStarts = adoptPtr(new Vector<size_t>());
     49        String source = this->source();
     50        size_t index = 0;
     51        do {
     52            m_lineStarts->append(index);
     53            index = source.findNextLineStart(index);
     54        } while (index != notFound);
     55        m_lineStarts->shrinkToFit();
     56    }
     57    return *m_lineStarts;
     58}
     59
     60
     61static inline size_t charPositionExtractor(const size_t* value)
     62{
     63    return *value;
     64}
     65
     66size_t SourceProvider::charPositionToColumnNumber(size_t charPosition)
     67{
     68    Vector<size_t>& lineStarts = this->lineStarts();
     69    size_t* data = lineStarts.data();
     70    size_t dataSize = lineStarts.size();
     71
     72    // Get the nearest line start entry (which could be to the left or to the
     73    // right of the requested charPosition.
     74    const size_t* line = approximateBinarySearch<size_t, size_t>(data, dataSize, charPosition, charPositionExtractor);
     75    size_t lineStartPosition = *line;
     76
     77    if (lineStartPosition > charPosition) {
     78        if (data < line) {
     79            line--;
     80            lineStartPosition = *line;
     81        }
     82    }
     83
     84    ASSERT(data <= line);
     85    ASSERT(lineStartPosition <= charPosition);
     86    return charPosition - lineStartPosition;
     87}
     88
    4489static TCMalloc_SpinLock providerIdLock = SPINLOCK_INITIALIZER;
    4590
  • trunk/Source/JavaScriptCore/parser/SourceProvider.h

    r144122 r146552  
    6767        void setValid() { m_validated = true; }
    6868
     69        size_t charPositionToColumnNumber(size_t charPosition);
     70
    6971    private:
    7072
    7173        JS_EXPORT_PRIVATE void getID();
     74        Vector<size_t>& lineStarts();
    7275
    7376        String m_url;
     
    7578        bool m_validated : 1;
    7679        uintptr_t m_id : sizeof(uintptr_t) * 8 - 1;
     80
     81        OwnPtr<Vector<size_t> > m_lineStarts;
    7782    };
    7883
  • trunk/Source/WTF/ChangeLog

    r146464 r146552  
     12013-03-21  Mark Lam  <mark.lam@apple.com>
     2
     3        Introducing String::findNextLineStart().
     4        https://bugs.webkit.org/show_bug.cgi?id=112957.
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        This is replaces String::reverseFindLineTerminator() in the JSC
     9        debugger's code for computing column numbers.
     10
     11        * wtf/text/StringImpl.cpp:
     12        (WTF::StringImpl::findNextLineStart):
     13        * wtf/text/StringImpl.h:
     14        (WTF::findNextLineStart):
     15        * wtf/text/WTFString.h:
     16        (WTF::String::findNextLineStart):
     17
    1182013-03-21  Adam Barth  <abarth@webkit.org>
    219
  • trunk/Source/WTF/wtf/text/StringImpl.cpp

    r146318 r146552  
    11171117}
    11181118
    1119 size_t StringImpl::reverseFindLineTerminator(unsigned index)
    1120 {
    1121     if (is8Bit())
    1122         return WTF::reverseFindLineTerminator(characters8(), m_length, index);
    1123     return WTF::reverseFindLineTerminator(characters16(), m_length, index);
     1119size_t StringImpl::findNextLineStart(unsigned index)
     1120{
     1121    if (is8Bit())
     1122        return WTF::findNextLineStart(characters8(), m_length, index);
     1123    return WTF::findNextLineStart(characters16(), m_length, index);
    11241124}
    11251125
  • trunk/Source/WTF/wtf/text/StringImpl.h

    r146464 r146552  
    698698    WTF_EXPORT_STRING_API size_t findIgnoringCase(StringImpl*, unsigned index = 0);
    699699
    700     WTF_EXPORT_STRING_API size_t reverseFindLineTerminator(unsigned index = UINT_MAX);
     700    WTF_EXPORT_STRING_API size_t findNextLineStart(unsigned index = UINT_MAX);
     701
    701702    WTF_EXPORT_STRING_API size_t reverseFind(UChar, unsigned index = UINT_MAX);
    702703    WTF_EXPORT_STRING_API size_t reverseFind(StringImpl*, unsigned index = UINT_MAX);
     
    11501151
    11511152template<typename CharacterType>
     1153inline size_t findNextLineStart(const CharacterType* characters, unsigned length, unsigned index = 0)
     1154{
     1155    while (index < length) {
     1156        CharacterType c = characters[index++];
     1157        if ((c != '\n') && (c != '\r'))
     1158            continue;
     1159
     1160        // There can only be a start of a new line if there are more characters
     1161        // beyond the current character.
     1162        if (index < length) {
     1163            // The 3 common types of line terminators are 1. \r\n (Windows),
     1164            // 2. \r (old MacOS) and 3. \n (Unix'es).
     1165
     1166            if (c == '\n')
     1167                return index; // Case 3: just \n.
     1168
     1169            CharacterType c2 = characters[index];
     1170            if (c2 != '\n')
     1171                return index; // Case 2: just \r.
     1172
     1173            // Case 1: \r\n.
     1174            // But, there's only a start of a new line if there are more
     1175            // characters beyond the \r\n.
     1176            if (++index < length)
     1177                return index;
     1178        }
     1179    }
     1180    return notFound;
     1181}
     1182
     1183template<typename CharacterType>
    11521184inline size_t reverseFindLineTerminator(const CharacterType* characters, unsigned length, unsigned index = UINT_MAX)
    11531185{
  • trunk/Source/WTF/wtf/text/WTFString.h

    r146318 r146552  
    262262        { return m_impl ? m_impl->find(str, start) : notFound; }
    263263
    264     size_t reverseFindLineTerminator(unsigned start = UINT_MAX) const
    265         { return m_impl ? m_impl->reverseFindLineTerminator(start) : notFound; }
     264    size_t findNextLineStart(unsigned start = 0) const
     265        { return m_impl ? m_impl->findNextLineStart(start) : notFound; }
    266266
    267267    // Find the last instance of a single character or string.
Note: See TracChangeset for help on using the changeset viewer.