/[jscoverage]/trunk/js/jsregexp.cpp
ViewVC logotype

Diff of /trunk/js/jsregexp.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 459 by siliconforks, Tue Dec 9 03:37:47 2008 UTC revision 460 by siliconforks, Sat Sep 26 23:15:22 2009 UTC
# Line 64  Line 64 
64  #include "jsregexp.h"  #include "jsregexp.h"
65  #include "jsscan.h"  #include "jsscan.h"
66  #include "jsscope.h"  #include "jsscope.h"
67    #include "jsstaticcheck.h"
68  #include "jsstr.h"  #include "jsstr.h"
69    
70  #ifdef JS_TRACER  #ifdef JS_TRACER
71  #include "jstracer.h"  #include "jstracer.h"
72  using namespace avmplus;  using namespace avmplus;
73  using namespace nanojit;  using namespace nanojit;
   
 /*  
  * FIXME  Duplicated with jstracer.cpp, doing it this way for now  
  *        to keep it private to files that need it.  
  */  
 #ifdef JS_JIT_SPEW  
 static bool verbose_debug = getenv("TRACEMONKEY") && strstr(getenv("TRACEMONKEY"), "verbose");  
 #define debug_only_v(x) if (verbose_debug) { x; }  
 #else  
 #define debug_only_v(x)  
 #endif  
