JSC: FunctionParameters are memory hungry.
<http://webkit.org/b/108033>
<rdar://problem/13094803>

Reviewed by Sam Weinig.

Instead of inheriting from Vector<Identifier>, make FunctionParameters a simple fixed-size array
with a custom-allocating create() function. Removes one step of indirection and cuts memory usage
roughly in half.

2.73 MB progression on Membuster3.

* bytecode/UnlinkedCodeBlock.cpp:
(JSC::UnlinkedFunctionExecutable::paramString):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
* parser/Nodes.cpp:
(JSC::FunctionParameters::create):
(JSC::FunctionParameters::FunctionParameters):
(JSC::FunctionParameters::~FunctionParameters):
* parser/Nodes.h:
(FunctionParameters):
(JSC::FunctionParameters::size):
(JSC::FunctionParameters::at):
(JSC::FunctionParameters::identifiers):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@140947 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 1aba86b..32d9d01 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,5 +1,33 @@
 2013-01-27  Andreas Kling  <akling@apple.com>
 
+        JSC: FunctionParameters are memory hungry.
+        <http://webkit.org/b/108033>
+        <rdar://problem/13094803>
+
+        Reviewed by Sam Weinig.
+
+        Instead of inheriting from Vector<Identifier>, make FunctionParameters a simple fixed-size array
+        with a custom-allocating create() function. Removes one step of indirection and cuts memory usage
+        roughly in half.
+
+        2.73 MB progression on Membuster3.
+
+        * bytecode/UnlinkedCodeBlock.cpp:
+        (JSC::UnlinkedFunctionExecutable::paramString):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::BytecodeGenerator):
+        * parser/Nodes.cpp:
+        (JSC::FunctionParameters::create):
+        (JSC::FunctionParameters::FunctionParameters):
+        (JSC::FunctionParameters::~FunctionParameters):
+        * parser/Nodes.h:
+        (FunctionParameters):
+        (JSC::FunctionParameters::size):
+        (JSC::FunctionParameters::at):
+        (JSC::FunctionParameters::identifiers):
+
+2013-01-27  Andreas Kling  <akling@apple.com>
+
         JSC: SourceProviderCache is memory hungry.
         <http://webkit.org/b/108029>
         <rdar://problem/13094806>
diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
index 5ceaac7..1fea8d1 100644
--- a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
@@ -150,7 +150,7 @@
     for (size_t pos = 0; pos < parameters.size(); ++pos) {
         if (!builder.isEmpty())
             builder.appendLiteral(", ");
-        builder.append(parameters[pos].string());
+        builder.append(parameters.at(pos).string());
     }
     return builder.toString();
 }
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index c387cfe..f57e1bc 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -360,7 +360,7 @@
         capturedArguments.resize(parameters.size());
         for (size_t i = 0; i < parameters.size(); ++i) {
             capturedArguments[i] = 0;
-            if (!functionBody->captures(parameters[i]) && !shouldCaptureAllTheThings)
+            if (!functionBody->captures(parameters.at(i)) && !shouldCaptureAllTheThings)
                 continue;
             capturesAnyArgumentByName = true;
             capturedArguments[i] = addVar();
@@ -461,12 +461,12 @@
     for (size_t i = 0; i < parameters.size(); ++i, --nextParameterIndex) {
         int index = nextParameterIndex;
         if (capturedArguments.size() && capturedArguments[i]) {
-            ASSERT((functionBody->hasCapturedVariables() && functionBody->captures(parameters[i])) || shouldCaptureAllTheThings);
+            ASSERT((functionBody->hasCapturedVariables() && functionBody->captures(parameters.at(i))) || shouldCaptureAllTheThings);
             index = capturedArguments[i]->index();
             RegisterID original(nextParameterIndex);
             emitMove(capturedArguments[i], &original);
         }
-        addParameter(parameters[i], index);
+        addParameter(parameters.at(i), index);
     }
     preserveLastVar();
 
diff --git a/Source/JavaScriptCore/parser/Nodes.cpp b/Source/JavaScriptCore/parser/Nodes.cpp
index 03ee8ee..45bf356 100644
--- a/Source/JavaScriptCore/parser/Nodes.cpp
+++ b/Source/JavaScriptCore/parser/Nodes.cpp
@@ -151,16 +151,29 @@
 
 // ------------------------------ FunctionBodyNode -----------------------------
 
-FunctionParameters::FunctionParameters(ParameterNode* firstParameter)
+PassRefPtr<FunctionParameters> FunctionParameters::create(ParameterNode* firstParameter)
 {
     unsigned parameterCount = 0;
     for (ParameterNode* parameter = firstParameter; parameter; parameter = parameter->nextParam())
         ++parameterCount;
 
-    reserveInitialCapacity(parameterCount);
+    size_t objectSize = sizeof(FunctionParameters) - sizeof(void*) + sizeof(StringImpl*) * parameterCount;
+    void* slot = fastMalloc(objectSize);
+    return adoptRef(new (slot) FunctionParameters(firstParameter, parameterCount));
+}
 
+FunctionParameters::FunctionParameters(ParameterNode* firstParameter, unsigned size)
+    : m_size(size)
+{
+    unsigned i = 0;
     for (ParameterNode* parameter = firstParameter; parameter; parameter = parameter->nextParam())
-        uncheckedAppend(parameter->ident());
+        new (&identifiers()[i++]) Identifier(parameter->ident());
+}
+
+FunctionParameters::~FunctionParameters()
+{
+    for (unsigned i = 0; i < m_size; ++i)
+        identifiers()[i].~Identifier();
 }
 
 inline FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData, const JSTokenLocation& location, bool inStrictContext)
diff --git a/Source/JavaScriptCore/parser/Nodes.h b/Source/JavaScriptCore/parser/Nodes.h
index 16ffd7d..5296e23 100644
--- a/Source/JavaScriptCore/parser/Nodes.h
+++ b/Source/JavaScriptCore/parser/Nodes.h
@@ -1393,13 +1393,23 @@
         virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
     };
 
-    class FunctionParameters : public Vector<Identifier>, public RefCounted<FunctionParameters> {
+    class FunctionParameters : public RefCounted<FunctionParameters> {
         WTF_MAKE_FAST_ALLOCATED;
     public:
-        static PassRefPtr<FunctionParameters> create(ParameterNode* firstParameter) { return adoptRef(new FunctionParameters(firstParameter)); }
+        static PassRefPtr<FunctionParameters> create(ParameterNode*);
+        ~FunctionParameters();
+
+        unsigned size() const { return m_size; }
+        const Identifier& at(unsigned index) const { ASSERT(index < m_size); return identifiers()[index]; }
 
     private:
-        FunctionParameters(ParameterNode*);
+        FunctionParameters(ParameterNode*, unsigned size);
+
+        Identifier* identifiers() { return reinterpret_cast<Identifier*>(&m_storage); }
+        const Identifier* identifiers() const { return reinterpret_cast<const Identifier*>(&m_storage); }
+
+        unsigned m_size;
+        void* m_storage;
     };
 
     enum FunctionNameIsInScopeToggle { FunctionNameIsNotInScope, FunctionNameIsInScope };