diff --git a/packages/core/src/render3/debug/chrome_dev_tools_performance.ts b/packages/core/src/render3/debug/chrome_dev_tools_performance.ts index d9312981ea0..7b72292a1bc 100644 --- a/packages/core/src/render3/debug/chrome_dev_tools_performance.ts +++ b/packages/core/src/render3/debug/chrome_dev_tools_performance.ts @@ -71,14 +71,14 @@ function measureEnd( entryName: string, color: DevToolsColor, ) { - const top = eventsStack.pop(); + let top: stackEntry | undefined; - assertDefined(top, 'Profiling error: could not find start event entry ' + startEvent); - assertEqual( - top[0], - startEvent, - `Profiling error: expected to see ${startEvent} event but got ${top[0]}`, - ); + // The stack may be asymmetric when an end event for a prior start event is missing (e.g. when an exception + // has occurred), unroll the stack until a matching item has been found in that case. + do { + top = eventsStack.pop(); + assertDefined(top, 'Profiling error: could not find start event entry ' + startEvent); + } while (top[0] !== startEvent); console.timeStamp( entryName, diff --git a/packages/core/test/acceptance/chrome_dev_tools_performance_spec.ts b/packages/core/test/acceptance/chrome_dev_tools_performance_spec.ts index d6b2c2c102b..df500959a72 100644 --- a/packages/core/test/acceptance/chrome_dev_tools_performance_spec.ts +++ b/packages/core/test/acceptance/chrome_dev_tools_performance_spec.ts @@ -6,8 +6,10 @@ * found in the LICENSE file at https://angular.dev/license */ -import {enableProfiling} from '../../src/render3/debug/chrome_dev_tools_performance'; import {Component, HostAttributeToken, inject, Inject} from '../../src/core'; +import {enableProfiling} from '../../src/render3/debug/chrome_dev_tools_performance'; +import {profiler} from '../../src/render3/profiler'; +import {ProfilerEvent} from '../../src/render3/profiler_types'; import {TestBed} from '../../testing'; describe('Chrome DevTools Performance integration', () => { @@ -59,5 +61,26 @@ describe('Chrome DevTools Performance integration', () => { stopProfiling(); } }); + + it('should not crash when asymmetric events are processed', () => { + const timeStampSpy = spyOn(console, 'timeStamp'); + const stopProfiling = enableProfiling(); + + try { + profiler(ProfilerEvent.ChangeDetectionSyncStart); + profiler(ProfilerEvent.ChangeDetectionStart); + profiler(ProfilerEvent.ChangeDetectionSyncEnd); + + const calls = timeStampSpy.calls.all(); + expect(calls.length).toBe(3); + + const [syncStart, cdStart, syncEnd] = calls; + expect(syncStart.args[0]).toMatch(/^Event_/); + expect(cdStart.args[0]).toMatch(/^Event_/); + expect(syncEnd.args[0]).toMatch(/^Synchronization /); + } finally { + stopProfiling(); + } + }); }); });