gnu: kio: Search 'smbd' on $PATH.
[jackhill/guix/guix.git] / gnu / packages / patches / mozjs38-tracelogger.patch
1 Squashed version of several commits to fix the tracelogger.
2
3 Taken from
4 https://github.com/GNOME/jhbuild/blob/master/patches/mozjs38-fix-tracelogger.patch.
5
6 # === Fix the SM38 tracelogger ===
7 # This patch is a squashed version of several patches that were adapted
8 # to fix failing hunks.
9 #
10 # Applied in the following order, they are:
11 # * https://bugzilla.mozilla.org/show_bug.cgi?id=1223767
12 # Assertion failure: i < size_, at js/src/vm/TraceLoggingTypes.h:210
13 # Also fix stop-information to make reduce.py work correctly.
14 # * https://bugzilla.mozilla.org/show_bug.cgi?id=1227914
15 # Limit the memory tracelogger can take.
16 # This causes tracelogger to flush data to the disk regularly and prevents out of
17 # memory issues if a lot of data gets logged.
18 # * https://bugzilla.mozilla.org/show_bug.cgi?id=1155618
19 # Fix tracelogger destructor that touches possibly uninitialised hash table.
20 # * https://bugzilla.mozilla.org/show_bug.cgi?id=1223636
21 # Don't treat extraTextId as containing only extra ids.
22 # This fixes an assertion failure: id == nextTextId at js/src/vm/TraceLoggingGraph.cpp
23 # * https://bugzilla.mozilla.org/show_bug.cgi?id=1227028
24 # Fix when to keep the payload of a TraceLogger event.
25 # This fixes an assertion failure: textId < uint32_t(1 << 31) at js/src/vm/TraceLoggingGraph.h
26 # * https://bugzilla.mozilla.org/show_bug.cgi?id=1266649
27 # Handle failing to add to pointermap gracefully.
28 # * https://bugzilla.mozilla.org/show_bug.cgi?id=1280648
29 # Don't cache based on pointers to movable GC things.
30 # * https://bugzilla.mozilla.org/show_bug.cgi?id=1224123
31 # Fix the use of LastEntryId in tracelogger.h.
32 # * https://bugzilla.mozilla.org/show_bug.cgi?id=1231170
33 # Use size in debugger instead of the current id to track last logged item.
34 # * https://bugzilla.mozilla.org/show_bug.cgi?id=1221844
35 # Move TraceLogger_Invalidation to LOG_ITEM.
36 # Add some debug checks to logTimestamp.
37 # * https://bugzilla.mozilla.org/show_bug.cgi?id=1255766
38 # Also mark resizing of memory.
39 # * https://bugzilla.mozilla.org/show_bug.cgi?id=1259403
40 # Only increase capacity by multiples of 2.
41 # Always make sure there are 3 free slots for events.
42 # ===
43
44 diff --git a/js/src/jit-test/tests/tracelogger/bug1231170.js b/js/src/jit-test/tests/tracelogger/bug1231170.js
45 new file mode 100644
46 index 0000000..023e93e
47 --- /dev/null
48 +++ b/js/src/jit-test/tests/tracelogger/bug1231170.js
49 @@ -0,0 +1,3 @@
50 +var du = new Debugger();
51 +if (typeof du.drainTraceLogger === "function")
52 + du.drainTraceLogger();
53 diff --git a/js/src/jit-test/tests/tracelogger/bug1266649.js b/js/src/jit-test/tests/tracelogger/bug1266649.js
54 new file mode 100644
55 index 0000000..81ae7ad
56 --- /dev/null
57 +++ b/js/src/jit-test/tests/tracelogger/bug1266649.js
58 @@ -0,0 +1,10 @@
59 +
60 +var du = new Debugger();
61 +if (typeof du.setupTraceLogger === "function" &&
62 + typeof oomTest === 'function')
63 +{
64 + du.setupTraceLogger({
65 + Scripts: true
66 + })
67 + oomTest(() => function(){});
68 +}
69 diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp
70 index 93e2fda..09049d6 100644
71 --- a/js/src/jit/Ion.cpp
72 +++ b/js/src/jit/Ion.cpp
73 @@ -1055,6 +1055,8 @@ IonScript::Destroy(FreeOp* fop, IonScript* script)
74
75 script->destroyCaches();
76 script->unlinkFromRuntime(fop);
77 + // Frees the potential event we have set.
78 + script->traceLoggerScriptEvent_ = TraceLoggerEvent();
79 fop->free_(script);
80 }
81
82 diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp
83 index 26262fd..af7f313 100644
84 --- a/js/src/vm/Debugger.cpp
85 +++ b/js/src/vm/Debugger.cpp
86 @@ -369,10 +369,10 @@ Debugger::Debugger(JSContext* cx, NativeObject* dbg)
87 objects(cx),
88 environments(cx),
89 #ifdef NIGHTLY_BUILD
90 - traceLoggerLastDrainedId(0),
91 + traceLoggerLastDrainedSize(0),
92 traceLoggerLastDrainedIteration(0),
93 #endif
94 - traceLoggerScriptedCallsLastDrainedId(0),
95 + traceLoggerScriptedCallsLastDrainedSize(0),
96 traceLoggerScriptedCallsLastDrainedIteration(0)
97 {
98 assertSameCompartment(cx, dbg);
99 @@ -3907,9 +3907,9 @@ Debugger::drainTraceLogger(JSContext* cx, unsigned argc, Value* vp)
100 size_t num;
101 TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
102 bool lostEvents = logger->lostEvents(dbg->traceLoggerLastDrainedIteration,
103 - dbg->traceLoggerLastDrainedId);
104 + dbg->traceLoggerLastDrainedSize);
105 EventEntry* events = logger->getEventsStartingAt(&dbg->traceLoggerLastDrainedIteration,
106 - &dbg->traceLoggerLastDrainedId,
107 + &dbg->traceLoggerLastDrainedSize,
108 &num);
109
110 RootedObject array(cx, NewDenseEmptyArray(cx));
111 @@ -4002,10 +4002,10 @@ Debugger::drainTraceLoggerScriptCalls(JSContext* cx, unsigned argc, Value* vp)
112 size_t num;
113 TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
114 bool lostEvents = logger->lostEvents(dbg->traceLoggerScriptedCallsLastDrainedIteration,
115 - dbg->traceLoggerScriptedCallsLastDrainedId);
116 + dbg->traceLoggerScriptedCallsLastDrainedSize);
117 EventEntry* events = logger->getEventsStartingAt(
118 &dbg->traceLoggerScriptedCallsLastDrainedIteration,
119 - &dbg->traceLoggerScriptedCallsLastDrainedId,
120 + &dbg->traceLoggerScriptedCallsLastDrainedSize,
121 &num);
122
123 RootedObject array(cx, NewDenseEmptyArray(cx));
124 diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h
125 index 8cac36a..c92d685 100644
126 --- a/js/src/vm/Debugger.h
127 +++ b/js/src/vm/Debugger.h
128 @@ -314,10 +314,10 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
129 * lost events.
130 */
131 #ifdef NIGHTLY_BUILD
132 - uint32_t traceLoggerLastDrainedId;
133 + uint32_t traceLoggerLastDrainedSize;
134 uint32_t traceLoggerLastDrainedIteration;
135 #endif
136 - uint32_t traceLoggerScriptedCallsLastDrainedId;
137 + uint32_t traceLoggerScriptedCallsLastDrainedSize;
138 uint32_t traceLoggerScriptedCallsLastDrainedIteration;
139
140 class FrameRange;
141 diff --git a/js/src/vm/TraceLogging.cpp b/js/src/vm/TraceLogging.cpp
142 index 6715b36..9766a6f 100644
143 --- a/js/src/vm/TraceLogging.cpp
144 +++ b/js/src/vm/TraceLogging.cpp
145 @@ -131,7 +131,7 @@ TraceLoggerThread::init()
146 {
147 if (!pointerMap.init())
148 return false;
149 - if (!extraTextId.init())
150 + if (!textIdPayloads.init())
151 return false;
152 if (!events.init())
153 return false;
154 @@ -185,10 +185,10 @@ TraceLoggerThread::~TraceLoggerThread()
155 graph = nullptr;
156 }
157
158 - for (TextIdHashMap::Range r = extraTextId.all(); !r.empty(); r.popFront())
159 - js_delete(r.front().value());
160 - extraTextId.finish();
161 - pointerMap.finish();
162 + if (textIdPayloads.initialized()) {
163 + for (TextIdHashMap::Range r = textIdPayloads.all(); !r.empty(); r.popFront())
164 + js_delete(r.front().value());
165 + }
166 }
167
168 bool
169 @@ -287,7 +287,7 @@ TraceLoggerThread::eventText(uint32_t id)
170 if (id < TraceLogger_Last)
171 return TLTextIdString(static_cast<TraceLoggerTextId>(id));
172
173 - TextIdHashMap::Ptr p = extraTextId.lookup(id);
174 + TextIdHashMap::Ptr p = textIdPayloads.lookup(id);
175 MOZ_ASSERT(p);
176
177 return p->value()->string();
178 @@ -341,13 +341,15 @@ TraceLoggerThread::extractScriptDetails(uint32_t textId, const char** filename,
179 TraceLoggerEventPayload*
180 TraceLoggerThread::getOrCreateEventPayload(TraceLoggerTextId textId)
181 {
182 - TextIdHashMap::AddPtr p = extraTextId.lookupForAdd(textId);
183 - if (p)
184 + TextIdHashMap::AddPtr p = textIdPayloads.lookupForAdd(textId);
185 + if (p) {
186 + MOZ_ASSERT(p->value()->textId() == textId); // Sanity check.
187 return p->value();
188 + }
189
190 TraceLoggerEventPayload* payload = js_new<TraceLoggerEventPayload>(textId, (char*)nullptr);
191
192 - if (!extraTextId.add(p, textId, payload))
193 + if (!textIdPayloads.add(p, textId, payload))
194 return nullptr;
195
196 return payload;
197 @@ -357,8 +359,10 @@ TraceLoggerEventPayload*
198 TraceLoggerThread::getOrCreateEventPayload(const char* text)
199 {
200 PointerHashMap::AddPtr p = pointerMap.lookupForAdd((const void*)text);
201 - if (p)
202 + if (p) {
203 + MOZ_ASSERT(p->value()->textId() < nextTextId); // Sanity check.
204 return p->value();
205 + }
206
207 size_t len = strlen(text);
208 char* str = js_pod_malloc<char>(len + 1);
209 @@ -369,7 +373,7 @@ TraceLoggerThread::getOrCreateEventPayload(const char* text)
210 MOZ_ASSERT(ret == len);
211 MOZ_ASSERT(strlen(str) == len);
212
213 - uint32_t textId = extraTextId.count() + TraceLogger_Last;
214 + uint32_t textId = nextTextId;
215
216 TraceLoggerEventPayload* payload = js_new<TraceLoggerEventPayload>(textId, str);
217 if (!payload) {
218 @@ -377,17 +381,19 @@ TraceLoggerThread::getOrCreateEventPayload(const char* text)
219 return nullptr;
220 }
221
222 - if (!extraTextId.putNew(textId, payload)) {
223 + if (!textIdPayloads.putNew(textId, payload)) {
224 js_delete(payload);
225 return nullptr;
226 }
227
228 - if (!pointerMap.add(p, text, payload))
229 - return nullptr;
230 -
231 if (graph.get())
232 graph->addTextId(textId, str);
233
234 + nextTextId++;
235 +
236 + if (!pointerMap.add(p, text, payload))
237 + return nullptr;
238 +
239 return payload;
240 }
241
242 @@ -407,9 +413,14 @@ TraceLoggerThread::getOrCreateEventPayload(TraceLoggerTextId type, const char* f
243 if (!traceLoggerState->isTextIdEnabled(type))
244 return getOrCreateEventPayload(type);
245
246 - PointerHashMap::AddPtr p = pointerMap.lookupForAdd(ptr);
247 - if (p)
248 - return p->value();
249 + PointerHashMap::AddPtr p;
250 + if (ptr) {
251 + p = pointerMap.lookupForAdd(ptr);
252 + if (p) {
253 + MOZ_ASSERT(p->value()->textId() < nextTextId); // Sanity check.
254 + return p->value();
255 + }
256 + }
257
258 // Compute the length of the string to create.
259 size_t lenFilename = strlen(filename);
260 @@ -428,24 +439,28 @@ TraceLoggerThread::getOrCreateEventPayload(TraceLoggerTextId type, const char* f
261 MOZ_ASSERT(ret == len);
262 MOZ_ASSERT(strlen(str) == len);
263
264 - uint32_t textId = extraTextId.count() + TraceLogger_Last;
265 + uint32_t textId = nextTextId;
266 TraceLoggerEventPayload* payload = js_new<TraceLoggerEventPayload>(textId, str);
267 if (!payload) {
268 js_free(str);
269 return nullptr;
270 }
271
272 - if (!extraTextId.putNew(textId, payload)) {
273 + if (!textIdPayloads.putNew(textId, payload)) {
274 js_delete(payload);
275 return nullptr;
276 }
277
278 - if (!pointerMap.add(p, ptr, payload))
279 - return nullptr;
280 -
281 if (graph.get())
282 graph->addTextId(textId, str);
283
284 + nextTextId++;
285 +
286 + if (ptr) {
287 + if (!pointerMap.add(p, ptr, payload))
288 + return nullptr;
289 + }
290 +
291 return payload;
292 }
293
294 @@ -453,14 +468,14 @@ TraceLoggerEventPayload*
295 TraceLoggerThread::getOrCreateEventPayload(TraceLoggerTextId type, JSScript* script)
296 {
297 return getOrCreateEventPayload(type, script->filename(), script->lineno(), script->column(),
298 - script);
299 + nullptr);
300 }
301
302 TraceLoggerEventPayload*
303 TraceLoggerThread::getOrCreateEventPayload(TraceLoggerTextId type,
304 const JS::ReadOnlyCompileOptions& script)
305 {
306 - return getOrCreateEventPayload(type, script.filename(), script.lineno, script.column, &script);
307 + return getOrCreateEventPayload(type, script.filename(), script.lineno, script.column, nullptr);
308 }
309
310 void
311 @@ -485,7 +500,7 @@ TraceLoggerThread::startEvent(uint32_t id)
312 if (!traceLoggerState->isTextIdEnabled(id))
313 return;
314
315 - logTimestamp(id);
316 + log(id);
317 }
318
319 void
320 @@ -510,7 +525,7 @@ TraceLoggerThread::stopEvent(uint32_t id)
321 if (!traceLoggerState->isTextIdEnabled(id))
322 return;
323
324 - logTimestamp(TraceLogger_Stop);
325 + log(TraceLogger_Stop);
326 }
327
328 void
329 @@ -522,23 +537,57 @@ TraceLoggerThread::logTimestamp(TraceLoggerTextId id)
330 void
331 TraceLoggerThread::logTimestamp(uint32_t id)
332 {
333 + MOZ_ASSERT(id > TraceLogger_LastTreeItem && id < TraceLogger_Last);
334 + log(id);
335 +}
336 +
337 +void
338 +TraceLoggerThread::log(uint32_t id)
339 +{
340 if (enabled == 0)
341 return;
342
343 MOZ_ASSERT(traceLoggerState);
344 - if (!events.ensureSpaceBeforeAdd()) {
345 +
346 + // We request for 3 items to add, since if we don't have enough room
347 + // we record the time it took to make more place. To log this information
348 + // we need 2 extra free entries.
349 + if (!events.hasSpaceForAdd(3)) {
350 uint64_t start = rdtsc() - traceLoggerState->startupTime;
351
352 - if (graph.get())
353 - graph->log(events);
354 + if (!events.ensureSpaceBeforeAdd(3)) {
355 + if (graph.get())
356 + graph->log(events);
357 +
358 + iteration_++;
359 + events.clear();
360 +
361 + // Remove the item in the pointerMap for which the payloads
362 + // have no uses anymore
363 + for (PointerHashMap::Enum e(pointerMap); !e.empty(); e.popFront()) {
364 + if (e.front().value()->uses() != 0)
365 + continue;
366 +
367 + TextIdHashMap::Ptr p = textIdPayloads.lookup(e.front().value()->textId());
368 + MOZ_ASSERT(p);
369 + textIdPayloads.remove(p);
370 +
371 + e.removeFront();
372 + }
373
374 - iteration_++;
375 - events.clear();
376 + // Free all payloads that have no uses anymore.
377 + for (TextIdHashMap::Enum e(textIdPayloads); !e.empty(); e.popFront()) {
378 + if (e.front().value()->uses() == 0) {
379 + js_delete(e.front().value());
380 + e.removeFront();
381 + }
382 + }
383 + }
384
385 // Log the time it took to flush the events as being from the
386 // Tracelogger.
387 if (graph.get()) {
388 - MOZ_ASSERT(events.capacity() > 2);
389 + MOZ_ASSERT(events.hasSpaceForAdd(2));
390 EventEntry& entryStart = events.pushUninitialized();
391 entryStart.time = start;
392 entryStart.textId = TraceLogger_Internal;
393 @@ -548,13 +597,6 @@ TraceLoggerThread::logTimestamp(uint32_t id)
394 entryStop.textId = TraceLogger_Stop;
395 }
396
397 - // Free all TextEvents that have no uses anymore.
398 - for (TextIdHashMap::Enum e(extraTextId); !e.empty(); e.popFront()) {
399 - if (e.front().value()->uses() == 0) {
400 - js_delete(e.front().value());
401 - e.removeFront();
402 - }
403 - }
404 }
405
406 uint64_t time = rdtsc() - traceLoggerState->startupTime;
407 @@ -956,3 +998,16 @@ TraceLoggerEvent::~TraceLoggerEvent()
408 if (payload_)
409 payload_->release();
410 }
411 +
412 +TraceLoggerEvent&
413 +TraceLoggerEvent::operator=(const TraceLoggerEvent& other)
414 +{
415 + if (hasPayload())
416 + payload()->release();
417 + if (other.hasPayload())
418 + other.payload()->use();
419 +
420 + payload_ = other.payload_;
421 +
422 + return *this;
423 +}
424 diff --git a/js/src/vm/TraceLogging.h b/js/src/vm/TraceLogging.h
425 index a124dcb..91a1eb0 100644
426 --- a/js/src/vm/TraceLogging.h
427 +++ b/js/src/vm/TraceLogging.h
428 @@ -110,6 +110,9 @@ class TraceLoggerEvent {
429 bool hasPayload() const {
430 return !!payload_;
431 }
432 +
433 + TraceLoggerEvent& operator=(const TraceLoggerEvent& other);
434 + TraceLoggerEvent(const TraceLoggerEvent& event) = delete;
435 };
436
437 /**
438 @@ -130,6 +133,10 @@ class TraceLoggerEventPayload {
439 uses_(0)
440 { }
441
442 + ~TraceLoggerEventPayload() {
443 + MOZ_ASSERT(uses_ == 0);
444 + }
445 +
446 uint32_t textId() {
447 return textId_;
448 }
449 @@ -166,7 +173,8 @@ class TraceLoggerThread
450 mozilla::UniquePtr<TraceLoggerGraph> graph;
451
452 PointerHashMap pointerMap;
453 - TextIdHashMap extraTextId;
454 + TextIdHashMap textIdPayloads;
455 + uint32_t nextTextId;
456
457 ContinuousSpace<EventEntry> events;
458
459 @@ -181,6 +189,7 @@ class TraceLoggerThread
460 : enabled(0),
461 failed(false),
462 graph(),
463 + nextTextId(TraceLogger_Last),
464 iteration_(0),
465 top(nullptr)
466 { }
467 @@ -195,22 +204,22 @@ class TraceLoggerThread
468 bool enable(JSContext* cx);
469 bool disable();
470
471 - // Given the previous iteration and lastEntryId, return an array of events
472 + // Given the previous iteration and size, return an array of events
473 // (there could be lost events). At the same time update the iteration and
474 - // lastEntry and gives back how many events there are.
475 - EventEntry* getEventsStartingAt(uint32_t* lastIteration, uint32_t* lastEntryId, size_t* num) {
476 + // size and gives back how many events there are.
477 + EventEntry* getEventsStartingAt(uint32_t* lastIteration, uint32_t* lastSize, size_t* num) {
478 EventEntry* start;
479 if (iteration_ == *lastIteration) {
480 - MOZ_ASSERT(events.lastEntryId() >= *lastEntryId);
481 - *num = events.lastEntryId() - *lastEntryId;
482 - start = events.data() + *lastEntryId + 1;
483 + MOZ_ASSERT(*lastSize <= events.size());
484 + *num = events.size() - *lastSize;
485 + start = events.data() + *lastSize;
486 } else {
487 - *num = events.lastEntryId() + 1;
488 + *num = events.size();
489 start = events.data();
490 }
491
492 *lastIteration = iteration_;
493 - *lastEntryId = events.lastEntryId();
494 + *lastSize = events.size();
495 return start;
496 }
497
498 @@ -220,16 +229,16 @@ class TraceLoggerThread
499 const char** lineno, size_t* lineno_len, const char** colno,
500 size_t* colno_len);
501
502 - bool lostEvents(uint32_t lastIteration, uint32_t lastEntryId) {
503 + bool lostEvents(uint32_t lastIteration, uint32_t lastSize) {
504 // If still logging in the same iteration, there are no lost events.
505 if (lastIteration == iteration_) {
506 - MOZ_ASSERT(lastEntryId <= events.lastEntryId());
507 + MOZ_ASSERT(lastSize <= events.size());
508 return false;
509 }
510
511 - // When proceeded to the next iteration and lastEntryId points to
512 - // the maximum capacity there are no logs that are lost.
513 - if (lastIteration + 1 == iteration_ && lastEntryId == events.capacity())
514 + // If we are in a consecutive iteration we are only sure we didn't lose any events,
515 + // when the lastSize equals the maximum size 'events' can get.
516 + if (lastIteration == iteration_ - 1 && lastSize == events.maxSize())
517 return false;
518
519 return true;
520 @@ -268,6 +277,7 @@ class TraceLoggerThread
521 void stopEvent(uint32_t id);
522 private:
523 void stopEvent();
524 + void log(uint32_t id);
525
526 public:
527 static unsigned offsetOfEnabled() {
528 diff --git a/js/src/vm/TraceLoggingGraph.cpp b/js/src/vm/TraceLoggingGraph.cpp
529 index d1b7f2e..a4eb273 100644
530 --- a/js/src/vm/TraceLoggingGraph.cpp
531 +++ b/js/src/vm/TraceLoggingGraph.cpp
532 @@ -276,7 +276,7 @@ TraceLoggerGraph::flush()
533 if (bytesWritten < tree.size())
534 return false;
535
536 - treeOffset += tree.lastEntryId();
537 + treeOffset += tree.size();
538 tree.clear();
539 }
540
541 @@ -359,7 +359,7 @@ TraceLoggerGraph::startEventInternal(uint32_t id, uint64_t timestamp)
542
543 if (parent.lastChildId() == 0) {
544 MOZ_ASSERT(!entry.hasChildren());
545 - MOZ_ASSERT(parent.treeId() == tree.lastEntryId() + treeOffset);
546 + MOZ_ASSERT(parent.treeId() == treeOffset + tree.size() - 1);
547
548 if (!updateHasChildren(parent.treeId()))
549 return false;
550 diff --git a/js/src/vm/TraceLoggingTypes.h b/js/src/vm/TraceLoggingTypes.h
551 index f1c9d0c..10b76d6 100644
552 --- a/js/src/vm/TraceLoggingTypes.h
553 +++ b/js/src/vm/TraceLoggingTypes.h
554 @@ -21,7 +21,6 @@
555 _(Internal) \
556 _(Interpreter) \
557 _(InlinedScripts) \
558 - _(Invalidation) \
559 _(IonCompilation) \
560 _(IonCompilationPaused) \
561 _(IonLinking) \
562 @@ -60,6 +59,7 @@
563
564 #define TRACELOGGER_LOG_ITEMS(_) \
565 _(Bailout) \
566 + _(Invalidation) \
567 _(Disable) \
568 _(Enable) \
569 _(Stop)
570 @@ -130,6 +130,9 @@ class ContinuousSpace {
571 uint32_t size_;
572 uint32_t capacity_;
573
574 + // The maximum amount of ram memory a continuous space structure can take (in bytes).
575 + static const uint32_t LIMIT = 200 * 1024 * 1024;
576 +
577 public:
578 ContinuousSpace ()
579 : data_(nullptr)
580 @@ -151,6 +154,10 @@ class ContinuousSpace {
581 data_ = nullptr;
582 }
583
584 + static uint32_t maxSize() {
585 + return LIMIT / sizeof(T);
586 + }
587 +
588 T* data() {
589 return data_;
590 }
591 @@ -187,11 +194,14 @@ class ContinuousSpace {
592 if (hasSpaceForAdd(count))
593 return true;
594
595 + // Limit the size of a continuous buffer.
596 + if (size_ + count > maxSize())
597 + return false;
598 +
599 uint32_t nCapacity = capacity_ * 2;
600 - if (size_ + count > nCapacity)
601 - nCapacity = size_ + count;
602 - T* entries = (T*) js_realloc(data_, nCapacity * sizeof(T));
603 + nCapacity = (nCapacity < maxSize()) ? nCapacity : maxSize();
604
605 + T* entries = (T*) js_realloc(data_, nCapacity * sizeof(T));
606 if (!entries)
607 return false;
608