Bug 509818 - Replace StringList with SeqBuilder<char*>, use Allocator, r=dvander.
authorEdwin Smith <edwsmith@adobe.com>
Tue, 04 Aug 2009 09:54:47 -0400
changeset 31507 c9c15d92f6a98bfabca36ff3f34e5d1fe74c85ff
parent 31506 1bd2807717b099626eb0e8b25aaa6d2ee0874f39
child 31508 b735c829735ec00c506b4f6f0f29981ee7621567
push id8556
push userrsayre@mozilla.com
push dateThu, 13 Aug 2009 21:38:45 +0000
treeherderautoland@9734564871cb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs509818
milestone1.9.2a1pre
Bug 509818 - Replace StringList with SeqBuilder<char*>, use Allocator, r=dvander.
js/src/jsregexp.cpp
js/src/jstracer.cpp
js/src/nanojit/Assembler.cpp
js/src/nanojit/Assembler.h
js/src/nanojit/LIR.cpp
js/src/nanojit/LIR.h
js/src/nanojit/nanojit.h
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -3082,22 +3082,23 @@ class RegExpNativeCompiler {
  public:
  RegExpNativeCompiler(JSRegExp* re, CompilerState* cs, Fragment* fragment)
         : re(re), cs(cs), fragment(fragment), lir(NULL), lirBufWriter(NULL) {  }
 
     JSBool compile(JSContext* cx)
     {
         GuardRecord* guard = NULL;
         LIns* pos;
-        Assembler *assm;
         bool oom = false;
         const jschar* re_chars;
         size_t re_length;
-        Fragmento* fragmento = JS_TRACE_MONITOR(cx).reFragmento;
-        VMAllocator *alloc = JS_TRACE_MONITOR(cx).reAllocator;
+        JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
+        Assembler *assm = tm->reAssembler;
+        Fragmento* fragmento = tm->reFragmento;
+        VMAllocator *alloc = tm->reAllocator;
 
         re->source->getCharsAndLength(re_chars, re_length);
         /*
          * If the regexp is too long nanojit will assert when we
          * try to insert the guard record.
          */
         if (re_length > 1024) {
             re->flags |= JSREG_NOCOMPILE;
@@ -3142,34 +3143,33 @@ class RegExpNativeCompiler {
             if (!compileAnchoring(cs->result, pos))
                 goto fail;
         }
 
         guard = insertGuard(re_chars, re_length);
 
         if (alloc->outOfMemory())
             goto fail;
-        assm = JS_TRACE_MONITOR(cx).reAssembler;
-        ::compile(JS_TRACE_MONITOR(cx).reFragmento, assm, fragment);
+        ::compile(fragmento, assm, fragment, *alloc);
         if (assm->error() != nanojit::None) {
             oom = assm->error() == nanojit::OutOMem;
             goto fail;
         }
 
         delete lirBufWriter;
 #ifdef NJ_VERBOSE
         debug_only_stmt( if (js_LogController.lcbits & LC_TMRegexp)
                              delete lir; )
 #endif
         return JS_TRUE;
     fail:
         if (alloc->outOfMemory() || oom ||
-            js_OverfullFragmento(&JS_TRACE_MONITOR(cx), fragmento)) {
+            js_OverfullFragmento(tm, fragmento)) {
             fragmento->clearFrags();
-            JS_TRACE_MONITOR(cx).reCodeAlloc->sweep();
+            tm->reCodeAlloc->sweep();
             alloc->reset();
             lirbuf->clear();
         } else {
             if (!guard) insertGuard(re_chars, re_length);
             re->flags |= JSREG_NOCOMPILE;
         }
         delete lirBufWriter;
 #ifdef NJ_VERBOSE
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -3395,18 +3395,18 @@ TraceRecorder::compile(JSTraceMonitor* t
         Blacklist((jsbytecode*) fragment->root->ip);
         return;
     }
     if (anchor && anchor->exitType != CASE_EXIT)
         ++treeInfo->branchCount;
     if (tm->allocator->outOfMemory())
         return;
 
-    Assembler *assm = JS_TRACE_MONITOR(cx).assembler;
-    ::compile(fragmento, assm, fragment);
+    Assembler *assm = tm->assembler;
+    ::compile(fragmento, assm, fragment, *tm->allocator);
     if (assm->error() == nanojit::OutOMem)
         return;
 
     if (assm->error() != nanojit::None) {
         debug_only_print0(LC_TMTracer, "Blacklisted: error during compilation\n");
         Blacklist((jsbytecode*) fragment->root->ip);
         return;
     }
@@ -6409,17 +6409,18 @@ js_InitJIT(JSTraceMonitor *tm)
 
     if (!tm->allocator)
         tm->allocator = new VMAllocator();
 
     if (!tm->codeAlloc)
         tm->codeAlloc = new CodeAlloc();
 
     if (!tm->assembler)
-        tm->assembler = new (&gc) Assembler(*tm->codeAlloc, core, &js_LogController);
+        tm->assembler = new (&gc) Assembler(*tm->codeAlloc, *tm->allocator, core,
+                                            &js_LogController);
 
     if (!tm->fragmento) {
         JS_ASSERT(!tm->reservedDoublePool);
         Fragmento* fragmento = new (&gc) Fragmento(core, &js_LogController, 32, tm->codeAlloc);
         verbose_only(fragmento->labels = new (&gc) LabelMap(core, *tm->allocator);)
         tm->fragmento = fragmento;
         tm->lirbuf = new (&gc) LirBuffer(*tm->allocator);
 #ifdef DEBUG
@@ -6436,17 +6437,18 @@ js_InitJIT(JSTraceMonitor *tm)
 
     if (!tm->reAllocator)
         tm->reAllocator = new VMAllocator();
 
     if (!tm->reCodeAlloc)
         tm->reCodeAlloc = new CodeAlloc();
 
     if (!tm->reAssembler)
-        tm->reAssembler = new (&gc) Assembler(*tm->reCodeAlloc, core, &js_LogController);
+        tm->reAssembler = new (&gc) Assembler(*tm->reCodeAlloc, *tm->reAllocator, core,
+                                              &js_LogController);
 
     if (!tm->reFragmento) {
         Fragmento* fragmento = new (&gc) Fragmento(core, &js_LogController, 32, tm->reCodeAlloc);
         verbose_only(fragmento->labels = new (&gc) LabelMap(core, *tm->reAllocator);)
         tm->reFragmento = fragmento;
         tm->reLirBuf = new (&gc) LirBuffer(*tm->reAllocator);
 #ifdef DEBUG
         tm->reLirBuf->names = new (&gc) LirNameMap(&gc, *tm->reAllocator, fragmento->labels);
--- a/js/src/nanojit/Assembler.cpp
+++ b/js/src/nanojit/Assembler.cpp
@@ -104,69 +104,64 @@ namespace nanojit
 
     /* A listing filter for LIR, going through backwards.  It merely
        passes its input to its output, but notes it down too.  When
        destructed, prints out what went through.  Is intended to be
        used to print arbitrary intermediate transformation stages of
        LIR. */
     class ReverseLister : public LirFilter
     {
-        avmplus::GC* _gc;
+        Allocator&   _alloc;
         LirNameMap*  _names;
         const char*  _title;
-        StringList*  _strs;
+        StringList   _strs;
         LogControl*  _logc;
     public:
-        ReverseLister(LirFilter* in, avmplus::GC* gc,
+        ReverseLister(LirFilter* in, Allocator& alloc,
                       LirNameMap* names, LogControl* logc, const char* title)
             : LirFilter(in)
-        {
-            _gc    = gc;
-            _names = names;
-            _title = title;
-            _strs  = new StringList(gc);
-            _logc  = logc;
-        }
+            , _alloc(alloc)
+            , _names(names)
+            , _title(title)
+            , _strs(alloc)
+            , _logc(logc)
+         { }
 
-        ~ReverseLister()
+        void finish()
         {
             _logc->printf("\n");
             _logc->printf("=== BEGIN %s ===\n", _title);
-            int i, j;
-            const char* prefix = "  ";
-            for (j = 0, i = _strs->size()-1; i >= 0; i--, j++) {
-                char* str = _strs->get(i);
-                _logc->printf("%s%02d: %s\n", prefix, j, str);
-                _gc->Free(str);
-            }
-            delete _strs;
+            int j = 0;
+            for (Seq<char*>* p = _strs.get(); p != NULL; p = p->tail)
+                _logc->printf("  %02d: %s\n", j++, p->head);
             _logc->printf("=== END %s ===\n", _title);
             _logc->printf("\n");
         }
 
         LInsp read()
         {
             LInsp i = in->read();
             const char* str = _names->formatIns(i);
-            char* cpy = (char*)_gc->Alloc(strlen(str) + 1,  0/*AllocFlags*/);
+            char* cpy = new (_alloc) char[strlen(str)+1];
             strcpy(cpy, str);
-            _strs->add(cpy);
+            _strs.insert(cpy);
             return i;
         }
     };
 #endif
 
     /**
      * Need the following:
      *
      *    - merging paths ( build a graph? ), possibly use external rep to drive codegen
      */
-    Assembler::Assembler(CodeAlloc& codeAlloc, AvmCore *core, LogControl* logc)
+    Assembler::Assembler(CodeAlloc& codeAlloc, Allocator& alloc, AvmCore *core, LogControl* logc)
         : hasLoop(0)
         , codeList(0)
+        , alloc(alloc)
         , core(core)
         , _codeAlloc(codeAlloc)
         , config(core->config)
     {
         nInit(core);
         verbose_only( _logc = logc; )
         verbose_only( _outputCache = 0; )
         verbose_only( outlineEOL[0] = '\0'; )
@@ -698,62 +693,62 @@ namespace nanojit
         // Used for debug printing, if needed
         verbose_only(
         ReverseLister *pp_init = NULL;
         ReverseLister *pp_after_sf1 = NULL;
         ReverseLister *pp_after_sf2 = NULL;
         )
 
         // set up backwards pipeline: assembler -> StackFilter -> LirReader
-        avmplus::GC *gc = core->gc;
         LirReader bufreader(frag->lastIns);
 
         // Used to construct the pipeline
         LirFilter* prev = &bufreader;
 
         // The LIR passes through these filters as listed in this
         // function, viz, top to bottom.
 
         // INITIAL PRINTING
         verbose_only( if (_logc->lcbits & LC_ReadLIR) {
-        pp_init = new ReverseLister(prev, gc, frag->lirbuf->names, _logc,
-                                    "Initial LIR");
+        pp_init = new (alloc) ReverseLister(prev, alloc, frag->lirbuf->names, _logc,
+                                            "Initial LIR");
         prev = pp_init;
         })
 
         // STOREFILTER for sp
-        StackFilter storefilter1(prev, frag->lirbuf, frag->lirbuf->sp);
+        StackFilter storefilter1(prev, alloc, frag->lirbuf, frag->lirbuf->sp);
         prev = &storefilter1;
 
         verbose_only( if (_logc->lcbits & LC_AfterSF_SP) {
-        pp_after_sf1 = new ReverseLister(prev, gc, frag->lirbuf->names, _logc,
-                                         "After Storefilter(sp)");
+        pp_after_sf1 = new (alloc) ReverseLister(prev, alloc, frag->lirbuf->names, _logc,
+                                                 "After Storefilter(sp)");
         prev = pp_after_sf1;
         })
 
         // STOREFILTER for rp
-        StackFilter storefilter2(prev, frag->lirbuf, frag->lirbuf->rp);
+        StackFilter storefilter2(prev, alloc, frag->lirbuf, frag->lirbuf->rp);
         prev = &storefilter2;
 
         verbose_only( if (_logc->lcbits & LC_AfterSF_RP) {
-        pp_after_sf2 = new ReverseLister(prev, gc, frag->lirbuf->names, _logc,
-                                         "After StoreFilter(rp) (final LIR)");
+        pp_after_sf2 = new (alloc) ReverseLister(prev, alloc, frag->lirbuf->names, _logc,
+                                                 "After StoreFilter(rp) (final LIR)");
         prev = pp_after_sf2;
         })
 
         // end of pipeline
         verbose_only(
         VerboseBlockReader vbr(prev, this, frag->lirbuf->names);
         if (_logc->lcbits & LC_Assembly)
             prev = &vbr;
         )
 
         verbose_only(_thisfrag->compileNbr++; )
         _inExit = false;
 
+        GC* gc = core->gc;
         LabelStateMap labels(_gc);
         NInsMap patches(_gc);
         gen(prev, loopJumps, labels, patches);
         frag->loopEntry = _nIns;
         //frag->outbound = config.tree_opt? _latestGuard : 0;
         //nj_dprintf("assemble frag %X entry %X\n", (int)frag, (int)frag->fragEntry);
 
         if (!error()) {
@@ -770,22 +765,21 @@ namespace nanojit
                 else {
                     setError(UnknownBranch);
                     break;
                 }
             }
         }
 
         // If we were accumulating debug info in the various ReverseListers,
-        // destruct them now.  Their destructors cause them to emit whatever
-        // contents they have accumulated.
+        // call finish() to emit whatever contents they have accumulated.
         verbose_only(
-        if (pp_init)       delete pp_init;
-        if (pp_after_sf1)  delete pp_after_sf1;
-        if (pp_after_sf2)  delete pp_after_sf2;
+        if (pp_init)       pp_init->finish();
+        if (pp_after_sf1)  pp_after_sf1->finish();
+        if (pp_after_sf2)  pp_after_sf2->finish();
         )
     }
 
     void Assembler::endAssembly(Fragment* frag, NInsList& loopJumps)
     {
         // don't try to patch code if we are in an error state since we might have partially
         // overwritten the code cache already
         if (error()) {
@@ -1820,19 +1814,19 @@ namespace nanojit
 
             output(outline);
         }
 
         void Assembler::output(const char* s)
         {
             if (_outputCache)
             {
-                char* str = (char*)_gc->Alloc(strlen(s)+1);
+                char* str = new (alloc) char[VMPI_strlen(s)+1];
                 strcpy(str, s);
-                _outputCache->add(str);
+                _outputCache->insert(str);
             }
             else
             {
                 _logc->printf("%s\n", s);
             }
         }
 
         void Assembler::output_asm(const char* s)
--- a/js/src/nanojit/Assembler.h
+++ b/js/src/nanojit/Assembler.h
@@ -131,16 +131,19 @@ namespace nanojit
     public:
         LabelStateMap(avmplus::GC *gc) : gc(gc), labels(gc)
         {}
         ~LabelStateMap();
 
         void add(LIns *label, NIns *addr, RegAlloc &regs);
         LabelState *get(LIns *);
     };
+
+    typedef SeqBuilder<char*> StringList;
+
     /**
      * Information about the activation record for the method is built up
      * as we generate machine code.  As part of the prologue, we issue
      * a stack adjustment instruction and then later patch the adjustment
      * value.  Temporary values can be placed into the AR as method calls
      * are issued.   Also LIR_alloc instructions will consume space.
      */
     class Assembler MMGC_SUBCLASS_DECL
@@ -162,17 +165,17 @@ namespace nanojit
 
             StringList* _outputCache;
 
             // Log controller object.  Contains what-stuff-should-we-print
             // bits, and a sink function for debug printing
             LogControl* _logc;
             #endif
 
-            Assembler(CodeAlloc& codeAlloc, AvmCore* core, LogControl* logc);
+            Assembler(CodeAlloc& codeAlloc, Allocator& alloc, AvmCore* core, LogControl* logc);
             ~Assembler() {}
 
             void        assemble(Fragment* frag, NInsList& loopJumps);
             void        endAssembly(Fragment* frag, NInsList& loopJumps);
             void        beginAssembly(Fragment *frag, RegAllocMap* map);
             void        copyRegisters(RegAlloc* copyTo);
             void        releaseRegisters();
             void        patch(GuardRecord *lr);
@@ -227,16 +230,17 @@ namespace nanojit
             void        codeAlloc(NIns *&start, NIns *&end, NIns *&eip);
             bool        canRemat(LIns*);
 
             Reservation* getresv(LIns *x) {
                 Reservation* r = x->resv();
                 return r->used ? r : 0;
             }
 
+            Allocator           &alloc;
             AvmCore             *core;
             CodeAlloc&          _codeAlloc;
             avmplus::GC*        _gc;
             DWB(Fragment*)      _thisfrag;
             RegAllocMap*        _branchStateMap;
 
             NIns        *codeStart, *codeEnd;       // current block we're adding code to
             NIns        *exitStart, *exitEnd;       // current block for exit stubs
--- a/js/src/nanojit/LIR.cpp
+++ b/js/src/nanojit/LIR.cpp
@@ -1012,18 +1012,18 @@ namespace nanojit
 #else
         ins->initLInsC(op, argc, ci);
 #endif
         return ins;
     }
 
     using namespace avmplus;
 
-    StackFilter::StackFilter(LirFilter *in, LirBuffer *lirbuf, LInsp sp)
-        : LirFilter(in), lirbuf(lirbuf), sp(sp), top(0)
+    StackFilter::StackFilter(LirFilter *in, Allocator& alloc, LirBuffer *lirbuf, LInsp sp)
+        : LirFilter(in), lirbuf(lirbuf), sp(sp), stk(alloc), top(0)
     {}
 
     LInsp StackFilter::read()
     {
         for (;;)
         {
             LInsp i = in->read();
             if (i->isStore())
@@ -1496,25 +1496,25 @@ namespace nanojit
             live.remove(i);
             retired.add(e);
         }
         bool contains(LInsp i) {
             return live.containsKey(i);
         }
     };
 
-    void live(GC *gc, Fragment *frag, LogControl *logc)
+    void live(GC *gc, Allocator& alloc, Fragment *frag, LogControl *logc)
     {
         // traverse backwards to find live exprs and a few other stats.
 
         LiveTable live(gc);
         uint32_t exits = 0;
         LirReader br(frag->lastIns);
-        StackFilter sf(&br, frag->lirbuf, frag->lirbuf->sp);
-        StackFilter r(&sf, frag->lirbuf, frag->lirbuf->rp);
+        StackFilter sf(&br, alloc, frag->lirbuf, frag->lirbuf->sp);
+        StackFilter r(&sf, alloc, frag->lirbuf, frag->lirbuf->rp);
         int total = 0;
         if (frag->lirbuf->state)
             live.add(frag->lirbuf->state, r.pos());
         for (LInsp i = r.read(); !i->isop(LIR_start); i = r.read())
         {
             total++;
 
             // first handle side-effect instructions
@@ -1973,17 +1973,17 @@ namespace nanojit
         return out->insCall(ci, args);
     }
 
     LIns* FASTCALL callArgN(LIns* i, uint32_t n)
     {
         return i->arg(i->argc()-n-1);
     }
 
-    void compile(Fragmento* frago, Assembler* assm, Fragment* triggerFrag)
+    void compile(Fragmento* frago, Assembler* assm, Fragment* triggerFrag, Allocator& alloc)
     {
         AvmCore *core = frago->core();
 #ifdef NJ_VERBOSE
         LabelMap* labels = frago->labels;
 #endif
         GC *gc = core->gc;
 
         verbose_only(
@@ -2003,21 +2003,21 @@ namespace nanojit
             logc->printf("===\n");
         })
         /* END decorative preamble */
 
         verbose_only( if (liveVerb) {
             logc->printf("\n");
             logc->printf("=== Results of liveness analysis:\n");
             logc->printf("===\n");
-            live(gc, triggerFrag, logc);
+            live(gc, alloc, triggerFrag, logc);
         })
 
         /* Set up the generic text output cache for the assembler */
-        verbose_only( StringList asmOutput(gc); )
+        verbose_only( StringList asmOutput(alloc); )
         verbose_only( assm->_outputCache = &asmOutput; )
 
         bool treeCompile = core->config.tree_opt && (triggerFrag->kind == BranchTrace);
         RegAllocMap regMap(gc);
         NInsList loopJumps(gc);
 #ifdef MEMORY_INFO
 //        loopJumps.set_meminfo_name("LIR loopjumps");
 #endif
@@ -2101,26 +2101,25 @@ namespace nanojit
 
         // reverse output so that assembly is displayed low-to-high
         // Up to this point, assm->_outputCache has been non-NULL, and so
         // has been accumulating output.  Now we set it to NULL, traverse
         // the entire list of stored strings, and hand them a second time
         // to assm->output.  Since _outputCache is now NULL, outputf just
         // hands these strings directly onwards to logc->printf.
         verbose_only( if (anyVerb) {
-               logc->printf("\n");
+            logc->printf("\n");
             logc->printf("=== Aggregated assembly output: BEGIN\n");
-               logc->printf("===\n");
+            logc->printf("===\n");
             assm->_outputCache = 0;
-            for (int i = asmOutput.size() - 1; i >= 0; --i) {
-                char* str = asmOutput.get(i);
+            for (Seq<char*>* p = asmOutput.get(); p != NULL; p = p->tail) {
+                char *str = p->head;
                 assm->outputf("  %s", str);
-                gc->Free(str);
             }
-               logc->printf("===\n");
+            logc->printf("===\n");
             logc->printf("=== Aggregated assembly output: END\n");
         });
 
         if (assm->error()) {
             root->fragEntry = 0;
             root->loopEntry = 0;
         }
         else
--- a/js/src/nanojit/LIR.h
+++ b/js/src/nanojit/LIR.h
@@ -1188,29 +1188,28 @@ namespace nanojit
         }
         void setpos(LIns *i) {
             _i = i;
         }
     };
 
     class Assembler;
 
-    void compile(Fragmento *frago, Assembler *assm, Fragment *frag);
+    void compile(Fragmento *frago, Assembler *assm, Fragment *frag, Allocator& alloc);
     verbose_only(void live(GC *gc, LirBuffer *lirbuf);)
 
     class StackFilter: public LirFilter
     {
         LirBuffer *lirbuf;
         LInsp sp;
-        avmplus::BitSet stk;
+        BitSet stk;
         int top;
         int getTop(LInsp br);
     public:
-        StackFilter(LirFilter *in, LirBuffer *lirbuf, LInsp sp);
-        virtual ~StackFilter() {}
+        StackFilter(LirFilter *in, Allocator& alloc, LirBuffer *lirbuf, LInsp sp);
         LInsp read();
     };
 
     // eliminate redundant loads by watching for stores & mutator calls
     class LoadFilter: public LirWriter
     {
     public:
         LInsp sp, rp;
--- a/js/src/nanojit/nanojit.h
+++ b/js/src/nanojit/nanojit.h
@@ -120,17 +120,16 @@ namespace nanojit
     class LIns;
     struct SideExit;
     class RegAlloc;
     typedef avmplus::AvmCore AvmCore;
     typedef avmplus::OSDep OSDep;
     typedef avmplus::GCSortedMap<const void*,Fragment*,avmplus::LIST_GCObjects> FragmentMap;
     typedef avmplus::SortedMap<SideExit*,RegAlloc*,avmplus::LIST_GCObjects> RegAllocMap;
     typedef avmplus::List<LIns*,avmplus::LIST_NonGCObjects>    InsList;
-    typedef avmplus::List<char*, avmplus::LIST_GCObjects> StringList;
 
     const uint32_t MAXARGS = 8;
 
     #ifdef MOZ_NO_VARADIC_MACROS
         static void NanoAssertMsgf(bool a,const char *f,...) {}
         static void NanoAssertMsg(bool a,const char *m) {}
         static void NanoAssert(bool a) {}
     #elif defined(_DEBUG)