@@ -149,6 +149,20 @@ class ProfileEntry
149
149
static int32_t pcToOffset (JSScript* aScript, jsbytecode* aPc);
150
150
151
151
public:
152
+ ProfileEntry () = default ;
153
+ ProfileEntry& operator =(const ProfileEntry& other)
154
+ {
155
+ label_ = other.label ();
156
+ dynamicString_ = other.dynamicString ();
157
+ void * spScript = other.spOrScript ;
158
+ spOrScript = spScript;
159
+ int32_t offset = other.lineOrPcOffset ;
160
+ lineOrPcOffset = offset;
161
+ uint32_t kindAndCategory = other.kindAndCategory_ ;
162
+ kindAndCategory_ = kindAndCategory;
163
+ return *this ;
164
+ }
165
+
152
166
enum class Kind : uint32_t {
153
167
// A normal C++ frame.
154
168
CPP_NORMAL = 0 ,
@@ -311,18 +325,14 @@ class PseudoStack final
311
325
: stackPointer(0 )
312
326
{}
313
327
314
- ~PseudoStack () {
315
- // The label macros keep a reference to the PseudoStack to avoid a TLS
316
- // access. If these are somehow not all cleared we will get a
317
- // use-after-free so better to crash now.
318
- MOZ_RELEASE_ASSERT (stackPointer == 0 );
319
- }
328
+ ~PseudoStack ();
320
329
321
330
void pushCppFrame (const char * label, const char * dynamicString, void * sp, uint32_t line,
322
331
js::ProfileEntry::Kind kind, js::ProfileEntry::Category category) {
323
- if (stackPointer < MaxEntries) {
324
- entries[stackPointer].initCppFrame (label, dynamicString, sp, line, kind, category);
325
- }
332
+ uint32_t oldStackPointer = stackPointer;
333
+
334
+ if (MOZ_LIKELY (entryCapacity > oldStackPointer) || MOZ_LIKELY (ensureCapacitySlow ()))
335
+ entries[oldStackPointer].initCppFrame (label, dynamicString, sp, line, kind, category);
326
336
327
337
// This must happen at the end! The compiler will not reorder this
328
338
// update because stackPointer is Atomic<..., ReleaseAcquire>, so any
@@ -332,15 +342,15 @@ class PseudoStack final
332
342
// more expensive on x86 than the separate operations done here.
333
343
// This thread is the only one that ever changes the value of
334
344
// stackPointer.
335
- uint32_t oldStackPointer = stackPointer;
336
345
stackPointer = oldStackPointer + 1 ;
337
346
}
338
347
339
348
void pushJsFrame (const char * label, const char * dynamicString, JSScript* script,
340
349
jsbytecode* pc) {
341
- if (stackPointer < MaxEntries) {
342
- entries[stackPointer].initJsFrame (label, dynamicString, script, pc);
343
- }
350
+ uint32_t oldStackPointer = stackPointer;
351
+
352
+ if (MOZ_LIKELY (entryCapacity > oldStackPointer) || MOZ_LIKELY (ensureCapacitySlow ()))
353
+ entries[oldStackPointer].initJsFrame (label, dynamicString, script, pc);
344
354
345
355
// This must happen at the end! The compiler will not reorder this
346
356
// update because stackPointer is Atomic<..., ReleaseAcquire>, which
@@ -351,7 +361,6 @@ class PseudoStack final
351
361
// more expensive on x86 than the separate operations done here.
352
362
// This thread is the only one that ever changes the value of
353
363
// stackPointer.
354
- uint32_t oldStackPointer = stackPointer;
355
364
stackPointer = oldStackPointer + 1 ;
356
365
}
357
366
@@ -366,20 +375,33 @@ class PseudoStack final
366
375
stackPointer = oldStackPointer - 1 ;
367
376
}
368
377
369
- uint32_t stackSize () const { return std::min (uint32_t (stackPointer), uint32_t (MaxEntries)); }
378
+ uint32_t stackSize () const { return std::min (uint32_t (stackPointer), stackCapacity ()); }
379
+ uint32_t stackCapacity () const { return entryCapacity; }
370
380
371
381
private:
382
+ // Out of line path for expanding the buffer, since otherwise this would get inlined in every
383
+ // DOM WebIDL call.
384
+ MOZ_COLD MOZ_MUST_USE bool ensureCapacitySlow ();
385
+
372
386
// No copying.
373
387
PseudoStack (const PseudoStack&) = delete ;
374
388
void operator =(const PseudoStack&) = delete ;
375
389
390
+ // No moving either.
391
+ PseudoStack (PseudoStack&&) = delete ;
392
+ void operator =(PseudoStack&&) = delete ;
393
+
394
+ uint32_t entryCapacity = 0 ;
395
+
376
396
public:
377
- static const uint32_t MaxEntries = 1024 ;
378
397
379
- // The stack entries.
380
- js::ProfileEntry entries[MaxEntries];
398
+ // The pointer to the stack entries, this is read from the profiler thread and written from the
399
+ // current thread.
400
+ //
401
+ // This is effectively a unique pointer.
402
+ mozilla::Atomic<js::ProfileEntry*> entries { nullptr };
381
403
382
- // This may exceed MaxEntries , so instead use the stackSize() method to
404
+ // This may exceed the entry capacity , so instead use the stackSize() method to
383
405
// determine the number of valid samples in entries. When this is less
384
406
// than MaxEntries, it refers to the first free entry past the top of the
385
407
// in-use stack (i.e. entries[stackPointer - 1] is the top stack entry).
0 commit comments