@@ -124,70 +124,77 @@ class BindingData : public BaseObject {
124124
125125// helper class for the Parser
126126struct StringPtr {
127- StringPtr () {
128- on_heap_ = false ;
129- Reset ();
130- }
131-
127+ // Memory impact: ~8KB per parser (66 StringPtr × 128 bytes).
128+ static constexpr size_t kSlabSize = 128 ;
132129
133- ~StringPtr () {
134- Reset ();
135- }
130+ StringPtr () = default ;
131+ ~StringPtr () { Reset (); }
136132
133+ StringPtr (const StringPtr&) = delete ;
134+ StringPtr& operator =(const StringPtr&) = delete ;
137135
138136 // If str_ does not point to a heap string yet, this function makes it do
139137 // so. This is called at the end of each http_parser_execute() so as not
140138 // to leak references. See issue #2438 and test-http-parser-bad-ref.js.
141139 void Save () {
142- if (!on_heap_ && size_ > 0 ) {
143- char * s = new char [size_];
144- memcpy (s, str_, size_);
145- str_ = s;
146- on_heap_ = true ;
140+ if (!on_heap_ && !using_slab_ && size_ > 0 ) {
141+ if (size_ <= kSlabSize ) {
142+ memcpy (slab_, str_, size_);
143+ str_ = slab_;
144+ using_slab_ = true ;
145+ } else {
146+ char * s = new char [size_];
147+ memcpy (s, str_, size_);
148+ str_ = s;
149+ on_heap_ = true ;
150+ }
147151 }
148152 }
149153
150-
151154 void Reset () {
152155 if (on_heap_) {
153156 delete[] str_;
154157 on_heap_ = false ;
155158 }
156-
159+ using_slab_ = false ;
157160 str_ = nullptr ;
158161 size_ = 0 ;
159162 }
160163
161-
162164 void Update (const char * str, size_t size) {
163165 if (str_ == nullptr ) {
164166 str_ = str;
165- } else if (on_heap_ || str_ + size_ != str) {
166- // Non-consecutive input, make a copy on the heap.
167- // TODO(bnoordhuis) Use slab allocation, O(n) allocs is bad.
168- char * s = new char [size_ + size];
169- memcpy (s, str_, size_);
170- memcpy (s + size_, str, size);
171-
172- if (on_heap_)
173- delete[] str_;
174- else
167+ } else if (on_heap_ || using_slab_ || str_ + size_ != str) {
168+ const size_t total = size_ + size;
169+
170+ if (!on_heap_ && total <= kSlabSize ) {
171+ if (!using_slab_) {
172+ memcpy (slab_, str_, size_);
173+ using_slab_ = true ;
174+ }
175+ memcpy (slab_ + size_, str, size);
176+ str_ = slab_;
177+ } else {
178+ char * s = new char [total];
179+ memcpy (s, str_, size_);
180+ memcpy (s + size_, str, size);
181+ if (on_heap_)
182+ delete[] str_;
175183 on_heap_ = true ;
176-
177- str_ = s;
184+ using_slab_ = false ;
185+ str_ = s;
186+ }
178187 }
179188 size_ += size;
180189 }
181190
182-
183191 Local<String> ToString (Environment* env) const {
184192 if (size_ != 0 )
185193 return OneByteString (env->isolate (), str_, size_);
186194 else
187195 return String::Empty (env->isolate ());
188196 }
189197
190-
191198 // Strip trailing OWS (SPC or HTAB) from string.
192199 Local<String> ToTrimmedString (Environment* env) {
193200 while (size_ > 0 && IsOWS (str_[size_ - 1 ])) {
@@ -196,10 +203,11 @@ struct StringPtr {
196203 return ToString (env);
197204 }
198205
199-
200- const char * str_;
201- bool on_heap_;
202- size_t size_;
206+ const char * str_ = nullptr ;
207+ bool on_heap_ = false ;
208+ bool using_slab_ = false ;
209+ size_t size_ = 0 ;
210+ char slab_[kSlabSize ];
203211};
204212
205213class Parser ;
0 commit comments