Repository: nodejs/node
Pull request: src: use stack allocation in indexOf latin1 path

Replaced malloc / free with MaybeStackBuffer in the Latin1 path of IndexOfString.
For short needles, the allocation stays on the stack, avoiding heap allocation.
This results in a 12-15% improvement for short string searches.

```sh
➜  node git:(mert/buffer-indexof-stack-alloc) ✗ node-benchmark-compare ./result.csv
                                                                                                                                                confidence improvement accuracy (*)    (**)   (***)
buffers/buffer-indexof-number.js n=1000000 value=64                                                                                                      *      1.55 %       ±1.36%  ±1.87%  ±2.57%
buffers/buffer-indexof.js n=50000 type='buffer' encoding='undefined' search='--l'                                                                               0.27 %       ±1.13%  ±1.57%  ±2.17%
buffers/buffer-indexof.js n=50000 type='buffer' encoding='undefined' search='@'                                                                                 1.72 %       ±2.49%  ±3.42%  ±4.68%
buffers/buffer-indexof.js n=50000 type='buffer' encoding='undefined' search='</i> to the Caterpillar'                                                           0.09 %       ±0.31%  ±0.43%  ±0.59%
buffers/buffer-indexof.js n=50000 type='buffer' encoding='undefined' search='aaaaaaaaaaaaaaaaa'                                                                 5.67 %      ±12.05% ±17.30% ±25.40%
buffers/buffer-indexof.js n=50000 type='buffer' encoding='undefined' search='Alice'                                                                            -0.13 %       ±2.35%  ±3.23%  ±4.41%
buffers/buffer-indexof.js n=50000 type='buffer' encoding='undefined' search='found it very'                                                                    -0.01 %       ±0.55%  ±0.76%  ±1.04%
buffers/buffer-indexof.js n=50000 type='buffer' encoding='undefined' search='Gryphon'                                                                          -0.56 %       ±1.41%  ±1.95%  ±2.70%
buffers/buffer-indexof.js n=50000 type='buffer' encoding='undefined' search='neighbouring pool'                                                                10.17 %      ±24.08% ±34.59% ±50.85%
buffers/buffer-indexof.js n=50000 type='buffer' encoding='undefined' search='Ou est ma chatte?'                                                                -0.04 %       ±0.53%  ±0.73%  ±0.99%
buffers/buffer-indexof.js n=50000 type='buffer' encoding='undefined' search='SQ'                                                                         *      1.19 %       ±1.18%  ±1.62%  ±2.24%
buffers/buffer-indexof.js n=50000 type='buffer' encoding='undefined' search='venture to go near the house till she had brought herself down to'                 0.22 %       ±0.72%  ±0.99%  ±1.34%
buffers/buffer-indexof.js n=50000 type='string' encoding='latin1' search='--l'                                                                           *      1.76 %       ±1.42%  ±2.01%  ±2.86%
buffers/buffer-indexof.js n=50000 type='string' encoding='latin1' search='@'                                                                           ***     12.51 %       ±1.72%  ±2.36%  ±3.23%
buffers/buffer-indexof.js n=50000 type='string' encoding='latin1' search='</i> to the Caterpillar'                                                             -0.01 %       ±0.32%  ±0.44%  ±0.60%
buffers/buffer-indexof.js n=50000 type='string' encoding='latin1' search='aaaaaaaaaaaaaaaaa'                                                                   -0.65 %       ±2.15%  ±2.98%  ±4.14%
buffers/buffer-indexof.js n=50000 type='string' encoding='latin1' search='Alice'                                                                       ***     15.69 %       ±2.20%  ±3.02%  ±4.13%
buffers/buffer-indexof.js n=50000 type='string' encoding='latin1' search='found it very'                                                                       -0.02 %       ±0.97%  ±1.39%  ±2.02%
buffers/buffer-indexof.js n=50000 type='string' encoding='latin1' search='Gryphon'                                                                       *      1.90 %       ±1.71%  ±2.35%  ±3.21%
buffers/buffer-indexof.js n=50000 type='string' encoding='latin1' search='neighbouring pool'                                                                   -0.01 %       ±0.58%  ±0.80%  ±1.11%
buffers/buffer-indexof.js n=50000 type='string' encoding='latin1' search='Ou est ma chatte?'                                                                    0.05 %       ±1.34%  ±1.89%  ±2.71%
buffers/buffer-indexof.js n=50000 type='string' encoding='latin1' search='SQ'                                                                            *      1.46 %       ±1.37%  ±1.89%  ±2.57%
buffers/buffer-indexof.js n=50000 type='string' encoding='latin1' search='venture to go near the house till she had brought herself down to'                   -0.06 %       ±0.75%  ±1.07%  ±1.52%
buffers/buffer-indexof.js n=50000 type='string' encoding='ucs2' search='--l'                                                                                   -0.09 %       ±1.19%  ±1.63%  ±2.23%
buffers/buffer-indexof.js n=50000 type='string' encoding='ucs2' search='@'                                                                                      0.28 %       ±1.60%  ±2.23%  ±3.15%
buffers/buffer-indexof.js n=50000 type='string' encoding='ucs2' search='</i> to the Caterpillar'                                                                0.25 %       ±0.33%  ±0.46%  ±0.65%
buffers/buffer-indexof.js n=50000 type='string' encoding='ucs2' search='aaaaaaaaaaaaaaaaa'                                                                      0.57 %       ±2.04%  ±2.83%  ±3.95%
buffers/buffer-indexof.js n=50000 type='string' encoding='ucs2' search='Alice'                                                                                  1.94 %       ±2.44%  ±3.35%  ±4.57%
buffers/buffer-indexof.js n=50000 type='string' encoding='ucs2' search='found it very'                                                                         -0.38 %       ±0.92%  ±1.29%  ±1.84%
buffers/buffer-indexof.js n=50000 type='string' encoding='ucs2' search='Gryphon'                                                                               -0.34 %       ±1.35%  ±1.85%  ±2.53%
buffers/buffer-indexof.js n=50000 type='string' encoding='ucs2' search='neighbouring pool'                                                                      0.08 %       ±0.36%  ±0.50%  ±0.70%
buffers/buffer-indexof.js n=50000 type='string' encoding='ucs2' search='Ou est ma chatte?'                                                                      0.58 %       ±0.79%  ±1.11%  ±1.55%
buffers/buffer-indexof.js n=50000 type='string' encoding='ucs2' search='SQ'                                                                                    -0.16 %       ±1.32%  ±1.83%  ±2.51%
buffers/buffer-indexof.js n=50000 type='string' encoding='ucs2' search='venture to go near the house till she had brought herself down to'                     -0.12 %       ±0.97%  ±1.33%  ±1.83%
buffers/buffer-indexof.js n=50000 type='string' encoding='utf8' search='--l'                                                                                   -0.96 %       ±1.28%  ±1.75%  ±2.39%
buffers/buffer-indexof.js n=50000 type='string' encoding='utf8' search='@'                                                                                     -0.20 %       ±1.83%  ±2.53%  ±3.47%
buffers/buffer-indexof.js n=50000 type='string' encoding='utf8' search='</i> to the Caterpillar'                                                               -0.13 %       ±0.40%  ±0.55%  ±0.76%
buffers/buffer-indexof.js n=50000 type='string' encoding='utf8' search='aaaaaaaaaaaaaaaaa'                                                                     -1.16 %       ±1.51%  ±2.07%  ±2.83%
buffers/buffer-indexof.js n=50000 type='string' encoding='utf8' search='Alice'                                                                                  0.37 %       ±2.71%  ±3.74%  ±5.18%
buffers/buffer-indexof.js n=50000 type='string' encoding='utf8' search='found it very'                                                                         -0.17 %       ±1.09%  ±1.50%  ±2.04%
buffers/buffer-indexof.js n=50000 type='string' encoding='utf8' search='Gryphon'                                                                               -0.22 %       ±1.46%  ±2.01%  ±2.77%
buffers/buffer-indexof.js n=50000 type='string' encoding='utf8' search='neighbouring pool'                                                                     -0.06 %       ±0.37%  ±0.51%  ±0.69%
buffers/buffer-indexof.js n=50000 type='string' encoding='utf8' search='Ou est ma chatte?'                                                                      1.16 %       ±1.86%  ±2.65%  ±3.85%
buffers/buffer-indexof.js n=50000 type='string' encoding='utf8' search='SQ'                                                                                     1.60 %       ±2.32%  ±3.25%  ±4.62%
buffers/buffer-indexof.js n=50000 type='string' encoding='utf8' search='venture to go near the house till she had brought herself down to'                     -0.64 %       ±0.78%  ±1.09%  ±1.53%

Be aware that when doing many comparisons the risk of a false-positive result increases.
In this case, there are 45 comparisons, you can thus expect the following amount of false-positive results:
  2.25 false positives, when considering a   5% risk acceptance (*, **, ***),
  0.45 false positives, when considering a   1% risk acceptance (**, ***),
  0.04 false positives, when considering a 0.1% risk acceptance (***)
➜  node git:(mert/buffer-indexof-stack-alloc) ✗ 
```

