From ed862de58f2729a467363d74f17557cd1c5b4443 Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Thu, 30 Jan 2025 11:51:25 -0500 Subject: [PATCH 1/2] In the assembly view state, refer to the current symbol by index. --- src/actions/profile-view.ts | 25 ++++++++++++++++++------- src/app-logic/url-handling.ts | 13 +++++++------ src/reducers/url-state.ts | 13 +++++++------ src/selectors/url-state.ts | 8 +++++++- src/types/actions.ts | 4 ++-- src/types/state.ts | 16 +++++++--------- 6 files changed, 48 insertions(+), 31 deletions(-) diff --git a/src/actions/profile-view.ts b/src/actions/profile-view.ts index 47c50d4017..0351e78def 100644 --- a/src/actions/profile-view.ts +++ b/src/actions/profile-view.ts @@ -1920,19 +1920,30 @@ export function updateBottomBoxContentsAndMaybeOpen( currentTab: TabSlug, { libIndex, sourceIndex, nativeSymbols, lineNumber }: BottomBoxInfo ): Action { - // TODO: If the set has more than one element, pick the native symbol with - // the highest total sample count - const nativeSymbol = nativeSymbols.length !== 0 ? nativeSymbols[0] : null; + const haveSource = sourceIndex !== null; + const haveAssembly = nativeSymbols.length !== 0; + + const shouldOpenBottomBox = haveSource || haveAssembly; + + // By default, only open the source view and keep the assembly + // view closed - unless the only thing we have is assembly. + const shouldOpenAssemblyView = !haveSource && haveAssembly; + + // If we have at least one native symbol to show assembly for, pick + // the first one arbitrarily. + // TODO: If the we have more than one native symbol, pick the one + // with the highest total sample count. + const currentNativeSymbol = nativeSymbols.length !== 0 ? 0 : null; return { type: 'UPDATE_BOTTOM_BOX', libIndex, sourceIndex, - nativeSymbol, - allNativeSymbolsForInitiatingCallNode: nativeSymbols, + nativeSymbols, + currentNativeSymbol, currentTab, - shouldOpenBottomBox: sourceIndex !== null || nativeSymbol !== null, - shouldOpenAssemblyView: sourceIndex === null && nativeSymbol !== null, + shouldOpenBottomBox, + shouldOpenAssemblyView, lineNumber, }; } diff --git a/src/app-logic/url-handling.ts b/src/app-logic/url-handling.ts index de0818abe4..0976efba13 100644 --- a/src/app-logic/url-handling.ts +++ b/src/app-logic/url-handling.ts @@ -353,9 +353,10 @@ export function getQueryStringFromUrlState(urlState: UrlState): string { if (sourceView.sourceIndex !== null) { query.sourceViewIndex = sourceView.sourceIndex; } - if (assemblyView.isOpen && assemblyView.nativeSymbol !== null) { + if (assemblyView.isOpen && assemblyView.currentNativeSymbol !== null) { + const { currentNativeSymbol, nativeSymbols } = assemblyView; query.assemblyView = stringifyAssemblyViewSymbol( - assemblyView.nativeSymbol + nativeSymbols[currentNativeSymbol] ); } } @@ -514,8 +515,8 @@ export function stateFromLocation( const assemblyView: AssemblyViewState = { isOpen: false, scrollGeneration: 0, - nativeSymbol: null, - allNativeSymbolsForInitiatingCallNode: [], + nativeSymbols: [], + currentNativeSymbol: null, }; const isBottomBoxOpenPerPanel: any = {}; tabSlugs.forEach((tabSlug) => (isBottomBoxOpenPerPanel[tabSlug] = false)); @@ -526,8 +527,8 @@ export function stateFromLocation( if (query.assemblyView) { const symbol = parseAssemblyViewSymbol(query.assemblyView); if (symbol !== null) { - assemblyView.nativeSymbol = symbol; - assemblyView.allNativeSymbolsForInitiatingCallNode = [symbol]; + assemblyView.nativeSymbols = [symbol]; + assemblyView.currentNativeSymbol = 0; assemblyView.isOpen = true; isBottomBoxOpenPerPanel[selectedTab] = true; } diff --git a/src/reducers/url-state.ts b/src/reducers/url-state.ts index bebe69468d..8823e926ce 100644 --- a/src/reducers/url-state.ts +++ b/src/reducers/url-state.ts @@ -585,20 +585,21 @@ const sourceView: Reducer = ( const assemblyView: Reducer = ( state = { scrollGeneration: 0, - nativeSymbol: null, - allNativeSymbolsForInitiatingCallNode: [], + nativeSymbols: [], + currentNativeSymbol: null, isOpen: false, }, action ) => { switch (action.type) { case 'UPDATE_BOTTOM_BOX': { + const { nativeSymbols, currentNativeSymbol, shouldOpenAssemblyView } = + action; return { scrollGeneration: state.scrollGeneration + 1, - nativeSymbol: action.nativeSymbol, - allNativeSymbolsForInitiatingCallNode: - action.allNativeSymbolsForInitiatingCallNode, - isOpen: state.isOpen || action.shouldOpenAssemblyView, + nativeSymbols, + currentNativeSymbol, + isOpen: state.isOpen || shouldOpenAssemblyView, }; } case 'OPEN_ASSEMBLY_VIEW': { diff --git a/src/selectors/url-state.ts b/src/selectors/url-state.ts index 48b7e17146..2587b5462c 100644 --- a/src/selectors/url-state.ts +++ b/src/selectors/url-state.ts @@ -81,7 +81,13 @@ export const getAssemblyViewIsOpen: Selector = (state) => getProfileSpecificState(state).assemblyView.isOpen; export const getAssemblyViewNativeSymbol: Selector = ( state -) => getProfileSpecificState(state).assemblyView.nativeSymbol; +) => { + const { nativeSymbols, currentNativeSymbol } = + getProfileSpecificState(state).assemblyView; + return currentNativeSymbol !== null + ? nativeSymbols[currentNativeSymbol] + : null; +}; export const getAssemblyViewScrollGeneration: Selector = (state) => getProfileSpecificState(state).assemblyView.scrollGeneration; export const getShowJsTracerSummary: Selector = (state) => diff --git a/src/types/actions.ts b/src/types/actions.ts index 940b018500..3804235664 100644 --- a/src/types/actions.ts +++ b/src/types/actions.ts @@ -338,8 +338,8 @@ type ProfileAction = readonly type: 'UPDATE_BOTTOM_BOX'; readonly libIndex: IndexIntoLibs | null; readonly sourceIndex: IndexIntoSourceTable | null; - readonly nativeSymbol: NativeSymbolInfo | null; - readonly allNativeSymbolsForInitiatingCallNode: NativeSymbolInfo[]; + readonly nativeSymbols: NativeSymbolInfo[]; + readonly currentNativeSymbol: number | null; readonly currentTab: TabSlug; readonly shouldOpenBottomBox: boolean; readonly shouldOpenAssemblyView: boolean; diff --git a/src/types/state.ts b/src/types/state.ts index aa6956090a..0989fd0472 100644 --- a/src/types/state.ts +++ b/src/types/state.ts @@ -262,15 +262,13 @@ export type AssemblyViewState = { isOpen: boolean; // When this is incremented, the assembly view scrolls to the "hotspot" line. scrollGeneration: number; - // The native symbol for which the assembly code is being shown at the moment. - // Null if the initiating call node did not have a native symbol. - nativeSymbol: NativeSymbolInfo | null; - // The set of native symbols which contributed samples to the initiating call - // node. Often, this will just be one element (the same as `nativeSymbol`), - // but it can also be multiple elements, for example when double-clicking a - // function like `Vec::push` in an inverted call tree, if that function has - // been inlined into multiple different callers. - allNativeSymbolsForInitiatingCallNode: NativeSymbolInfo[]; + // The list of native symbols whose assembly code should be accessible in the + // assembly view. Often empty or just one element, but sometimes this can have + // multiple elements, for example the different JIT compilations of one JS function. + nativeSymbols: NativeSymbolInfo[]; + // The index in `nativeSymbols` for the symbol whose assembly code is being shown at the moment. + // Null if nativeSymbols is empty. + currentNativeSymbol: number | null; }; export type DecodedInstruction = { From 1bc11770bf18f14dd7f57823003907f8870cec2f Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Mon, 19 Jan 2026 13:29:48 -0500 Subject: [PATCH 2/2] Fix typo in comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nazım Can Altınova --- src/actions/profile-view.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/actions/profile-view.ts b/src/actions/profile-view.ts index 0351e78def..0885bcc50f 100644 --- a/src/actions/profile-view.ts +++ b/src/actions/profile-view.ts @@ -1931,7 +1931,7 @@ export function updateBottomBoxContentsAndMaybeOpen( // If we have at least one native symbol to show assembly for, pick // the first one arbitrarily. - // TODO: If the we have more than one native symbol, pick the one + // TODO: If we have more than one native symbol, pick the one // with the highest total sample count. const currentNativeSymbol = nativeSymbols.length !== 0 ? 0 : null;