Moved the global-pool-allocator to TCompiler so that all memory allocated by the compiler can be de-allocated. Earlier the global-pool-allocator kept accumulating memory from all compilers (symbol-table in particular). The memory was only de-allocated when gpu-process exited or ShFinalize() was called. This was a problem for Chromium which keeps the GPU process around for the browser session. Now the memory is de-allocated as soon as the compiler is deleted, which happens when a tab is closed.
BUG=58808 (crbug.com)
Review URL: http://codereview.appspot.com/3280041

git-svn-id: http://angleproject.googlecode.com/svn/trunk@489 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/compiler/Compiler.cpp b/src/compiler/Compiler.cpp
index 322595b..11acfae 100644
--- a/src/compiler/Compiler.cpp
+++ b/src/compiler/Compiler.cpp
@@ -8,10 +8,11 @@
 #include "compiler/ParseHelper.h"
 #include "compiler/ShHandle.h"
 
-static bool InitializeSymbolTable(
-        const TBuiltInStrings& builtInStrings,
-        ShShaderType type, ShShaderSpec spec, const ShBuiltInResources& resources,
-        TInfoSink& infoSink, TSymbolTable& symbolTable)
+namespace {
+bool InitializeSymbolTable(
+    const TBuiltInStrings& builtInStrings,
+    ShShaderType type, ShShaderSpec spec, const ShBuiltInResources& resources,
+    TInfoSink& infoSink, TSymbolTable& symbolTable)
 {
     TIntermediate intermediate(infoSink);
     TExtensionBehavior extBehavior;
@@ -49,6 +50,34 @@
     return true;
 }
 
+class TScopedPoolAllocator {
+public:
+    TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
+        : mAllocator(allocator), mPushPopAllocator(pushPop) {
+        if (mPushPopAllocator) mAllocator->push();
+        SetGlobalPoolAllocator(mAllocator);
+    }
+    ~TScopedPoolAllocator() {
+        SetGlobalPoolAllocator(NULL);
+        if (mPushPopAllocator) mAllocator->pop();
+    }
+
+private:
+    TPoolAllocator* mAllocator;
+    bool mPushPopAllocator;
+};
+}  // namespace
+
+TShHandleBase::TShHandleBase() {
+    allocator.push();
+    SetGlobalPoolAllocator(&allocator);
+}
+
+TShHandleBase::~TShHandleBase() {
+    SetGlobalPoolAllocator(NULL);
+    allocator.popAll();
+}
+
 TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
     : shaderType(type),
       shaderSpec(spec) 
@@ -61,11 +90,13 @@
 
 bool TCompiler::Init(const ShBuiltInResources& resources)
 {
+    TScopedPoolAllocator scopedAlloc(&allocator, false);
+
     // Generate built-in symbol table.
     if (!InitBuiltInSymbolTable(resources))
         return false;
-
     InitExtensionBehavior(resources, extensionBehavior);
+
     return true;
 }
 
@@ -73,6 +104,7 @@
                         const int numStrings,
                         int compileOptions)
 {
+    TScopedPoolAllocator scopedAlloc(&allocator, true);
     clearResults();
 
     if (numStrings == 0)
diff --git a/src/compiler/PoolAlloc.cpp b/src/compiler/PoolAlloc.cpp
index 8cbe560..ff44353 100644
--- a/src/compiler/PoolAlloc.cpp
+++ b/src/compiler/PoolAlloc.cpp
@@ -22,14 +22,10 @@
     if (globalPools)
         return;
 
-    TPoolAllocator *globalPoolAllocator = new TPoolAllocator(true);
-
     TThreadGlobalPools* threadData = new TThreadGlobalPools();
-    
-    threadData->globalPoolAllocator = globalPoolAllocator;
-        
-    OS_SetTLSValue(PoolIndex, threadData);     
-    globalPoolAllocator->push();
+    threadData->globalPoolAllocator = 0;
+
+    OS_SetTLSValue(PoolIndex, threadData);
 }
 
 void FreeGlobalPools()
@@ -38,9 +34,7 @@
     TThreadGlobalPools* globalPools= static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex));    
     if (!globalPools)
         return;
-    
-    GlobalPoolAllocator.popAll();
-    delete &GlobalPoolAllocator;       
+ 
     delete globalPools;
 }
 
@@ -66,7 +60,7 @@
     return *threadData->globalPoolAllocator;
 }
 