Changed files:
filename: benchmark/buffers/buffer-indexof.js
patch: @@ -19,7 +19,7 @@ const searchStrings = [
 
 const bench = common.createBenchmark(main, {
   search: searchStrings,
-  encoding: ['undefined', 'utf8', 'ucs2'],
+  encoding: ['undefined', 'utf8', 'ucs2', 'latin1'],
   type: ['buffer', 'string'],
   n: [5e4],
 }, {

filename: src/node_buffer.cc
patch: @@ -1051,23 +1051,19 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
         offset,
         is_forward);
   } else if (enc == LATIN1) {
-    uint8_t* needle_data = node::UncheckedMalloc<uint8_t>(needle_length);
-    if (needle_data == nullptr) {
-      return args.GetReturnValue().Set(-1);
-    }
+    MaybeStackBuffer<uint8_t> needle_data(needle_length);
     StringBytes::Write(isolate,
-                       reinterpret_cast<char*>(needle_data),
+                       reinterpret_cast<char*>(needle_data.out()),
                        needle_length,
                        needle,
                        enc);
 
     result = nbytes::SearchString(reinterpret_cast<const uint8_t*>(haystack),
                                   haystack_length,
-                                  needle_data,
+                                  needle_data.out(),
                                   needle_length,
                                   offset,
                                   is_forward);
-    free(needle_data);
   }
 
   args.GetReturnValue().Set(