Bug 647390 - Remove the calloc+placement-new pattern (r=luke)
authorReuben Morais <reuben.morais@gmail.com>
Wed, 28 Sep 2011 09:17:51 -0700
changeset 77811 611807062ab55a9dee7e202a8ff33b444e7614b4
parent 77810 ea0d2b03cfcf7547d6c8acbc360e47595eb90a66
child 77812 4320fd88ed156bd949a4ab6fbe31778b30c227bf
push id2266
push userlwagner@mozilla.com
push dateThu, 29 Sep 2011 16:15:28 +0000
treeherdermozilla-inbound@611807062ab5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs647390
milestone10.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 647390 - Remove the calloc+placement-new pattern (r=luke)
js/src/jsapi.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -631,21 +631,109 @@ JS_IsBuiltinFunctionConstructor(JSFuncti
 /*
  * Has a new runtime ever been created?  This flag is used to detect unsafe
  * changes to js_CStringsAreUTF8 after a runtime has been created, and to
  * control things that should happen only once across all runtimes.
  */
 static JSBool js_NewRuntimeWasCalled = JS_FALSE;
 
 JSRuntime::JSRuntime()
-  : trustedPrincipals_(NULL)
+  : atomsCompartment(NULL),
+#ifdef JS_THREADSAFE
+    atomsCompartmentIsLocked(false),
+#endif
+    state(),
+    cxCallback(NULL),
+    compartmentCallback(NULL),
+    activityCallback(NULL),
+    activityCallbackArg(NULL),
+    protoHazardShape(0),
+    gcSystemAvailableChunkListHead(NULL),
+    gcUserAvailableChunkListHead(NULL),
+    gcEmptyChunkListHead(NULL),
+    gcEmptyChunkCount(0),
+    gcKeepAtoms(0),
+    gcBytes(0),
+    gcTriggerBytes(0),
+    gcLastBytes(0),
+    gcMaxBytes(0),
+    gcMaxMallocBytes(0),
+    gcEmptyArenaPoolLifespan(0),
+    gcNumber(0),
+    gcMarkingTracer(NULL),
+    gcChunkAllocationSinceLastGC(false),
+    gcNextFullGCTime(0),
+    gcJitReleaseTime(0),
+    gcMode(JSGC_MODE_GLOBAL),
+    gcIsNeeded(0),
+    gcWeakMapList(NULL),
+    gcTriggerCompartment(NULL),
+    gcCurrentCompartment(NULL),
+    gcCheckCompartment(NULL),
+    gcPoke(false),
+    gcMarkAndSweep(false),
+    gcRunning(false),
+    gcRegenShapes(false),
+#ifdef JS_GC_ZEAL
+    gcZeal_(0),
+    gcZealFrequency(0),
+    gcNextScheduled(0),
+    gcDebugCompartmentGC(false),
+#endif
+    gcCallback(NULL),
+    gcMallocBytes(0),
+    gcExtraRootsTraceOp(NULL),
+    gcExtraRootsData(NULL),
+    NaNValue(UndefinedValue()),
+    negativeInfinityValue(UndefinedValue()),
+    positiveInfinityValue(UndefinedValue()),
+    emptyString(NULL),
+    debugMode(false),
+    hadOutOfMemory(false),
+    data(NULL),
+#ifdef JS_THREADSAFE
+    gcLock(NULL),
+    gcDone(NULL),
+    requestDone(NULL),
+    requestCount(0),
+    gcThread(NULL),
+    rtLock(NULL),
+# ifdef DEBUG
+    rtLockOwner(0),
+# endif
+    stateChange(NULL),
+#endif
+    debuggerMutations(0),
+    securityCallbacks(NULL),
+    structuredCloneCallbacks(NULL),
+    propertyRemovals(0),
+    scriptFilenameTable(NULL),
+#ifdef JS_THREADSAFE
+    scriptFilenameTableLock(NULL),
+#endif
+    thousandsSeparator(0),
+    decimalSeparator(0),
+    numGrouping(0),
+    anynameObject(NULL),
+    functionNamespaceObject(NULL),
+#ifdef JS_THREADSAFE
+    interruptCounter(0),
+#endif
+    trustedPrincipals_(NULL),
+    shapeGen(0),
+    wrapObjectCallback(NULL),
+    preWrapObjectCallback(NULL),
+    inOOMReport(0)
 {
     /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
     JS_INIT_CLIST(&contextList);
     JS_INIT_CLIST(&debuggerList);
+
+    PodZero(&globalDebugHooks);
+    PodZero(&atomState);
 }
 
 bool
 JSRuntime::init(uint32 maxbytes)
 {
 #ifdef JS_METHODJIT_SPEW
     JMCheckLogging();
 #endif
@@ -764,21 +852,20 @@ JS_NewRuntime(uint32 maxbytes)
     JS_END_MACRO;
 #include "js.msg"
 #undef MSG_DEF
 #endif /* DEBUG */
 
         js_NewRuntimeWasCalled = JS_TRUE;
     }
 
-    void *mem = OffTheBooks::calloc_(sizeof(JSRuntime));
-    if (!mem)
+    JSRuntime *rt = OffTheBooks::new_<JSRuntime>();
+    if (!rt)
         return NULL;
 
-    JSRuntime *rt = new (mem) JSRuntime();
     if (!rt->init(maxbytes)) {
         JS_DestroyRuntime(rt);
         return NULL;
     }
 
     Probes::createRuntime(rt);
     return rt;
 }
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -314,66 +314,54 @@ js_PurgeThreads(JSContext *cx)
 #else
     cx->runtime->threadData.purge(cx);
 #endif
 }
 
 JSContext *
 js_NewContext(JSRuntime *rt, size_t stackChunkSize)
 {
-    JSContext *cx;
-    JSBool first;
-    JSContextCallback cxCallback;
-
     /*
      * We need to initialize the new context fully before adding it to the
      * runtime list. After that it can be accessed from another thread via
      * js_ContextIterator.
      */
-    void *mem = OffTheBooks::calloc_(sizeof *cx);
-    if (!mem)
+    JSContext *cx = OffTheBooks::new_<JSContext>(rt);
+    if (!cx)
         return NULL;
 
-    cx = new (mem) JSContext(rt);
-    cx->debugHooks = &rt->globalDebugHooks;
-#if JS_STACK_GROWTH_DIRECTION > 0
-    cx->stackLimit = (jsuword) -1;
-#endif
-    cx->iterValue.setMagic(JS_NO_ITER_VALUE);
-    JS_STATIC_ASSERT(JSVERSION_DEFAULT == 0);
     JS_ASSERT(cx->findVersion() == JSVERSION_DEFAULT);
     VOUCH_DOES_NOT_REQUIRE_STACK();
 
-    JS_ASSERT(cx->resolveFlags == 0);
-
     if (!cx->busyArrays.init()) {
         Foreground::delete_(cx);
         return NULL;
     }
 
 #ifdef JS_THREADSAFE
     if (!js_InitContextThreadAndLockGC(cx)) {
         Foreground::delete_(cx);
         return NULL;
     }
 #endif
 
     /*
      * Here the GC lock is still held after js_InitContextThreadAndLockGC took it and
      * the GC is not running on another thread.
      */
+    bool first;
     for (;;) {
         if (rt->state == JSRTS_UP) {
             JS_ASSERT(!JS_CLIST_IS_EMPTY(&rt->contextList));
-            first = JS_FALSE;
+            first = false;
             break;
         }
         if (rt->state == JSRTS_DOWN) {
             JS_ASSERT(JS_CLIST_IS_EMPTY(&rt->contextList));
-            first = JS_TRUE;
+            first = true;
             rt->state = JSRTS_LAUNCHING;
             break;
         }
         JS_WAIT_CONDVAR(rt->stateChange, JS_NO_TIMEOUT);
 
         /*
          * During the above wait after we are notified about the state change
          * but before we wake up, another thread could enter the GC from
@@ -412,17 +400,17 @@ js_NewContext(JSRuntime *rt, size_t stac
             return NULL;
         }
 
         AutoLockGC lock(rt);
         rt->state = JSRTS_UP;
         JS_NOTIFY_ALL_CONDVAR(rt->stateChange);
     }
 
-    cxCallback = rt->cxCallback;
+    JSContextCallback cxCallback = rt->cxCallback;
     if (cxCallback && !cxCallback(cx, JSCONTEXT_NEW)) {
         js_DestroyContext(cx, JSDCM_NEW_FAILED);
         return NULL;
     }
 
     return cx;
 }
 
@@ -1341,25 +1329,78 @@ DSTOffsetCache::purge()
  * doesn't return a bogus offset.
  */
 DSTOffsetCache::DSTOffsetCache()
 {
     purge();
 }
 
 JSContext::JSContext(JSRuntime *rt)
-  : hasVersionOverride(false),
+  : defaultVersion(JSVERSION_DEFAULT),
+    hasVersionOverride(false),
+    throwing(false),
+    exception(UndefinedValue()),
+    runOptions(0),
+    localeCallbacks(NULL),
+    resolvingList(NULL),
+    generatingError(false),
+#if JS_STACK_GROWTH_DIRECTION > 0
+    stackLimit((jsuword)-1),
+#else
+    stackLimit(0),
+#endif
     runtime(rt),
     compartment(NULL),
-    stack(thisDuringConstruction()),
-    busyArrays()
+#ifdef JS_THREADSAFE
+    thread_(NULL),
+#endif
+    stack(thisDuringConstruction()),  /* depends on cx->thread_ */
+    parseMapPool_(NULL),
+    globalObject(NULL),
+    argumentFormatMap(NULL),
+    lastMessage(NULL),
+    errorReporter(NULL),
+    operationCallback(NULL),
+    data(NULL),
+    data2(NULL),
+#ifdef JS_THREADSAFE
+    outstandingRequests(0),
+#endif
+    autoGCRooters(NULL),
+    debugHooks(&rt->globalDebugHooks),
+    securityCallbacks(NULL),
+    resolveFlags(0),
+    rngSeed(0),
+    iterValue(MagicValue(JS_NO_ITER_VALUE)),
+#ifdef JS_TRACER
+    traceJitEnabled(false),
+#endif
+#ifdef JS_METHODJIT
+    methodJitEnabled(false),
+    profilingEnabled(false),
+#endif
+    inferenceEnabled(false),
+#ifdef MOZ_TRACE_JSCALLS
+    functionCallback(NULL),
+#endif
+    enumerators(NULL),
+#ifdef JS_THREADSAFE
+    gcBackgroundFree(NULL),
+#endif
+    activeCompilations(0)
 #ifdef DEBUG
     , stackIterAssertionEnabled(true)
 #endif
-{}
+{
+    PodZero(&sharpObjectMap);
+    PodZero(&link);
+#ifdef JS_THREADSAFE
+    PodZero(&threadLinks);
+#endif
+}
 
 JSContext::~JSContext()
 {
 #ifdef JS_THREADSAFE
     JS_ASSERT(!thread_);
 #endif
 
     /* Free the stuff hanging off of cx. */
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -671,16 +671,27 @@ struct JSRuntime {
      * To ensure that cx->malloc does not cause a GC, we set this flag during
      * OOM reporting (in js_ReportOutOfMemory). If a GC is requested while
      * reporting the OOM, we ignore it.
      */
     int32               inOOMReport;
 
 #if defined(MOZ_GCTIMER) || defined(JSGC_TESTPILOT)
     struct GCData {
+        GCData()
+          : firstEnter(0),
+            firstEnterValid(false)
+#ifdef JSGC_TESTPILOT
+            , infoEnabled(false),
+            info(),
+            start(0),
+            count(0)
+#endif
+        { }
+
         /*
          * Timestamp of the first GCTimer -- application runtime is determined
          * relative to this value.
          */
         uint64      firstEnter;
         bool        firstEnterValid;
 
         void setFirstEnter(uint64 v) {
@@ -978,16 +989,26 @@ struct JSContext
     /* Data shared by threads in an address space. */
     JSRuntime *const    runtime;
 
     /* GC heap compartment. */
     JSCompartment       *compartment;
 
     inline void setCompartment(JSCompartment *compartment);
 
+#ifdef JS_THREADSAFE
+  private:
+    JSThread            *thread_;
+  public:
+    JSThread *thread() const { return thread_; }
+
+    void setThread(JSThread *thread);
+    static const size_t threadOffset() { return offsetof(JSContext, thread_); }
+#endif
+
     /* Current execution stack. */
     js::ContextStack    stack;
 
     /* ContextStack convenience functions */
     bool hasfp() const                { return stack.hasfp(); }
     js::StackFrame* fp() const        { return stack.fp(); }
     js::StackFrame* maybefp() const   { return stack.maybefp(); }
     js::FrameRegs& regs() const       { return stack.regs(); }
@@ -1142,24 +1163,16 @@ struct JSContext
     bool hasStrictOption() const { return hasRunOption(JSOPTION_STRICT); }
     bool hasWErrorOption() const { return hasRunOption(JSOPTION_WERROR); }
     bool hasAtLineOption() const { return hasRunOption(JSOPTION_ATLINE); }
 
     js::LifoAlloc &tempLifoAlloc() { return JS_THREAD_DATA(this)->tempLifoAlloc; }
     inline js::LifoAlloc &typeLifoAlloc();
 
 #ifdef JS_THREADSAFE
-  private:
-    JSThread            *thread_;
-  public:
-    JSThread *thread() const { return thread_; }
-
-    void setThread(JSThread *thread);
-    static const size_t threadOffset() { return offsetof(JSContext, thread_); }
-
     unsigned            outstandingRequests;/* number of JS_BeginRequest calls
                                                without the corresponding
                                                JS_EndRequest. */
     JSCList             threadLinks;        /* JSThread contextList linkage */
 #endif
 
     /* Stack of thread-stack-allocated GC roots. */
     js::AutoGCRooter   *autoGCRooters;