Changeset 19434 in webkit


Ignore:
Timestamp:
Feb 6, 2007 11:42:35 AM (17 years ago)
Author:
darin
Message:

Reviewed by John.

  • fix <rdar://problem/4687840> 9A241: JavaScript RegExp 25-30x slower than on 10.4.7

I used Shark to figure out what to do. The test case is now 15% faster than with
stock Safari. Some other regular expression cases might still be a few % slower
than before, but the >10x slowdown is now completely gone.

1) Fix slowness caused by setjmp/longjmp by using computed goto instead.

Use GCC extensions - locally declared labels, labels as values, and computed goto -
instead of using setjmp/longjmp to implemement non-recursive version of the regular
expression system. We could probably make this even faster if we reduced the use
of malloc a bit too.

2) Fix slowness caused by allocating heapframe objects by allocating the first

16 of them from the stack.

3) Speed up use of malloc and free in PCRE by making it use fastMalloc and fastFree.

4) Speed up the test case by adding a special case to a UString function.

5) Made a small improvement to the innermost hottest loop of match by hoisting

the conversion from int to pcre_uchar out of the loop.

  • JavaScriptCore.xcodeproj/project.pbxproj: Compile FastMallocPCRE.cpp, and don't compile pcre_globals.c.
  • wtf/FastMallocPCRE.cpp: Added. A copy of pcre_globals.c that uses FastMalloc.h. This is better than code that sets the PCRE allocation globals because by doing it this way there's guaranteed to be no problem with order of initialization.
  • kjs/ustring.cpp: (KJS::UString::spliceSubstringsWithSeparators): Add a fast special case when this is called for only one subrange and no seaprators. This was happening a lot in the test case and it seems quite reasonable to optimize this.
  • pcre/pcre_exec.c: Create a copy of the RMATCH and RRETURN macros that use goto instead of setjmp/longjmp. Change code that calls pcre_stack_malloc to first use storage on the stack inside the match function. (match): Move initialization of utf8 up a couple lines to avoid "possibly used uninitialized" warning. Use a local variable so we compare with pcre_uchar instead of with int inside the inner "find a character" loop.
