perf(ngcc): store the position of SegmentMarkers to avoid unnecessary computation (#36027)

Previously, calculations related to the position of and difference between
SegmentMarkers required extensive computation based around the line,
line start positions and columns of each segment.

PR Close #36027
This commit is contained in:
Pete Bacon Darwin
2020-03-11 19:57:38 +00:00
committed by Andrew Kushnir
parent 47025e07ce
commit 772bb5e742
4 changed files with 165 additions and 163 deletions

View File

@ -16,6 +16,7 @@
export interface SegmentMarker {
readonly line: number;
readonly column: number;
readonly position: number;
next: SegmentMarker|undefined;
}
@ -26,20 +27,7 @@ export interface SegmentMarker {
* and zero if they are at the same position.
*/
export function compareSegments(a: SegmentMarker, b: SegmentMarker): number {
return a.line === b.line ? a.column - b.column : a.line - b.line;
}
/**
* Compute the difference between two segment markers in a source file.
*
* @param startOfLinePositions the position of the start of each line of content of the source file
* where we are computing the difference
* @param a the start marker
* @param b the end marker
* @returns the number of characters between the two segments `a` and `b`
*/
export function segmentDiff(startOfLinePositions: number[], a: SegmentMarker, b: SegmentMarker) {
return startOfLinePositions[b.line] - startOfLinePositions[a.line] + b.column - a.column;
return a.position - b.position;
}
/**
@ -51,19 +39,19 @@ export function segmentDiff(startOfLinePositions: number[], a: SegmentMarker, b:
* @param offset the number of character to offset by.
*/
export function offsetSegment(
startOfLinePositions: number[], marker: SegmentMarker, offset: number) {
startOfLinePositions: number[], marker: SegmentMarker, offset: number): SegmentMarker {
if (offset === 0) {
return marker;
}
let line = marker.line;
const newPos = startOfLinePositions[line] + marker.column + offset;
while (line < startOfLinePositions.length - 1 && startOfLinePositions[line + 1] <= newPos) {
const position = marker.position + offset;
while (line < startOfLinePositions.length - 1 && startOfLinePositions[line + 1] <= position) {
line++;
}
while (line > 0 && startOfLinePositions[line] > newPos) {
while (line > 0 && startOfLinePositions[line] > position) {
line--;
}
const column = newPos - startOfLinePositions[line];
return {line, column, next: undefined};
const column = position - startOfLinePositions[line];
return {line, column, position, next: undefined};
}

View File

@ -9,7 +9,7 @@ import {removeComments, removeMapFileComments} from 'convert-source-map';
import {SourceMapMappings, SourceMapSegment, decode, encode} from 'sourcemap-codec';
import {AbsoluteFsPath, dirname, relative} from '../../../src/ngtsc/file_system';
import {RawSourceMap} from './raw_source_map';
import {SegmentMarker, compareSegments, offsetSegment, segmentDiff} from './segment_marker';
import {SegmentMarker, compareSegments, offsetSegment} from './segment_marker';
export function removeSourceMapComments(contents: string): string {
return removeMapFileComments(removeComments(contents)).replace(/\n\n$/, '\n');
@ -89,7 +89,7 @@ export class SourceFile {
* source files with no transitive source maps.
*/
private flattenMappings(): Mapping[] {
const mappings = parseMappings(this.rawMap, this.sources);
const mappings = parseMappings(this.rawMap, this.sources, this.startOfLinePositions);
ensureOriginalSegmentLinks(mappings);
const flattenedMappings: Mapping[] = [];
for (let mappingIndex = 0; mappingIndex < mappings.length; mappingIndex++) {
@ -277,8 +277,7 @@ export function mergeMappings(generatedSource: SourceFile, ab: Mapping, bc: Mapp
// segment-marker" of B->C (4*): `1 - 4 = -3`.
// Since it is negative we must increment the "generated segment-marker" with `3` to give [3,2].
const diff =
segmentDiff(ab.originalSource.startOfLinePositions, ab.originalSegment, bc.generatedSegment);
const diff = compareSegments(bc.generatedSegment, ab.originalSegment);
if (diff > 0) {
return {
name,
@ -303,7 +302,8 @@ export function mergeMappings(generatedSource: SourceFile, ab: Mapping, bc: Mapp
* in the `sources` parameter.
*/
export function parseMappings(
rawMap: RawSourceMap | null, sources: (SourceFile | null)[]): Mapping[] {
rawMap: RawSourceMap | null, sources: (SourceFile | null)[],
generatedSourceStartOfLinePositions: number[]): Mapping[] {
if (rawMap === null) {
return [];
}
@ -330,11 +330,13 @@ export function parseMappings(
const generatedSegment: SegmentMarker = {
line: generatedLine,
column: generatedColumn,
position: generatedSourceStartOfLinePositions[generatedLine] + generatedColumn,
next: undefined,
};
const originalSegment: SegmentMarker = {
line,
column,
position: originalSource.startOfLinePositions[line] + column,
next: undefined,
};
mappings.push({name, generatedSegment, originalSegment, originalSource});