From 2cc96ff86cf106952f981bc674c63c3b9c2bd018 Mon Sep 17 00:00:00 2001 From: Boris Buegling Date: Mon, 20 Oct 2025 13:49:58 -0700 Subject: [PATCH] Reduce traffic through `macroConfigPaths` lock Internally to `MacroValueAssignmentTable` we were looking up interned location references to paths and back, even though we really only need to pass the reference to new `MacroValueAssignment` instances. rdar://146340881 --- .../SWBMacro/MacroValueAssignmentTable.swift | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/Sources/SWBMacro/MacroValueAssignmentTable.swift b/Sources/SWBMacro/MacroValueAssignmentTable.swift index cb1204b6..788dbd68 100644 --- a/Sources/SWBMacro/MacroValueAssignmentTable.swift +++ b/Sources/SWBMacro/MacroValueAssignmentTable.swift @@ -85,6 +85,13 @@ public struct MacroValueAssignmentTable: Serializable, Sendable { valueAssignments[macro] = MacroValueAssignment(expression: value, conditions: conditions, next: valueAssignments[macro], location: location) } + mutating func push(_ macro: MacroDeclaration, _ value: MacroExpression, conditions: MacroConditionSet? = nil, locationRef: InternedMacroValueAssignmentLocation?) { + assert(namespace.lookupMacroDeclaration(macro.name) === macro) + // Validate the type. + assert(macro.type.matchesExpressionType(value)) + valueAssignments[macro] = MacroValueAssignment(expression: value, conditions: conditions, next: valueAssignments[macro], locationRef: locationRef) + } + /// Adds a mapping from each of the macro-to-value mappings in `otherTable`, inserting them ahead of any already existing assignments in the receiving table. The other table isn’t affected in any way (in particular, no reference is kept from the receiver to the other table). public mutating func pushContentsOf(_ otherTable: MacroValueAssignmentTable) { for (macro, firstAssignment) in otherTable.valueAssignments { @@ -183,7 +190,7 @@ public struct MacroValueAssignmentTable: Serializable, Sendable { if effectiveConditionValue.evaluate(condition) == true { // Condition evaluates to true, so we push an assignment with a condition set that excludes the condition. let filteredConditions = conditions.conditions.filter{ $0.parameter != parameter } - table.push(macro, assignment.expression, conditions: filteredConditions.isEmpty ? nil : MacroConditionSet(conditions: filteredConditions), location: assignment.location) + table.push(macro, assignment.expression, conditions: filteredConditions.isEmpty ? nil : MacroConditionSet(conditions: filteredConditions), locationRef: assignment._location) } else { // Condition evaluates to false, so we elide the assignment. @@ -191,7 +198,7 @@ public struct MacroValueAssignmentTable: Serializable, Sendable { } else { // Assignment isn't conditioned on the specified parameter, so we just push it as-is. - table.push(macro, assignment.expression, conditions: assignment.conditions, location: assignment.location) + table.push(macro, assignment.expression, conditions: assignment.conditions, locationRef: assignment._location) } } bindAndPushAssignment(firstAssignment) @@ -330,7 +337,7 @@ public final class MacroValueAssignment: Serializable, CustomStringConvertible, /// Reference to the next (lower precedence) assignment in the linked list, or nil if this is the last one. public let next: MacroValueAssignment? - private let _location: InternedMacroValueAssignmentLocation? + let _location: InternedMacroValueAssignmentLocation? private static let macroConfigPaths = SWBMutex>(OrderedSet()) public var location: MacroValueAssignmentLocation? { @@ -348,13 +355,10 @@ public final class MacroValueAssignment: Serializable, CustomStringConvertible, } /// Initializes the macro value assignment to represent `expression`, with the next existing macro value assignment (if any). - init(expression: MacroExpression, conditions: MacroConditionSet? = nil, next: MacroValueAssignment?, location: MacroValueAssignmentLocation?) { - self.expression = expression - self.conditions = conditions - self.next = next - + convenience init(expression: MacroExpression, conditions: MacroConditionSet? = nil, next: MacroValueAssignment?, location: MacroValueAssignmentLocation?) { + let locationRef: InternedMacroValueAssignmentLocation? if let location { - self._location = InternedMacroValueAssignmentLocation( + locationRef = InternedMacroValueAssignmentLocation( pathRef: Self.macroConfigPaths.withLock({ $0.append(location.path).index }), startLine: location.startLine, endLine: location.endLine, @@ -362,8 +366,22 @@ public final class MacroValueAssignment: Serializable, CustomStringConvertible, endColumn: location.endColumn ) } else { - self._location = nil + locationRef = nil } + + self.init( + expression: expression, + conditions: conditions, + next: next, + locationRef: locationRef + ) + } + + init(expression: MacroExpression, conditions: MacroConditionSet? = nil, next: MacroValueAssignment?, locationRef: InternedMacroValueAssignmentLocation?) { + self.expression = expression + self.conditions = conditions + self.next = next + self._location = locationRef } /// Returns the first macro value assignment that is reachable from the receiver and whose conditions match the given set of parameter values, or nil if there is no such assignment value. The returned assignment may be the receiver itself, or it may be any assignment that’s downstream in the linked list of macro value assignments, or it may be nil if there is none. Unconditional macro value assignments are considered to match any conditions. Conditions that reference parameters that don’t have a value in `paramValues` are only considered to match if the match pattern is `*`, i.e. the “match-anything” pattern (which is effectively a no-op). @@ -448,7 +466,7 @@ public struct MacroValueAssignmentLocation: Sendable, Equatable { } } -private struct InternedMacroValueAssignmentLocation: Serializable, Sendable { +struct InternedMacroValueAssignmentLocation: Serializable, Sendable { let pathRef: OrderedSet.Index public let startLine: Int public let endLine: Int