Location:
trunk/JavaScriptCore
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r19393 r19434  
     12007-02-06  Darin Adler  <darin@apple.com>
     2
     3        Reviewed by John.
     4
     5        - fix <rdar://problem/4687840> 9A241: JavaScript RegExp 25-30x slower than on 10.4.7
     6
     7        I used Shark to figure out what to do. The test case is now 15% faster than with
     8        stock Safari. Some other regular expression cases might still be a few % slower
     9        than before, but the >10x slowdown is now completely gone.
     10
     11        1) Fix slowness caused by setjmp/longjmp by using computed goto instead.
     12
     13        Use GCC extensions - locally declared labels, labels as values, and computed goto -
     14        instead of using setjmp/longjmp to implemement non-recursive version of the regular
     15        expression system. We could probably make this even faster if we reduced the use
     16        of malloc a bit too.
     17
     18        2) Fix slowness caused by allocating heapframe objects by allocating the first
     19           16 of them from the stack.
     20
     21        3) Speed up use of malloc and free in PCRE by making it use fastMalloc and fastFree.
     22
     23        4) Speed up the test case by adding a special case to a UString function.
     24
     25        5) Made a small improvement to the innermost hottest loop of match by hoisting
     26           the conversion from int to pcre_uchar out of the loop.
     27
     28        * JavaScriptCore.xcodeproj/project.pbxproj: Compile FastMallocPCRE.cpp, and don't
     29        compile pcre_globals.c.
     30
     31        * wtf/FastMallocPCRE.cpp: Added. A copy of pcre_globals.c that uses FastMalloc.h.
     32        This is better than code that sets the PCRE allocation globals because by doing it
     33        this way there's guaranteed to be no problem with order of initialization.
     34
     35        * kjs/ustring.cpp: (KJS::UString::spliceSubstringsWithSeparators): Add a fast
     36        special case when this is called for only one subrange and no seaprators. This
     37        was happening a lot in the test case and it seems quite reasonable to optimize this.
     38
     39        * pcre/pcre_exec.c: Create a copy of the RMATCH and RRETURN macros that use goto
     40        instead of setjmp/longjmp. Change code that calls pcre_stack_malloc to first use
     41        storage on the stack inside the match function.
     42        (match): Move initialization of utf8 up a couple lines to avoid "possibly used
     43        uninitialized" warning. Use a local variable so we compare with pcre_uchar instead
     44        of with int inside the inner "find a character" loop.
     45
    1462007-02-03  George Staikos  <staikos@kde.org>
    247
  • trunk/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r19302 r19434  
    120120                65FB3F5109D11B2400F49DEB /* grammar.h in Headers */ = {isa = PBXBuildFile; fileRef = 65FB3F4909D11B2400F49DEB /* grammar.h */; };
    121121                65FB3F5409D11B2400F49DEB /* regexp_object.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = 65FB3F4C09D11B2400F49DEB /* regexp_object.lut.h */; };
     122                9302043B0B790750000C6115 /* FastMallocPCRE.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9302043A0B790750000C6115 /* FastMallocPCRE.cpp */; };
    122123                9303F568099118FA00AD71B8 /* OwnPtr.h in Headers */ = {isa = PBXBuildFile; fileRef = 9303F567099118FA00AD71B8 /* OwnPtr.h */; settings = {ATTRIBUTES = (Private, ); }; };
    123124                9303F56A0991190000AD71B8 /* Noncopyable.h in Headers */ = {isa = PBXBuildFile; fileRef = 9303F5690991190000AD71B8 /* Noncopyable.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    125126                930754C108B0F68000AB3056 /* pcre_compile.c in Sources */ = {isa = PBXBuildFile; fileRef = 930754BF08B0F68000AB3056 /* pcre_compile.c */; };
    126127                930754D008B0F74600AB3056 /* pcre_tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 930754CE08B0F74500AB3056 /* pcre_tables.c */; };
    127                 930754D308B0F76300AB3056 /* pcre_globals.c in Sources */ = {isa = PBXBuildFile; fileRef = 930754D108B0F76200AB3056 /* pcre_globals.c */; };
    128128                930754E808B0F77700AB3056 /* pcre_fullinfo.c in Sources */ = {isa = PBXBuildFile; fileRef = 930754E608B0F77700AB3056 /* pcre_fullinfo.c */; };
    129129                930754EB08B0F78500AB3056 /* pcre_exec.c in Sources */ = {isa = PBXBuildFile; fileRef = 930754E908B0F78500AB3056 /* pcre_exec.c */; };
     
    566566                70B16A270569A10900DB756D /* runtime_object.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = runtime_object.h; path = bindings/runtime_object.h; sourceTree = "<group>"; tabWidth = 8; };
    567567                84ABF1DE070B628C00A3AC05 /* npruntime_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = npruntime_impl.h; path = bindings/npruntime_impl.h; sourceTree = "<group>"; tabWidth = 8; };
     568                9302043A0B790750000C6115 /* FastMallocPCRE.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FastMallocPCRE.cpp; sourceTree = "<group>"; };
    568569                9303F567099118FA00AD71B8 /* OwnPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OwnPtr.h; sourceTree = "<group>"; };
    569570                9303F5690991190000AD71B8 /* Noncopyable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Noncopyable.h; sourceTree = "<group>"; };
     
    571572                930754BF08B0F68000AB3056 /* pcre_compile.c */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = pcre_compile.c; path = pcre/pcre_compile.c; sourceTree = "<group>"; tabWidth = 8; };
    572573                930754CE08B0F74500AB3056 /* pcre_tables.c */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = pcre_tables.c; path = pcre/pcre_tables.c; sourceTree = "<group>"; tabWidth = 8; };
    573                 930754D108B0F76200AB3056 /* pcre_globals.c */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = pcre_globals.c; path = pcre/pcre_globals.c; sourceTree = "<group>"; tabWidth = 8; };
    574574                930754E608B0F77700AB3056 /* pcre_fullinfo.c */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = pcre_fullinfo.c; path = pcre/pcre_fullinfo.c; sourceTree = "<group>"; tabWidth = 8; };
    575575                930754E908B0F78500AB3056 /* pcre_exec.c */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = pcre_exec.c; path = pcre/pcre_exec.c; sourceTree = "<group>"; tabWidth = 8; };
     
    890890                        isa = PBXGroup;
    891891                        children = (
    892                                 657EB7450B708F540063461B /* ListHashSet.h */,
    893892                                E195678D09E7CF1200B89D13 /* unicode */,
    894893                                93AA4F770957251F0084B3A7 /* AlwaysInline.h */,
     
    898897                                65E217BA08E7EECC0023E5F6 /* FastMalloc.h */,
    899898                                65D7D19B08F10B5B0015ABD8 /* FastMallocInternal.h */,
     899                                9302043A0B790750000C6115 /* FastMallocPCRE.cpp */,
    900900                                935AF46909E9D9DB00ACD1D8 /* Forward.h */,
    901901                                93B6A0DE0AA64DA40076DE27 /* GetPtr.h */,
     
    907907                                65DFC92E08EA173A00F7300B /* HashTable.h */,
    908908                                65DFC92F08EA173A00F7300B /* HashTraits.h */,
     909                                657EB7450B708F540063461B /* ListHashSet.h */,
    909910                                148A1626095D16BB00666D0D /* ListRefPtr.h */,
    910911                                BCF6553B0A2048DE0038A194 /* MathExtras.h */,
     
    10311032                                930754E608B0F77700AB3056 /* pcre_fullinfo.c */,
    10321033                                93E26CF608B29A1C00F85226 /* pcre_get.c */,
    1033                                 930754D108B0F76200AB3056 /* pcre_globals.c */,
    10341034                                93E26BE508B1517100F85226 /* pcre_internal.h */,
    10351035                                93E26BC908B1511900F85226 /* pcre_ord2utf8.c */,
     
    14921492                                930754C108B0F68000AB3056 /* pcre_compile.c in Sources */,
    14931493                                930754D008B0F74600AB3056 /* pcre_tables.c in Sources */,
    1494                                 930754D308B0F76300AB3056 /* pcre_globals.c in Sources */,
    14951494                                930754E808B0F77700AB3056 /* pcre_fullinfo.c in Sources */,
    14961495                                930754EB08B0F78500AB3056 /* pcre_exec.c in Sources */,
     
    15231522                                D212022A0AD4310D00ED79B6 /* DateMath.cpp in Sources */,
    15241523                                146AAB380B66A94400E55F16 /* JSStringRefCF.cpp in Sources */,
     1524                                9302043B0B790750000C6115 /* FastMallocPCRE.cpp in Sources */,
    15251525                        );
    15261526                        runOnlyForDeploymentPostprocessing = 0;
  • trunk/JavaScriptCore/kjs/ustring.cpp

    r19178 r19434  
    4444
    4545using std::max;
     46using std::min;
    4647
    4748namespace KJS {
     
    617618}
    618619
    619 UString UString::spliceSubstringsWithSeparators(const Range *substringRanges, int rangeCount, const UString *separators, int separatorCount) const
    620 {
     620UString UString::spliceSubstringsWithSeparators(const Range* substringRanges, int rangeCount, const UString* separators, int separatorCount) const
     621{
     622  if (rangeCount == 1 && separatorCount == 0) {
     623    int thisSize = size();
     624    int position = substringRanges[0].position;
     625    int length = substringRanges[0].length;
     626    if (position <= 0 && length >= thisSize)
     627      return *this;
     628    return UString::Rep::create(m_rep, max(0, position), min(thisSize, length));
     629  }
     630
    621631  int totalLength = 0;
    622 
    623   for (int i = 0; i < rangeCount; i++) {
     632  for (int i = 0; i < rangeCount; i++)
    624633    totalLength += substringRanges[i].length;
    625   }
    626   for (int i = 0; i < separatorCount; i++) {
     634  for (int i = 0; i < separatorCount; i++)
    627635    totalLength += separators[i].size();
    628   }
    629 
    630   UChar *buffer = static_cast<UChar *>(fastMalloc(totalLength * sizeof(UChar)));
     636
     637  UChar* buffer = static_cast<UChar*>(fastMalloc(totalLength * sizeof(UChar)));
    631638
    632639  int maxCount = max(rangeCount, separatorCount);
     
    643650  }
    644651
    645   return UString(UString::Rep::create(buffer, totalLength));
    646 }
    647 
    648 
     652  return UString::Rep::create(buffer, totalLength);
     653}
    649654
    650655UString &UString::append(const UString &t)
  • trunk/JavaScriptCore/pcre/pcre_exec.c

    r18498 r19434  
    88                       Written by Philip Hazel
    99           Copyright (c) 1997-2005 University of Cambridge
     10
     11    Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. All rights reserved.
    1012
    1113-----------------------------------------------------------------------------
     
    213215#define REGISTER
    214216
     217#ifndef __GNUC__
     218
     219/* Use setjmp/longjmp. */
     220
    215221#define RMATCH(rx,ra,rb,rc,rd,re,rf,rg)\
    216222  {\
    217   heapframe *newframe = (pcre_stack_malloc)(sizeof(heapframe));\
     223  heapframe *newframe;\
     224  if (frame >= stackframes && frame + 1 < stackframesend)\
     225    newframe = frame + 1;\
     226  else\
     227    newframe = (pcre_stack_malloc)(sizeof(heapframe));\
    218228  if (setjmp(frame->Xwhere) == 0)\
    219229    {\
     
    241251  heapframe *newframe = frame;\
    242252  frame = newframe->Xprevframe;\
    243   (pcre_stack_free)(newframe);\
     253  if (!(newframe >= stackframes && newframe < stackframesend))\
     254    (pcre_stack_free)(newframe);\
    244255  if (frame != NULL)\
    245256    {\
     
    251262  }
    252263
     264#else
     265
     266/* Use locally declared labels, labels as values, and computed goto. */
     267
     268#define RMATCH(rx,ra,rb,rc,rd,re,rf,rg)\
     269  {\
     270  __label__ where;\
     271  heapframe *newframe;\
     272  if (frame >= stackframes && frame + 1 < stackframesend)\
     273    newframe = frame + 1;\
     274  else\
     275    newframe = (pcre_stack_malloc)(sizeof(heapframe));\
     276  frame->Xwhere = &&where;\
     277  newframe->Xeptr = ra;\
     278  newframe->Xecode = rb;\
     279  newframe->Xoffset_top = rc;\
     280  newframe->Xims = re;\
     281  newframe->Xeptrb = rf;\
     282  newframe->Xflags = rg;\
     283  newframe->Xprevframe = frame;\
     284  frame = newframe;\
     285  DPRINTF(("restarting from line %d\n", __LINE__));\
     286  goto HEAP_RECURSE;\
     287where:\
     288  DPRINTF(("did a goto back to line %d\n", __LINE__));\
     289  frame = md->thisframe;\
     290  rx = frame->Xresult;\
     291  }
     292
     293#define RRETURN(ra)\
     294  {\
     295  heapframe *newframe = frame;\
     296  frame = newframe->Xprevframe;\
     297  if (!(newframe >= stackframes && newframe < stackframesend))\
     298    (pcre_stack_free)(newframe);\
     299  if (frame != NULL)\
     300    {\
     301    frame->Xresult = ra;\
     302    md->thisframe = frame;\
     303    goto *frame->Xwhere;\
     304    }\
     305  return ra;\
     306  }
     307
     308#endif
    253309
    254310/* Structure for remembering the local variables in a private frame */
     
    313369
    314370  int  Xresult;
     371#ifndef __GNUC__
    315372  jmp_buf Xwhere;
     373#else
     374  void *Xwhere;
     375#endif
    316376
    317377} heapframe;
     
    379439
    380440#ifdef NO_RECURSE
    381 heapframe *frame = (pcre_stack_malloc)(sizeof(heapframe));
     441
     442/* The value 16 here is large enough that most regular expressions don't require
     443any calls to pcre_stack_malloc, yet the amount of stack used for the array is
     444modest enough that we don't run out of stack. */
     445heapframe stackframes[16];
     446heapframe *stackframesend = stackframes + sizeof(stackframes) / sizeof(stackframes[0]);
     447
     448heapframe *frame = stackframes;
    382449frame->Xprevframe = NULL;            /* Marks the top level */
    383450
     
    522589performance when true recursion is being used. */
    523590
     591utf8 = md->utf8;       /* Local copy of the flag */
     592
    524593if (md->match_call_count++ >= md->match_limit) RRETURN(PCRE_ERROR_MATCHLIMIT);
    525594
    526595original_ims = ims;    /* Save for resetting on ')' */
    527 utf8 = md->utf8;       /* Local copy of the flag */
    528596
    529597/* At the start of a bracketed group, add the current subject pointer to the
     
    36113679  if (first_byte >= 0)
    36123680    {
     3681    pcre_uchar first_char = first_byte;
    36133682    if (first_byte_caseless)
    36143683      while (start_match < end_subject)
     
    36193688          break;
    36203689#endif
    3621         if (match_block.lcc[sm] == first_byte)
     3690        if (match_block.lcc[sm] == first_char)
    36223691          break;
    36233692        start_match++;
    36243693        }
    36253694    else
    3626       while (start_match < end_subject && *start_match != first_byte)
     3695      while (start_match < end_subject && *start_match != first_char)
    36273696        start_match++;
    36283697    }
Note: See TracChangeset for help on using the changeset viewer.