-void SetGlobalPoolAllocatorPtr(TPoolAllocator* poolAllocator)
+void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator)
 {
     TThreadGlobalPools* threadData = static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex));
 
@@ -77,8 +71,7 @@
 // Implement the functionality of the TPoolAllocator class, which
 // is documented in PoolAlloc.h.
 //
-TPoolAllocator::TPoolAllocator(bool g, int growthIncrement, int allocationAlignment) : 
-    global(g),
+TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) : 
     pageSize(growthIncrement),
     alignment(allocationAlignment),
     freeList(0),
@@ -124,24 +117,14 @@
 
 TPoolAllocator::~TPoolAllocator()
 {
-    if (!global) {
-        //
-        // Then we know that this object is not being 
-        // allocated after other, globally scoped objects
-        // that depend on it.  So we can delete the "in use" memory.
-        //
-        while (inUseList) {
-            tHeader* next = inUseList->nextPage;
-            inUseList->~tHeader();
-            delete [] reinterpret_cast<char*>(inUseList);
-            inUseList = next;
-        }
+    while (inUseList) {
+        tHeader* next = inUseList->nextPage;
+        inUseList->~tHeader();
+        delete [] reinterpret_cast<char*>(inUseList);
+        inUseList = next;
     }
 
-    //
-    // Always delete the free list memory - it can't be being
-    // (correctly) referenced, whether the pool allocator was
-    // global or not.  We should not check the guard blocks
+    // We should not check the guard blocks
     // here, because we did it already when the block was
     // placed into the free list.
     //
diff --git a/src/compiler/PoolAlloc.h b/src/compiler/PoolAlloc.h
index 645db78..55e09db 100644
--- a/src/compiler/PoolAlloc.h
+++ b/src/compiler/PoolAlloc.h
@@ -115,7 +115,7 @@
 //
 class TPoolAllocator {
 public:
-    TPoolAllocator(bool global = false, int growthIncrement = 8*1024, int allocationAlignment = 16);
+    TPoolAllocator(int growthIncrement = 8*1024, int allocationAlignment = 16);
 
     //
     // Don't call the destructor just to free up the memory, call pop()
@@ -194,7 +194,6 @@
         return TAllocation::offsetAllocation(memory);
     }
 
-    bool global;            // should be true if this object is globally scoped
     size_t pageSize;        // granularity of allocation from the OS
     size_t alignment;       // all returned allocations will be aligned at 
                             // this granularity, which will be a power of 2
@@ -220,18 +219,15 @@
 // different times.  But a simple use is to have a global pop
 // with everyone using the same global allocator.
 //
-typedef TPoolAllocator* PoolAllocatorPointer;
 extern TPoolAllocator& GetGlobalPoolAllocator();
+extern void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator);
 #define GlobalPoolAllocator GetGlobalPoolAllocator()
 
-
 struct TThreadGlobalPools
 {
     TPoolAllocator* globalPoolAllocator;
 };
 
-void SetGlobalPoolAllocatorPtr(TPoolAllocator* poolAllocator);
-
 //
 // This STL compatible allocator is intended to be used as the allocator
 // parameter to templatized STL containers, like vector and map.
diff --git a/src/compiler/ShHandle.h b/src/compiler/ShHandle.h
index 385259e..4e2affe 100644
--- a/src/compiler/ShHandle.h
+++ b/src/compiler/ShHandle.h
@@ -28,9 +28,14 @@
 //
 class TShHandleBase {
 public:
-    TShHandleBase() { }
-    virtual ~TShHandleBase() { }
+    TShHandleBase();
+    virtual ~TShHandleBase();
     virtual TCompiler* getAsCompiler() { return 0; }
+
+protected:
+    // Memory allocator. Allocates and tracks memory required by the compiler.
+    // Deallocates all memory when compiler is destructed.
+    TPoolAllocator allocator;
 };
 
 //
diff --git a/src/compiler/ShaderLang.cpp b/src/compiler/ShaderLang.cpp
index c5eaf30..f4cccc6 100644
--- a/src/compiler/ShaderLang.cpp
+++ b/src/compiler/ShaderLang.cpp
@@ -161,15 +161,7 @@
     if (compiler == 0)
         return 0;
 
-    GlobalPoolAllocator.push();
-
     bool success = compiler->compile(shaderStrings, numStrings, compileOptions);
-
-    //
-    // Throw away all the temporary memory used by the compilation process.
-    //
-    GlobalPoolAllocator.pop();
-
     return success ? 1 : 0;
 }