From 40e176056d9640635d3bbc9f4e63b50ccc9057bc Mon Sep 17 00:00:00 2001
From: jgruber <jgruber@chromium.org>
Date: Wed, 7 Dec 2016 05:05:30 -0800
Subject: [PATCH] [regexp] Shrink results array in @@match and @@split

Both @@match and @@split internally use dynamically growing fixed
arrays. Shrink to fit when wrapping these in a JSArray to avoid
excessive memory usage.

BUG=chromium:670205,chromium:670708

Review-Url: https://codereview.chromium.org/2556773002
Cr-Commit-Position: refs/heads/master@{#41550}
---
 src/builtins/builtins-regexp.cc | 36 +++++++++++++++++++++++++--------
 1 file changed, 28 insertions(+), 8 deletions(-)

diff --git a/src/builtins/builtins-regexp.cc b/src/builtins/builtins-regexp.cc
index 86871d24c1..6196f6d93a 100644
--- a/src/builtins/builtins-regexp.cc
+++ b/src/builtins/builtins-regexp.cc
@@ -1386,7 +1386,7 @@ class GrowableFixedArray {
     a->Bind(&grow);
     {
       Node* const new_capacity = NewCapacity(a, capacity);
-      Node* const new_array = GrowFixedArray(capacity, new_capacity, mode);
+      Node* const new_array = ResizeFixedArray(length, new_capacity, mode);
 
       var_capacity_.Bind(new_capacity);
       var_array_.Bind(new_array);
@@ -1407,10 +1407,28 @@ class GrowableFixedArray {
     CodeStubAssembler* a = assembler_;
 
     const ElementsKind kind = FAST_ELEMENTS;
+    const ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS;
 
     Node* const native_context = a->LoadNativeContext(context);
     Node* const array_map = a->LoadJSArrayElementsMap(kind, native_context);
 
+    // Shrink to fit if necessary.
+    {
+      Label next(a);
+
+      Node* const length = var_length_.value();
+      Node* const capacity = var_capacity_.value();
+
+      a->GotoIf(a->WordEqual(length, capacity), &next);
+
+      Node* const array = ResizeFixedArray(length, length, mode);
+      var_array_.Bind(array);
+      var_capacity_.Bind(length);
+      a->Goto(&next);
+
+      a->Bind(&next);
+    }
+
     Node* const result_length = a->SmiTag(length());
     Node* const result = a->AllocateUninitializedJSArrayWithoutElements(
         kind, array_map, result_length, nullptr);
@@ -1454,14 +1472,17 @@ class GrowableFixedArray {
     return new_capacity;
   }
 
-  Node* GrowFixedArray(Node* const current_capacity, Node* const new_capacity,
-                       ParameterMode mode) {
+  // Creates a new array with {new_capacity} and copies the first
+  // {element_count} elements from the current array.
+  Node* ResizeFixedArray(Node* const element_count, Node* const new_capacity,
+                         ParameterMode mode) {
     DCHECK(mode == CodeStubAssembler::INTPTR_PARAMETERS);
 
     CodeStubAssembler* a = assembler_;
 
-    CSA_ASSERT(a, a->IntPtrGreaterThan(current_capacity, a->IntPtrConstant(0)));
-    CSA_ASSERT(a, a->IntPtrGreaterThan(new_capacity, current_capacity));
+    CSA_ASSERT(a, a->IntPtrGreaterThan(element_count, a->IntPtrConstant(0)));
+    CSA_ASSERT(a, a->IntPtrGreaterThan(new_capacity, a->IntPtrConstant(0)));
+    CSA_ASSERT(a, a->IntPtrGreaterThanOrEqual(new_capacity, element_count));
 
     const ElementsKind kind = FAST_ELEMENTS;
     const WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER;
@@ -1471,9 +1492,8 @@ class GrowableFixedArray {
     Node* const from_array = var_array_.value();
     Node* const to_array =
         a->AllocateFixedArray(kind, new_capacity, mode, flags);
-    a->CopyFixedArrayElements(kind, from_array, kind, to_array,
-                              current_capacity, new_capacity, barrier_mode,
-                              mode);
+    a->CopyFixedArrayElements(kind, from_array, kind, to_array, element_count,
+                              new_capacity, barrier_mode, mode);
 
     return to_array;
   }