74  #endif  #endif
75    
76  typedef enum REOp {  typedef enum REOp {
# Line 1277  Line 1267 
1267                  /* Treat this as an octal escape. */                  /* Treat this as an octal escape. */
1268                  goto doOctal;                  goto doOctal;
1269              }              }
1270              JS_ASSERT(1 <= num && num <= 0x10000);  
1271                /*
1272                 * When FindParenCount calls the regex parser recursively (to find
1273                 * the number of backrefs) num can be arbitrary and the maximum
1274                 * supported number of backrefs does not bound it.
1275                 */
1276                JS_ASSERT_IF(!(state->flags & JSREG_FIND_PAREN_COUNT),
1277                             1 <= num && num <= 0x10000);
1278              state->result = NewRENode(state, REOP_BACKREF);              state->result = NewRENode(state, REOP_BACKREF);
1279              if (!state->result)              if (!state->result)
1280                  return JS_FALSE;                  return JS_FALSE;
# Line 1960  Line 1957 
1957      goto cleanup;      goto cleanup;
1958  }  }
1959    
1960    static JSBool
1961    CompileRegExpToAST(JSContext* cx, JSTokenStream* ts,
1962                       JSString* str, uintN flags, CompilerState& state)
1963    {
1964        uintN i;
1965        size_t len;
1966    
1967        len = JSSTRING_LENGTH(str);
1968    
1969        state.context = cx;
1970        state.tokenStream = ts;
1971        state.cp = js_UndependString(cx, str);
1972        if (!state.cp)
1973            return JS_FALSE;
1974        state.cpbegin = state.cp;
1975        state.cpend = state.cp + len;
1976        state.flags = flags;
1977        state.parenCount = 0;
1978        state.classCount = 0;
1979        state.progLength = 0;
1980        state.treeDepth = 0;
1981        state.classBitmapsMem = 0;
1982        for (i = 0; i < CLASS_CACHE_SIZE; i++)
1983            state.classCache[i].start = NULL;
1984    
1985        if (len != 0 && (flags & JSREG_FLAT)) {
1986            state.result = NewRENode(&state, REOP_FLAT);
1987            if (!state.result)
1988                return JS_FALSE;
1989            state.result->u.flat.chr = *state.cpbegin;
1990            state.result->u.flat.length = len;
1991            state.result->kid = (void *) state.cpbegin;
1992            /* Flat bytecode: REOP_FLAT compact(string_offset) compact(len). */
1993            state.progLength += 1 + GetCompactIndexWidth(0)
1994                              + GetCompactIndexWidth(len);
1995            return JS_TRUE;
1996        }
1997        
1998        return ParseRegExp(&state);
1999    }
2000    
2001  #ifdef JS_TRACER  #ifdef JS_TRACER
2002  typedef List<LIns*, LIST_NonGCObjects> LInsList;  typedef List<LIns*, LIST_NonGCObjects> LInsList;
2003    
2004  /* Dummy GC for nanojit placement new. */  /* Dummy GC for nanojit placement new. */
2005  static GC gc;  static GC gc;
2006    
2007    static void*
2008    HashRegExp(uint16 flags, jschar* s, size_t n)
2009    {
2010        uint32 h;
2011    
2012        for (h = 0; n; s++, n--)
2013            h = JS_ROTATE_LEFT32(h, 4) ^ *s;
2014        return (void*)(h + flags);
2015    }
2016    
2017    struct RESideExit : public SideExit {
2018        size_t re_length;
2019        uint16 re_flags;
2020        jschar re_chars[1];
2021    };
2022    
2023    /* Return the cached fragment for the given regexp, or NULL. */
2024    static Fragment*
2025    LookupNativeRegExp(JSContext* cx, void* hash, uint16 re_flags,
2026                       jschar* re_chars, size_t re_length)
2027    {
2028        Fragmento* fragmento = JS_TRACE_MONITOR(cx).reFragmento;
2029        Fragment* fragment = fragmento->getLoop(hash);
2030        while (fragment) {
2031            if (fragment->lastIns) {
2032                RESideExit* exit = (RESideExit*)fragment->lastIns->record()->exit;
2033                if (exit->re_flags == re_flags &&
2034                    exit->re_length == re_length &&
2035                    !memcmp(exit->re_chars, re_chars, re_length * sizeof(jschar))) {
2036                    return fragment;
2037                }
2038            }
2039            fragment = fragment->peer;
2040        }
2041        return NULL;
2042    }
2043    
2044    static JSBool
2045    ProcessCharSet(JSContext *cx, JSRegExp *re, RECharSet *charSet);
2046    
2047  class RegExpNativeCompiler {  class RegExpNativeCompiler {
2048   private:   private:
2049      JSRegExp*        re;   /* Careful: not fully initialized */      JSContext*       cx;
2050      CompilerState*   cs;   /* RegExp to compile */      JSRegExp*        re;
2051        CompilerState*   cs;            /* RegExp to compile */
2052      Fragment*        fragment;      Fragment*        fragment;
2053      LirWriter*       lir;      LirWriter*       lir;
2054        LirBufWriter*    lirBufWriter;  /* for skip */
2055    
2056      LIns*            state;      LIns*            state;
2057      LIns*            gdata;      LIns*            gdata;
2058      LIns*            cpend;      LIns*            cpend;
2059    
2060      JSBool isCaseInsensitive() const { return cs->flags & JSREG_FOLD; }      JSBool isCaseInsensitive() const { return (cs->flags & JSREG_FOLD) != 0; }
2061    
2062      void targetCurrentPoint(LIns* ins) { ins->target(lir->ins0(LIR_label)); }      JSBool targetCurrentPoint(LIns* ins)
2063        {
2064            if (fragment->lirbuf->outOMem())
2065                return JS_FALSE;
2066            ins->target(lir->ins0(LIR_label));
2067            return JS_TRUE;
2068        }
2069    
2070      void targetCurrentPoint(LInsList& fails)      JSBool targetCurrentPoint(LInsList& fails)
2071      {      {
2072            if (fragment->lirbuf->outOMem())
2073                return JS_FALSE;
2074          LIns* fail = lir->ins0(LIR_label);          LIns* fail = lir->ins0(LIR_label);
2075          for (size_t i = 0; i < fails.size(); ++i) {          for (size_t i = 0; i < fails.size(); ++i) {
2076              fails[i]->target(fail);              fails[i]->target(fail);
2077          }          }
2078          fails.clear();          fails.clear();
2079            return JS_TRUE;
2080      }      }
2081    
2082      /*      /*
# Line 1999  Line 2088 
2088          return pos;          return pos;
2089      }      }
2090    
2091      LIns* compileFlatSingleChar(RENode* node, LIns* pos, LInsList& fails)      LIns* compileFlatSingleChar(jschar ch, LIns* pos, LInsList& fails)
2092      {      {
2093          /*          /*
2094           * Fast case-insensitive test for ASCII letters: convert text           * Fast case-insensitive test for ASCII letters: convert text
2095           * char to lower case by bit-or-ing in 32 and compare.           * char to lower case by bit-or-ing in 32 and compare.
2096           */           */
2097          JSBool useFastCI = JS_FALSE;          JSBool useFastCI = JS_FALSE;
         jschar ch = node->u.flat.chr; /* char to test for */  
2098          jschar ch2 = ch;              /* 2nd char to test for if ci */          jschar ch2 = ch;              /* 2nd char to test for if ci */
2099          if (cs->flags & JSREG_FOLD) {          if (cs->flags & JSREG_FOLD) {
2100              if (L'A' <= ch && ch <= L'Z' || L'a' <= ch || ch <= L'z') {              if ((L'A' <= ch && ch <= L'Z') || (L'a' <= ch && ch <= L'z')) {
2101                  ch |= 32;                  ch |= 32;
2102                  ch2 = ch;                  ch2 = ch;
2103                  useFastCI = JS_TRUE;                  useFastCI = JS_TRUE;
# Line 2030  Line 2118 
2118          } else {          } else {
2119              LIns* to_ok = lir->insBranch(LIR_jt, lir->ins2(LIR_eq, comp_ch, lir->insImm(ch)), 0);              LIns* to_ok = lir->insBranch(LIR_jt, lir->ins2(LIR_eq, comp_ch, lir->insImm(ch)), 0);
2120              fails.add(lir->insBranch(LIR_jf, lir->ins2(LIR_eq, comp_ch, lir->insImm(ch2)), 0));              fails.add(lir->insBranch(LIR_jf, lir->ins2(LIR_eq, comp_ch, lir->insImm(ch2)), 0));
2121              targetCurrentPoint(to_ok);              if (!targetCurrentPoint(to_ok))
2122                    return NULL;
2123          }          }
2124    
2125          return lir->ins2(LIR_piadd, pos, lir->insImm(2));          return lir->ins2(LIR_piadd, pos, lir->insImm(2));
2126      }      }
2127    
2128        LIns* compileFlatDoubleChar(jschar ch1, jschar ch2, LIns* pos,
2129                                    LInsList& fails)
2130        {
2131    #ifdef IS_BIG_ENDIAN
2132            uint32 word = (ch1 << 16) | ch2;
2133    #else
2134            uint32 word = (ch2 << 16) | ch1;
2135    #endif
2136            /*
2137             * Fast case-insensitive test for ASCII letters: convert text
2138             * char to lower case by bit-or-ing in 32 and compare.
2139             */
2140            JSBool useFastCI = JS_FALSE;
2141            union { jschar c[2]; uint32 i; } mask;
2142            if (cs->flags & JSREG_FOLD) {
2143                JSBool mask1 = (L'A' <= ch1 && ch1 <= L'Z') || (L'a' <= ch1 && ch1 <= L'z');
2144                JSBool mask2 = (L'A' <= ch2 && ch2 <= L'Z') || (L'a' <= ch2 && ch2 <= L'z');
2145                if ((!mask1 && JS_TOLOWER(ch1) != ch1) || (!mask2 && JS_TOLOWER(ch2) != ch2)) {
2146                    pos = compileFlatSingleChar(ch1, pos, fails);
2147                    if (!pos) return NULL;
2148                    return compileFlatSingleChar(ch2, pos, fails);
2149                }
2150    
2151                mask.c[0] = mask1 ? 0x0020 : 0x0;
2152                mask.c[1] = mask2 ? 0x0020 : 0x0;
2153    
2154                if (mask.i) {
2155                    word |= mask.i;
2156                    useFastCI = JS_TRUE;
2157                }
2158            }
2159    
2160            LIns* to_fail = lir->insBranch(LIR_jf, lir->ins2(LIR_lt, pos, lir->ins2(LIR_sub, cpend, lir->insImm(2))), 0);
2161            fails.add(to_fail);
2162            LIns* text_word = lir->insLoad(LIR_ld, pos, lir->insImm(0));
2163            LIns* comp_word = useFastCI ?
2164                lir->ins2(LIR_or, text_word, lir->insImm(mask.i)) :
2165                text_word;
2166            fails.add(lir->insBranch(LIR_jf, lir->ins2(LIR_eq, comp_word, lir->insImm(word)), 0));
2167    
2168            return lir->ins2(LIR_piadd, pos, lir->insImm(4));
2169        }
2170    
2171      LIns* compileClass(RENode* node, LIns* pos, LInsList& fails)      LIns* compileClass(RENode* node, LIns* pos, LInsList& fails)
2172      {      {
2173          if (!node->u.ucclass.sense)          if (!node->u.ucclass.sense)
2174              return JS_FALSE;              return JS_FALSE;
2175            /*
2176             * If we share generated native code, we need to make a copy
2177             * of the bitmap because the original regexp's copy is destroyed
2178             * when that regexp is.
2179             */
2180            RECharSet *charSet = &re->classList[node->u.ucclass.index];
2181            size_t bitmapLen = (charSet->length >> 3) + 1;
2182            /* skip() can't hold large data blocks. */
2183            if (bitmapLen > 1024)
2184                return NULL;
2185            /* The following line allocates charSet.u.bits if successful. */
2186            if (!charSet->converted && !ProcessCharSet(cx, re, charSet))
2187                return NULL;
2188            LIns* skip = lirBufWriter->skip(bitmapLen);
2189            if (fragment->lirbuf->outOMem())
2190                return NULL;
2191            void* bitmapData = skip->payload();
2192            memcpy(bitmapData, charSet->u.bits, bitmapLen);
2193    
         RECharSet* charSet = InitNodeCharSet(re, node);  
2194          LIns* to_fail = lir->insBranch(LIR_jf, lir->ins2(LIR_lt, pos, cpend), 0);          LIns* to_fail = lir->insBranch(LIR_jf, lir->ins2(LIR_lt, pos, cpend), 0);
2195          fails.add(to_fail);          fails.add(to_fail);
2196          LIns* text_ch = lir->insLoad(LIR_ldcs, pos, lir->insImm(0));          LIns* text_ch = lir->insLoad(LIR_ldcs, pos, lir->insImm(0));
2197          fails.add(lir->insBranch(LIR_jf, lir->ins2(LIR_le, text_ch, lir->insImm(charSet->length)), 0));          fails.add(lir->insBranch(LIR_jf, lir->ins2(LIR_le, text_ch, lir->insImm(charSet->length)), 0));
2198          LIns* byteIndex = lir->ins2(LIR_rsh, text_ch, lir->insImm(3));          LIns* byteIndex = lir->ins2(LIR_rsh, text_ch, lir->insImm(3));
2199          LIns* bitmap = lir->insLoad(LIR_ld, lir->insImmPtr(charSet), (int) offsetof(RECharSet, u.bits));          LIns* bitmap = lir->insImmPtr(bitmapData);
2200          LIns* byte = lir->insLoad(LIR_ldcb, lir->ins2(LIR_piadd, bitmap, byteIndex), (int) 0);          LIns* byte = lir->insLoad(LIR_ldcb, lir->ins2(LIR_piadd, bitmap, byteIndex), (int) 0);
2201          LIns* bitMask = lir->ins2(LIR_lsh, lir->insImm(1),          LIns* bitMask = lir->ins2(LIR_lsh, lir->insImm(1),
2202                                 lir->ins2(LIR_and, text_ch, lir->insImm(0x7)));                                 lir->ins2(LIR_and, text_ch, lir->insImm(0x7)));
# Line 2062  Line 2211 
2211      {      {
2212          LInsList kidFails(NULL);          LInsList kidFails(NULL);
2213          if (!compileNode((RENode *) node->kid, pos, kidFails))          if (!compileNode((RENode *) node->kid, pos, kidFails))
2214              return JS_FALSE;              return NULL;
2215          if (!compileNode(node->next, pos, kidFails))          if (!compileNode(node->next, pos, kidFails))
2216              return JS_FALSE;              return NULL;
2217    
2218          targetCurrentPoint(kidFails);          if (!targetCurrentPoint(kidFails))
2219                return NULL;
2220          if (!compileNode(node->u.altprereq.kid2, pos, fails))          if (!compileNode(node->u.altprereq.kid2, pos, fails))
2221              return JS_FALSE;              return NULL;
2222          /*          /*
2223           * Disable compilation for any regexp where something follows an           * Disable compilation for any regexp where something follows an
2224           * alternation. To make this work, we need to redesign to either           * alternation. To make this work, we need to redesign to either
# Line 2077  Line 2227 
2227           * code.           * code.
2228           */           */
2229          if (node->next)          if (node->next)
2230              return JS_FALSE;              return NULL;
2231          return pos;          return pos;
2232      }      }
2233    
2234    #if defined(AVMPLUS_ARM) || defined(AVMPLUS_SPARC)
2235    /* We can't do this on ARM or SPARC, since it relies on doing a 32-bit load from
2236     * a pointer which is only 2-byte aligned.
2237     */
2238    #undef USE_DOUBLE_CHAR_MATCH
2239    #else
2240    #define USE_DOUBLE_CHAR_MATCH
2241    #endif
2242    
2243      JSBool compileNode(RENode* node, LIns* pos, LInsList& fails)      JSBool compileNode(RENode* node, LIns* pos, LInsList& fails)
2244      {      {
2245          for (; node; node = node->next) {          for (; node; node = node->next) {
2246              if (fragment->lirbuf->outOmem())              if (fragment->lirbuf->outOMem())
2247                  return JS_FALSE;                  return JS_FALSE;
2248    
2249              switch (node->op) {              switch (node->op) {
# Line 2092  Line 2251 
2251                  pos = compileEmpty(node, pos, fails);                  pos = compileEmpty(node, pos, fails);
2252                  break;                  break;
2253              case REOP_FLAT:              case REOP_FLAT:
2254                  if (node->u.flat.length != 1)  #ifdef USE_DOUBLE_CHAR_MATCH
2255                      return JS_FALSE;                  if (node->u.flat.length == 1) {
2256                  pos = compileFlatSingleChar(node, pos, fails);                      if (node->next && node->next->op == REOP_FLAT &&
2257                            node->next->u.flat.length == 1) {
2258                            pos = compileFlatDoubleChar(node->u.flat.chr,
2259                                                        node->next->u.flat.chr,
2260                                                        pos, fails);
2261                            node = node->next;
2262                        } else {
2263                            pos = compileFlatSingleChar(node->u.flat.chr, pos, fails);
2264                        }
2265                    } else {
2266                       size_t i;
2267                       for (i = 0; i < node->u.flat.length - 1; i += 2) {
2268                           if (fragment->lirbuf->outOMem())
2269                               return JS_FALSE;
2270                           pos = compileFlatDoubleChar(((jschar*) node->kid)[i],
2271                                                       ((jschar*) node->kid)[i+1],
2272                                                       pos, fails);
2273                           if (!pos) break;
2274                       }
2275                       if (pos && i == node->u.flat.length - 1)
2276                           pos = compileFlatSingleChar(((jschar*) node->kid)[i], pos, fails);
2277                    }
2278    #else
2279                    if (node->u.flat.length == 1) {
2280                        pos = compileFlatSingleChar(node->u.flat.chr, pos, fails);
2281                    } else {
2282                        for (size_t i = 0; i < node->u.flat.length; i++) {
2283                            if (fragment->lirbuf->outOMem())
2284                                return JS_FALSE;
2285                            pos = compileFlatSingleChar(((jschar*) node->kid)[i], pos, fails);
2286                            if (!pos) break;
2287                        }
2288                    }
2289    #endif
2290                  break;                  break;
2291              case REOP_ALT:              case REOP_ALT:
2292              case REOP_ALTPREREQ:              case REOP_ALTPREREQ:
# Line 2120  Line 2312 
2312          LInsList fails(NULL);          LInsList fails(NULL);
2313          if (!compileNode(root, start, fails))          if (!compileNode(root, start, fails))
2314              return JS_FALSE;              return JS_FALSE;
2315          targetCurrentPoint(fails);          if (!targetCurrentPoint(fails))
2316                return JS_FALSE;
2317          lir->ins1(LIR_ret, lir->insImm(0));          lir->ins1(LIR_ret, lir->insImm(0));
2318          return JS_TRUE;          return JS_TRUE;
2319      }      }
# Line 2134  Line 2327 
2327          if (!compileNode(root, start, fails))          if (!compileNode(root, start, fails))
2328              return JS_FALSE;              return JS_FALSE;
2329    
2330          targetCurrentPoint(to_next);          if (!targetCurrentPoint(to_next))
2331                return JS_FALSE;
2332          lir->ins1(LIR_ret, lir->insImm(0));          lir->ins1(LIR_ret, lir->insImm(0));
2333                    
2334          targetCurrentPoint(fails);          if (!targetCurrentPoint(fails))
2335                return JS_FALSE;
2336          lir->insStorei(lir->ins2(LIR_piadd, start, lir->insImm(2)), gdata,          lir->insStorei(lir->ins2(LIR_piadd, start, lir->insImm(2)), gdata,
2337                         (int) offsetof(REGlobalData, skipped));                         (int) offsetof(REGlobalData, skipped));
2338                    
# Line 2147  Line 2342 
2342      inline LIns*      inline LIns*
2343      addName(LirBuffer* lirbuf, LIns* ins, const char* name)      addName(LirBuffer* lirbuf, LIns* ins, const char* name)
2344      {      {
2345    #ifdef NJ_VERBOSE
2346          debug_only_v(lirbuf->names->addName(ins, name);)          debug_only_v(lirbuf->names->addName(ins, name);)
2347    #endif
2348          return ins;          return ins;
2349      }      }
2350    
2351        /*
2352         * Insert the side exit and guard record for a compiled regexp. Most
2353         * of the fields are not used. The important part is the regexp source
2354         * and flags, which we use as the fragment lookup key.
2355         */
2356        GuardRecord* insertGuard(jschar* re_chars, size_t re_length)
2357        {
2358            LIns* skip = lirBufWriter->skip(sizeof(GuardRecord) +
2359                                            sizeof(RESideExit) +
2360                                            (re_length-1) * sizeof(jschar));
2361            GuardRecord* guard = (GuardRecord *) skip->payload();
2362            memset(guard, 0, sizeof(*guard));
2363            RESideExit* exit = (RESideExit*)(guard+1);
2364            guard->exit = exit;
2365            guard->exit->target = fragment;
2366            exit->re_flags = re->flags;
2367            exit->re_length = re_length;
2368            memcpy(exit->re_chars, re_chars, re_length * sizeof(jschar));
2369            fragment->lastIns = lir->insGuard(LIR_loop, lir->insImm(1), skip);
2370            return guard;
2371        }
2372    
2373   public:   public:
2374      RegExpNativeCompiler(JSRegExp *re, CompilerState *cs)   RegExpNativeCompiler(JSRegExp* re, CompilerState* cs, Fragment* fragment)
2375          : re(re), cs(cs), fragment(NULL) {  }          : re(re), cs(cs), fragment(fragment), lir(NULL), lirBufWriter(NULL) {  }
2376    
2377      JSBool compile(JSContext* cx)      JSBool compile(JSContext* cx)
2378      {      {
2379          GuardRecord* guard;          GuardRecord* guard = NULL;
         LIns* skip;  
2380          LIns* start;          LIns* start;
2381          bool oom = false;          bool oom = false;
2382                    jschar* re_chars;
2383            size_t re_length;
2384          Fragmento* fragmento = JS_TRACE_MONITOR(cx).reFragmento;          Fragmento* fragmento = JS_TRACE_MONITOR(cx).reFragmento;
2385          fragment = fragmento->getLoop(re);  
2386          if (!fragment) {          JSSTRING_CHARS_AND_LENGTH(re->source, re_chars, re_length);
2387              fragment = fragmento->getAnchor(re);          /*
2388              fragment->lirbuf = new (&gc) LirBuffer(fragmento, NULL);           * If the regexp is too long nanojit will assert when we
2389              /* Scary: required to have the onDestroy method delete the lirbuf. */           * try to insert the guard record.
2390              fragment->root = fragment;           */
2391          }          if (re_length > 1024)
2392                return JS_FALSE;
2393    
2394            this->cx = cx;
2395            /* At this point we have an empty fragment. */
2396          LirBuffer* lirbuf = fragment->lirbuf;          LirBuffer* lirbuf = fragment->lirbuf;
2397          LirBufWriter* lirb;          if (lirbuf->outOMem())
2398          if (lirbuf->outOmem()) goto fail2;              goto fail;
2399          /* FIXME Use bug 463260 smart pointer when available. */          /* FIXME Use bug 463260 smart pointer when available. */
2400          lir = lirb = new (&gc) LirBufWriter(lirbuf);          lir = lirBufWriter = new (&gc) LirBufWriter(lirbuf);
2401    
2402          /* FIXME Use bug 463260 smart pointer when available. */          /* FIXME Use bug 463260 smart pointer when available. */
2403    #ifdef NJ_VERBOSE
2404          debug_only_v(fragment->lirbuf->names = new (&gc) LirNameMap(&gc, NULL, fragmento->labels);)          debug_only_v(fragment->lirbuf->names = new (&gc) LirNameMap(&gc, NULL, fragmento->labels);)
2405    #endif
2406          /* FIXME Use bug 463260 smart pointer when available. */          /* FIXME Use bug 463260 smart pointer when available. */
2407    #ifdef NJ_VERBOSE
2408          debug_only_v(lir = new (&gc) VerboseWriter(&gc, lir, lirbuf->names);)          debug_only_v(lir = new (&gc) VerboseWriter(&gc, lir, lirbuf->names);)
2409    #endif
2410    
2411          lir->ins0(LIR_start);          lir->ins0(LIR_start);
2412          lirbuf->state = state = addName(lirbuf, lir->insParam(0, 0), "state");          lirbuf->state = state = addName(lirbuf, lir->insParam(0, 0), "state");
# Line 2188  Line 2415 
2415          cpend = addName(lirbuf, lir->insLoad(LIR_ldp, lirbuf->param1, offsetof(REGlobalData, cpend)), "cpend");          cpend = addName(lirbuf, lir->insLoad(LIR_ldp, lirbuf->param1, offsetof(REGlobalData, cpend)), "cpend");
2416    
2417          if (cs->flags & JSREG_STICKY) {          if (cs->flags & JSREG_STICKY) {
2418              if (!compileSticky(cs->result, start)) goto fail;              if (!compileSticky(cs->result, start))
2419                    goto fail;
2420          } else {          } else {
2421              if (!compileAnchoring(cs->result, start)) goto fail;              if (!compileAnchoring(cs->result, start))
2422                    goto fail;
2423          }          }
2424    
2425          /* Create fake guard record for loop edge. */          guard = insertGuard(re_chars, re_length);
         skip = lirb->skip(sizeof(GuardRecord) + sizeof(SideExit));  
         guard = (GuardRecord *) skip->payload();  
         memset(guard, 0, sizeof(*guard));  
         guard->exit = (SideExit *) guard+1;  
         guard->exit->target = fragment;  
         fragment->lastIns = lir->insGuard(LIR_loop, lir->insImm(1), skip);  
2426    
2427            if (lirbuf->outOMem())
2428                goto fail;
2429          ::compile(fragmento->assm(), fragment);          ::compile(fragmento->assm(), fragment);
2430          if (fragmento->assm()->error() != nanojit::None) {          if (fragmento->assm()->error() != nanojit::None) {
2431              oom = fragmento->assm()->error() == nanojit::OutOMem;              oom = fragmento->assm()->error() == nanojit::OutOMem;
2432              goto fail;              goto fail;
2433          }          }
2434    
2435          delete lirb;          delete lirBufWriter;
2436    #ifdef NJ_VERBOSE
2437          debug_only_v(delete lir;)          debug_only_v(delete lir;)
2438    #endif
2439          return JS_TRUE;          return JS_TRUE;
2440      fail:      fail:
2441          delete lirb;          if (lirbuf->outOMem() || oom ||
2442          debug_only_v(delete lir;)              js_OverfullFragmento(&JS_TRACE_MONITOR(cx), fragmento)) {
     fail2:  
         if (lirbuf->outOmem() || oom)  
2443              fragmento->clearFrags();              fragmento->clearFrags();
2444                lirbuf->rewind();
2445            } else {
2446                if (!guard) insertGuard(re_chars, re_length);
2447                fragment->blacklist();
2448            }
2449            delete lirBufWriter;
2450    #ifdef NJ_VERBOSE
2451            debug_only_v(delete lir;)
2452    #endif
2453          return JS_FALSE;          return JS_FALSE;
2454      }      }
2455  };  };
2456    
2457    /*
2458     * Compile a regexp to native code in the given fragment.
2459     */
2460  static inline JSBool  static inline JSBool
2461  js_CompileRegExpToNative(JSContext *cx, JSRegExp *re, CompilerState *cs)  CompileRegExpToNative(JSContext* cx, JSRegExp* re, Fragment* fragment)
2462    {
2463        JSBool rv = JS_FALSE;
2464        void* mark;
2465        CompilerState state;
2466        RegExpNativeCompiler rc(re, &state, fragment);
2467    
2468        JS_ASSERT(!fragment->code());
2469        JS_ASSERT(!fragment->isBlacklisted());
2470    
2471        mark = JS_ARENA_MARK(&cx->tempPool);
2472        if (!CompileRegExpToAST(cx, NULL, re->source, re->flags, state)) {
2473            goto out;
2474        }
2475        rv = rc.compile(cx);
2476     out:
2477        JS_ARENA_RELEASE(&cx->tempPool, mark);
2478        return rv;
2479    }
2480    
2481    /* Function type for a compiled native regexp. */
2482    typedef REMatchState* (FASTCALL *NativeRegExp)(REMatchState*, REGlobalData*);
2483    
2484    /*
2485     * Return a compiled native regexp if one already exists or can be created
2486     * now, or NULL otherwise.
2487     */
2488    static NativeRegExp
2489    GetNativeRegExp(JSContext* cx, JSRegExp* re)
2490  {  {
2491      RegExpNativeCompiler rc(re, cs);      Fragment *fragment;
2492      return rc.compile(cx);      jschar* re_chars;
2493        size_t re_length;
2494        Fragmento* fragmento = JS_TRACE_MONITOR(cx).reFragmento;
2495    
2496        JSSTRING_CHARS_AND_LENGTH(re->source, re_chars, re_length);
2497        void* hash = HashRegExp(re->flags, re_chars, re_length);
2498        fragment = LookupNativeRegExp(cx, hash, re->flags, re_chars, re_length);
2499        if (fragment) {
2500            if (fragment->code())
2501                goto ok;
2502            if (fragment->isBlacklisted())
2503                return NULL;
2504        } else {
2505            fragment = fragmento->getAnchor(hash);
2506            fragment->lirbuf = JS_TRACE_MONITOR(cx).reLirBuf;
2507            fragment->root = fragment;
2508        }
2509            
2510        if (!CompileRegExpToNative(cx, re, fragment))
2511            return NULL;
2512     ok:
2513        union { NIns *code; NativeRegExp func; } u;
2514        u.code = fragment->code();
2515        return u.func;
2516  }  }
2517  #endif  #endif
2518    
# Line 2238  Line 2526 
2526      size_t resize;      size_t resize;
2527      jsbytecode *endPC;      jsbytecode *endPC;
2528      uintN i;      uintN i;
     size_t len;  
2529    
2530      re = NULL;      re = NULL;
2531      mark = JS_ARENA_MARK(&cx->tempPool);      mark = JS_ARENA_MARK(&cx->tempPool);
     len = JSSTRING_LENGTH(str);  
2532    
2533      state.context = cx;      /*
2534      state.tokenStream = ts;       * Parsing the string as flat is now expressed internally using
2535      state.cp = js_UndependString(cx, str);       * a flag, so that we keep this information in the JSRegExp, but
2536      if (!state.cp)       * we keep the 'flat' parameter for now for compatibility.
2537         */
2538        if (flat) flags |= JSREG_FLAT;
2539        if (!CompileRegExpToAST(cx, ts, str, flags, state))
2540          goto out;          goto out;
     state.cpbegin = state.cp;  
     state.cpend = state.cp + len;  
     state.flags = flags;  
     state.parenCount = 0;  
     state.classCount = 0;  
     state.progLength = 0;  
     state.treeDepth = 0;  
     state.classBitmapsMem = 0;  
     for (i = 0; i < CLASS_CACHE_SIZE; i++)  
         state.classCache[i].start = NULL;  
   
     if (len != 0 && flat) {  
         state.result = NewRENode(&state, REOP_FLAT);  
         if (!state.result)  
             goto out;  
         state.result->u.flat.chr = *state.cpbegin;  
         state.result->u.flat.length = len;  
         state.result->kid = (void *) state.cpbegin;  
         /* Flat bytecode: REOP_FLAT compact(string_offset) compact(len). */  
         state.progLength += 1 + GetCompactIndexWidth(0)  
                           + GetCompactIndexWidth(len);  
     } else {  
         if (!ParseRegExp(&state))  
             goto out;  
     }  
2541    
2542      resize = offsetof(JSRegExp, program) + state.progLength + 1;      resize = offsetof(JSRegExp, program) + state.progLength + 1;
2543      re = (JSRegExp *) JS_malloc(cx, resize);      re = (JSRegExp *) JS_malloc(cx, resize);
# Line 2297  Line 2561 
2561          re->classList = NULL;          re->classList = NULL;
2562      }      }
2563    
 #ifdef JS_TRACER  
     /*  
      * Try compiling the native code version. For the time being we also  
      * compile the bytecode version in case we evict the native code  
      * version from the code cache.  
      */  
     if (TRACING_ENABLED(cx))  
         js_CompileRegExpToNative(cx, re, &state);  
 #endif  
2564      /* Compile the bytecode version. */      /* Compile the bytecode version. */
2565      endPC = EmitREBytecode(&state, re, state.treeDepth, re->program, state.result);      endPC = EmitREBytecode(&state, re, state.treeDepth, re->program, state.result);
2566      if (!endPC) {      if (!endPC) {
# Line 2319  Line 2574 
2574       * This is safe since no pointers to newly parsed regexp or its parts       * This is safe since no pointers to newly parsed regexp or its parts
2575       * besides re exist here.       * besides re exist here.
2576       */       */
 #if 0  
     /*  
      * FIXME: Until bug 464866 is fixed, we can't move the re object so  
      * don't shrink it for now.  
      */  
2577      if ((size_t)(endPC - re->program) != state.progLength + 1) {      if ((size_t)(endPC - re->program) != state.progLength + 1) {
2578          JSRegExp *tmp;          JSRegExp *tmp;
2579          JS_ASSERT((size_t)(endPC - re->program) < state.progLength + 1);          JS_ASSERT((size_t)(endPC - re->program) < state.progLength + 1);
# Line 2332  Line 2582 
2582          if (tmp)          if (tmp)
2583              re = tmp;              re = tmp;
2584      }      }
 #endif      
2585    
2586      re->flags = flags;      re->flags = flags;
2587      re->parenCount = state.parenCount;      re->parenCount = state.parenCount;
# Line 2355  Line 2604 
2604      if (opt) {      if (opt) {
2605          JSSTRING_CHARS_AND_LENGTH(opt, s, n);          JSSTRING_CHARS_AND_LENGTH(opt, s, n);
2606          for (i = 0; i < n; i++) {          for (i = 0; i < n; i++) {
2607    #define HANDLE_FLAG(name)                                                     \
2608                JS_BEGIN_MACRO                                                    \
2609                    if (flags & (name))                                           \
2610                        goto bad_flag;                                            \
2611                    flags |= (name);                                              \
2612                JS_END_MACRO
2613              switch (s[i]) {              switch (s[i]) {
2614                case 'g':                case 'g':
2615                  flags |= JSREG_GLOB;                  HANDLE_FLAG(JSREG_GLOB);
2616                  break;                  break;
2617                case 'i':                case 'i':
2618                  flags |= JSREG_FOLD;                  HANDLE_FLAG(JSREG_FOLD);
2619                  break;                  break;
2620                case 'm':                case 'm':
2621                  flags |= JSREG_MULTILINE;                  HANDLE_FLAG(JSREG_MULTILINE);
2622                  break;                  break;
2623                case 'y':                case 'y':
2624                  flags |= JSREG_STICKY;                  HANDLE_FLAG(JSREG_STICKY);
2625                  break;                  break;
2626                default:                default:
2627                  bad_flag:
2628                  charBuf[0] = (char)s[i];                  charBuf[0] = (char)s[i];
2629                  charBuf[1] = '\0';                  charBuf[1] = '\0';
2630                  JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,                  JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
2631                                               js_GetErrorMessage, NULL,                                               js_GetErrorMessage, NULL,
2632                                               JSMSG_BAD_FLAG, charBuf);                                               JSMSG_BAD_REGEXP_FLAG, charBuf);
2633                  return NULL;                  return NULL;
2634              }              }
2635    #undef HANDLE_FLAG
2636          }          }
2637      }      }
2638      return js_NewRegExp(cx, NULL, str, flags, flat);      return js_NewRegExp(cx, NULL, str, flags, flat);
# Line 2407  Line 2664 
2664      re_debug("\tBT_Push: %lu,%lu",      re_debug("\tBT_Push: %lu,%lu",
2665               (unsigned long) parenIndex, (unsigned long) parenCount);               (unsigned long) parenIndex, (unsigned long) parenCount);
2666    
     JS_COUNT_OPERATION(gData->cx, JSOW_JUMP * (1 + parenCount));  
2667      if (btincr > 0) {      if (btincr > 0) {
2668          ptrdiff_t offset = (char *)result - (char *)gData->backTrackStack;          ptrdiff_t offset = (char *)result - (char *)gData->backTrackStack;
2669    
         JS_COUNT_OPERATION(gData->cx, JSOW_ALLOCATION);  
2670          btincr = JS_ROUNDUP(btincr, btsize);          btincr = JS_ROUNDUP(btincr, btsize);
2671          JS_ARENA_GROW_CAST(gData->backTrackStack, REBackTrackData *,          JS_ARENA_GROW_CAST(gData->backTrackStack, REBackTrackData *,
2672                             &gData->cx->regexpPool, btsize, btincr);                             &gData->cx->regexpPool, btsize, btincr);
# Line 2637  Line 2892 
2892            
2893  /* Compile the source of the class into a RECharSet */  /* Compile the source of the class into a RECharSet */
2894  static JSBool  static JSBool
2895  ProcessCharSet(REGlobalData *gData, RECharSet *charSet)  ProcessCharSet(JSContext *cx, JSRegExp *re, RECharSet *charSet)
2896  {  {
2897      const jschar *src, *end;      const jschar *src, *end;
2898      JSBool inRange = JS_FALSE;      JSBool inRange = JS_FALSE;
# Line 2653  Line 2908 
2908       */       */
2909      JS_ASSERT(1 <= charSet->u.src.startIndex);      JS_ASSERT(1 <= charSet->u.src.startIndex);
2910      JS_ASSERT(charSet->u.src.startIndex      JS_ASSERT(charSet->u.src.startIndex
2911                < JSSTRING_LENGTH(gData->regexp->source));                < JSSTRING_LENGTH(re->source));
2912      JS_ASSERT(charSet->u.src.length <= JSSTRING_LENGTH(gData->regexp->source)      JS_ASSERT(charSet->u.src.length <= JSSTRING_LENGTH(re->source)
2913                                         - 1 - charSet->u.src.startIndex);                                         - 1 - charSet->u.src.startIndex);
2914    
2915      charSet->converted = JS_TRUE;      charSet->converted = JS_TRUE;
2916      src = JSSTRING_CHARS(gData->regexp->source) + charSet->u.src.startIndex;      src = JSSTRING_CHARS(re->source) + charSet->u.src.startIndex;
2917      end = src + charSet->u.src.length;      end = src + charSet->u.src.length;
2918      JS_ASSERT(src[-1] == '[');      JS_ASSERT(src[-1] == '[');
2919      JS_ASSERT(end[0] == ']');      JS_ASSERT(end[0] == ']');
2920    
2921      byteLength = (charSet->length >> 3) + 1;      byteLength = (charSet->length >> 3) + 1;
2922      charSet->u.bits = (uint8 *)JS_malloc(gData->cx, byteLength);      charSet->u.bits = (uint8 *)JS_malloc(cx, byteLength);
2923      if (!charSet->u.bits) {      if (!charSet->u.bits) {
2924          JS_ReportOutOfMemory(gData->cx);          JS_ReportOutOfMemory(cx);
         gData->ok = JS_FALSE;  
2925          return JS_FALSE;          return JS_FALSE;
2926      }      }
2927      memset(charSet->u.bits, 0, byteLength);      memset(charSet->u.bits, 0, byteLength);
# Line 2806  Line 3060 
3060    
3061          }          }
3062          if (inRange) {          if (inRange) {
3063              if (gData->regexp->flags & JSREG_FOLD) {              if (re->flags & JSREG_FOLD) {
3064                  int i;                  int i;
3065    
3066                  JS_ASSERT(rangeStart <= thisCh);                  JS_ASSERT(rangeStart <= thisCh);
# Line 2826  Line 3080 
3080              }              }
3081              inRange = JS_FALSE;              inRange = JS_FALSE;
3082          } else {          } else {
3083              if (gData->regexp->flags & JSREG_FOLD) {              if (re->flags & JSREG_FOLD) {
3084                  AddCharacterToCharSet(charSet, upcase(thisCh));                  AddCharacterToCharSet(charSet, upcase(thisCh));
3085                  AddCharacterToCharSet(charSet, downcase(thisCh));                  AddCharacterToCharSet(charSet, downcase(thisCh));
3086              } else {              } else {
# Line 2844  Line 3098 
3098      return JS_TRUE;      return JS_TRUE;
3099  }  }
3100    
3101    static inline JSBool
3102    MatcherProcessCharSet(REGlobalData *gData, RECharSet *charSet) {
3103        JSBool rv = ProcessCharSet(gData->cx, gData->regexp, charSet);
3104        if (!rv) gData->ok = JS_FALSE;
3105        return rv;
3106    }
3107    
3108  void  void
3109  js_DestroyRegExp(JSContext *cx, JSRegExp *re)  js_DestroyRegExp(JSContext *cx, JSRegExp *re)
3110  {  {
3111      if (JS_ATOMIC_DECREMENT(&re->nrefs) == 0) {      if (JS_ATOMIC_DECREMENT(&re->nrefs) == 0) {
 #ifdef JS_TRACER  
         /* Don't reuse this compiled code for some new regexp at same addr. */  
         Fragment* fragment = JS_TRACE_MONITOR(cx).reFragmento->getLoop(re);  
         if (fragment)  
             fragment->blacklist();  
 #endif  
3112          if (re->classList) {          if (re->classList) {
3113              uintN i;              uintN i;
3114              for (i = 0; i < re->classCount; i++) {              for (i = 0; i < re->classCount; i++) {
# Line 3178  Line 3433 
3433                          goto doAlt;                          goto doAlt;
3434    
3435                      charSet = &gData->regexp->classList[k];                      charSet = &gData->regexp->classList[k];
3436                      if (!charSet->converted && !ProcessCharSet(gData, charSet))                      if (!charSet->converted && !MatcherProcessCharSet(gData, charSet))
3437                          goto bad;                          goto bad;
3438                      matchCh1 = *x->cp;                      matchCh1 = *x->cp;
3439                      k = matchCh1 >> 3;                      k = matchCh1 >> 3;
# Line 3588  Line 3843 
3843          if (!result) {          if (!result) {
3844              if (gData->cursz == 0)              if (gData->cursz == 0)
3845                  return NULL;                  return NULL;
3846              if (!JS_CHECK_OPERATION_LIMIT(gData->cx, JSOW_JUMP)) {              if (!JS_CHECK_OPERATION_LIMIT(gData->cx)) {
3847                  gData->ok = JS_FALSE;                  gData->ok = JS_FALSE;
3848                  return NULL;                  return NULL;
3849              }              }
# Line 3661  Line 3916 
3916      const jschar *cp2;      const jschar *cp2;
3917      uintN j;      uintN j;
3918  #ifdef JS_TRACER  #ifdef JS_TRACER
3919      Fragment *fragment;      NativeRegExp native;
3920    
3921      /* Run with native regexp if possible. */      /* Run with native regexp if possible. */
3922      if (TRACING_ENABLED(gData->cx) &&      if (TRACING_ENABLED(gData->cx) &&
3923          ((fragment = JS_TRACE_MONITOR(gData->cx).reFragmento->getLoop(gData->regexp)) != NULL)          (native = GetNativeRegExp(gData->cx, gData->regexp))) {
         && fragment->code() && !fragment->isBlacklisted()) {  
         union { NIns *code; REMatchState* (FASTCALL *func)(void*, void*); } u;  
         u.code = fragment->code();  
         REMatchState *lr;  
3924          gData->skipped = (ptrdiff_t) x->cp;          gData->skipped = (ptrdiff_t) x->cp;
3925    
3926          debug_only_v(printf("entering REGEXP trace at %s:%u@%u, code: %p\n",  #ifdef JS_JIT_SPEW
3927                              gData->cx->fp->script->filename,          debug_only_v({
3928                              js_FramePCToLineNumber(gData->cx, gData->cx->fp),              VOUCH_DOES_NOT_REQUIRE_STACK();
3929                              FramePCOffset(gData->cx->fp),              JSStackFrame *caller = (JS_ON_TRACE(gData->cx))
3930                              fragment->code()););                                     ? NULL
3931                                       : js_GetScriptedCaller(gData->cx, NULL);
3932                printf("entering REGEXP trace at %s:%u@%u, code: %p\n",
3933                       caller ? caller->script->filename : "<unknown>",
3934                       caller ? js_FramePCToLineNumber(gData->cx, caller) : 0,
3935                       caller ? FramePCOffset(caller) : 0,
3936                       JS_FUNC_TO_DATA_PTR(void *, native));
3937            })
3938    #endif
3939    
3940  #if defined(JS_NO_FASTCALL) && defined(NANOJIT_IA32)  #if defined(JS_NO_FASTCALL) && defined(NANOJIT_IA32)
3941          SIMULATE_FASTCALL(lr, x, gData, u.func);          SIMULATE_FASTCALL(result, x, gData, native);
3942  #else  #else
3943          lr = u.func(x, gData);          result = native(x, gData);
3944  #endif  #endif
3945    
3946          debug_only_v(printf("leaving REGEXP trace\n"));          debug_only_v(printf("leaving REGEXP trace\n"));
3947    
3948          gData->skipped = ((const jschar *) gData->skipped) - cp;          gData->skipped = ((const jschar *) gData->skipped) - cp;
3949          return lr;          return result;
3950      }      }
3951  #endif  #endif
3952      /*      /*
# Line 3756  Line 4015 
4015    
4016      for (i = 0; i < re->classCount; i++) {      for (i = 0; i < re->classCount; i++) {
4017          if (!re->classList[i].converted &&          if (!re->classList[i].converted &&
4018              !ProcessCharSet(gData, &re->classList[i])) {              !MatcherProcessCharSet(gData, &re->classList[i])) {
4019              return NULL;              return NULL;
4020          }          }
4021      }      }
# Line 4096  Line 4355 
4355      REGEXP_STATIC_RIGHT_CONTEXT = -6      REGEXP_STATIC_RIGHT_CONTEXT = -6
4356  };  };
4357    
4358  JSBool  void
4359  js_InitRegExpStatics(JSContext *cx, JSRegExpStatics *res)  js_InitRegExpStatics(JSContext *cx)
4360  {  {
4361        /*
4362         * To avoid multiple allocations in InitMatch(), the arena size parameter
4363         * should be at least as big as:
4364         *   INITIAL_BACKTRACK
4365         *   + (sizeof(REProgState) * INITIAL_STATESTACK)
4366         *   + (offsetof(REMatchState, parens) + avgParanSize * sizeof(RECapture))
4367         */
4368        JS_INIT_ARENA_POOL(&cx->regexpPool, "regexp",
4369                           12 * 1024 - 40,  /* FIXME: bug 421435 */
4370                           sizeof(void *), &cx->scriptStackQuota);
4371    
4372      JS_ClearRegExpStatics(cx);      JS_ClearRegExpStatics(cx);
4373      return js_AddRoot(cx, &res->input, "res->input");  }
4374    
4375    JS_FRIEND_API(void)
4376    js_SaveRegExpStatics(JSContext *cx, JSRegExpStatics *statics,
4377                         JSTempValueRooter *tvr)
4378    {
4379      *statics = cx->regExpStatics;
4380      JS_PUSH_TEMP_ROOT_STRING(cx, statics->input, tvr);
4381    }
4382    
4383    JS_FRIEND_API(void)
4384    js_RestoreRegExpStatics(JSContext *cx, JSRegExpStatics *statics,
4385                            JSTempValueRooter *tvr)
4386    {
4387      cx->regExpStatics = *statics;
4388      JS_POP_TEMP_ROOT(cx, tvr);
4389    }
4390    
4391    void
4392    js_TraceRegExpStatics(JSTracer *trc, JSContext *acx)
4393    {
4394        JSRegExpStatics *res = &acx->regExpStatics;
4395    
4396        if (res->input)
4397            JS_CALL_STRING_TRACER(trc, res->input, "res->input");
4398  }  }
4399    
4400  void  void
4401  js_FreeRegExpStatics(JSContext *cx, JSRegExpStatics *res)  js_FreeRegExpStatics(JSContext *cx)
4402  {  {
4403        JSRegExpStatics *res = &cx->regExpStatics;
4404    
4405      if (res->moreParens) {      if (res->moreParens) {
4406          JS_free(cx, res->moreParens);          JS_free(cx, res->moreParens);
4407          res->moreParens = NULL;          res->moreParens = NULL;
4408      }      }
4409      js_RemoveRoot(cx->runtime, &res->input);      JS_FinishArenaPool(&cx->regexpPool);
4410  }  }
4411    
4412  static JSBool  static JSBool
# Line 4259  Line 4555 
4555    
4556  #include "jsxdrapi.h"  #include "jsxdrapi.h"
4557    
4558  static JSBool  JSBool
4559  regexp_xdrObject(JSXDRState *xdr, JSObject **objp)  js_XDRRegExpObject(JSXDRState *xdr, JSObject **objp)
4560  {  {
4561      JSRegExp *re;      JSRegExp *re;
4562      JSString *source;      JSString *source;
# Line 4299  Line 4595 
4595    
4596  #else  /* !JS_HAS_XDR */  #else  /* !JS_HAS_XDR */
4597    
4598  #define regexp_xdrObject NULL  #define js_XDRRegExpObject NULL
4599    
4600  #endif /* !JS_HAS_XDR */  #endif /* !JS_HAS_XDR */
4601    
# Line 4323  Line 4619 
4619      JS_ConvertStub,     regexp_finalize,      JS_ConvertStub,     regexp_finalize,
4620      NULL,               NULL,      NULL,               NULL,
4621      regexp_call,        NULL,      regexp_call,        NULL,
4622      regexp_xdrObject,   NULL,      js_XDRRegExpObject, NULL,
4623      JS_CLASS_TRACE(regexp_trace), 0      JS_CLASS_TRACE(regexp_trace), 0
4624  };  };
4625    
# Line 4619  Line 4915 
4915      return JS_TRUE;      return JS_TRUE;
4916  }  }
4917    
 #ifdef JS_TRACER  
 static jsint FASTCALL  
 Regexp_p_test(JSContext* cx, JSObject* regexp, JSString* str)  
 {  
     jsval vp[3] = { JSVAL_NULL, OBJECT_TO_JSVAL(regexp), STRING_TO_JSVAL(str) };  
     if (!regexp_exec_sub(cx, regexp, 1, vp + 2, JS_TRUE, vp))  
         return JSVAL_TO_BOOLEAN(JSVAL_VOID);  
     return *vp == JSVAL_TRUE;  
 }  
   
 JS_DEFINE_TRCINFO_1(regexp_test,  
     (3, (static, BOOL_FAIL, Regexp_p_test, CONTEXT, THIS, STRING,  1, 1)))  
   
 #endif  
   
4918  static JSFunctionSpec regexp_methods[] = {  static JSFunctionSpec regexp_methods[] = {
4919  #if JS_HAS_TOSOURCE  #if JS_HAS_TOSOURCE
4920      JS_FN(js_toSource_str,  regexp_toString,    0,0),      JS_FN(js_toSource_str,  regexp_toString,    0,0),
# Line 4641  Line 4922 
4922      JS_FN(js_toString_str,  regexp_toString,    0,0),      JS_FN(js_toString_str,  regexp_toString,    0,0),
4923      JS_FN("compile",        regexp_compile,     2,0),      JS_FN("compile",        regexp_compile,     2,0),
4924      JS_FN("exec",           regexp_exec,        1,0),      JS_FN("exec",           regexp_exec,        1,0),
4925      JS_TN("test",           regexp_test,        1,0, regexp_test_trcinfo),      JS_FN("test",           regexp_test,        1,0),
4926      JS_FS_END      JS_FS_END
4927  };  };
4928    
4929  static JSBool  static JSBool
4930  RegExp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)  RegExp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
4931  {  {
4932      if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {      if (!JS_IsConstructing(cx)) {
4933          /*          /*
4934           * If first arg is regexp and no flags are given, just return the arg.           * If first arg is regexp and no flags are given, just return the arg.
4935           * (regexp_compile_sub detects the regexp + flags case and throws a           * (regexp_compile_sub detects the regexp + flags case and throws a
# Line 4678  Line 4959 
4959  JSObject *  JSObject *
4960  js_InitRegExpClass(JSContext *cx, JSObject *obj)  js_InitRegExpClass(JSContext *cx, JSObject *obj)
4961  {  {
4962      JSObject *proto, *ctor;      JSObject *proto = js_InitClass(cx, obj, NULL, &js_RegExpClass, RegExp, 1,
4963      jsval rval;                                     regexp_props, regexp_methods,
4964                                       regexp_static_props, NULL);
4965      proto = JS_InitClass(cx, obj, NULL, &js_RegExpClass, RegExp, 1,      if (!proto)
4966                           regexp_props, regexp_methods,          return NULL;
                          regexp_static_props, NULL);  
4967    
4968      if (!proto || !(ctor = JS_GetConstructor(cx, proto)))      JSObject *ctor = JS_GetConstructor(cx, proto);
4969        if (!ctor)
4970          return NULL;          return NULL;
4971    
4972        /* Give RegExp.prototype private data so it matches the empty string. */
4973        jsval rval;
4974      if (!JS_AliasProperty(cx, ctor, "input",        "$_") ||      if (!JS_AliasProperty(cx, ctor, "input",        "$_") ||
4975          !JS_AliasProperty(cx, ctor, "multiline",    "$*") ||          !JS_AliasProperty(cx, ctor, "multiline",    "$*") ||
4976          !JS_AliasProperty(cx, ctor, "lastMatch",    "$&") ||          !JS_AliasProperty(cx, ctor, "lastMatch",    "$&") ||
4977          !JS_AliasProperty(cx, ctor, "lastParen",    "$+") ||          !JS_AliasProperty(cx, ctor, "lastParen",    "$+") ||
4978          !JS_AliasProperty(cx, ctor, "leftContext",  "$`") ||          !JS_AliasProperty(cx, ctor, "leftContext",  "$`") ||
4979          !JS_AliasProperty(cx, ctor, "rightContext", "$'")) {          !JS_AliasProperty(cx, ctor, "rightContext", "$'") ||
4980          goto bad;          !regexp_compile_sub(cx, proto, 0, NULL, &rval)) {
4981            return NULL;
4982      }      }
4983    
     /* Give RegExp.prototype private data so it matches the empty string. */  
     if (!regexp_compile_sub(cx, proto, 0, NULL, &rval))  
         goto bad;  
4984      return proto;      return proto;
   
 bad:  
     JS_DeleteProperty(cx, obj, js_RegExpClass.name);  
     return NULL;  
4985  }  }
4986    
4987  JSObject *  JSObject *
# Line 4713  Line 4991 
4991      JSString *str;      JSString *str;
4992      JSObject *obj;      JSObject *obj;
4993      JSRegExp *re;      JSRegExp *re;
     JSTempValueRooter tvr;  
4994    
4995      str = js_NewStringCopyN(cx, chars, length);      str = js_NewStringCopyN(cx, chars, length);
4996      if (!str)      if (!str)
4997          return NULL;          return NULL;
4998        JSAutoTempValueRooter tvr(cx, str);
4999      re = js_NewRegExp(cx, ts,  str, flags, JS_FALSE);      re = js_NewRegExp(cx, ts,  str, flags, JS_FALSE);
5000      if (!re)      if (!re)
5001          return NULL;          return NULL;
     JS_PUSH_TEMP_ROOT_STRING(cx, str, &tvr);  
5002      obj = js_NewObject(cx, &js_RegExpClass, NULL, NULL, 0);      obj = js_NewObject(cx, &js_RegExpClass, NULL, NULL, 0);
5003      if (!obj || !JS_SetPrivate(cx, obj, re)) {      if (!obj || !JS_SetPrivate(cx, obj, re)) {
5004          js_DestroyRegExp(cx, re);          js_DestroyRegExp(cx, re);
# Line 4729  Line 5006 
5006      }      }
5007      if (obj && !js_SetLastIndex(cx, obj, 0))      if (obj && !js_SetLastIndex(cx, obj, 0))
5008          obj = NULL;          obj = NULL;
     JS_POP_TEMP_ROOT(cx, &tvr);  
5009      return obj;      return obj;
5010  }  }
5011    

Legend:
Removed from v.459  
changed lines
  Added in v.460

  ViewVC Help
Powered by ViewVC 1.1.24