Even faster source map generation

Summary:
This replaces a polymorphic method with three separate methods that support the different used invocations.

In isolation, this leads to a 25% speedup.

Shoutout to trueadm for teaching me about this.

Reviewed By: trueadm

Differential Revision: D4436781

fbshipit-source-id: 3dce83556debf19d5305c4566a56b9e9565e85bc
This commit is contained in:
David Aurelio 2017-01-20 07:12:15 -08:00 committed by Facebook Github Bot
parent ec6d380a7a
commit 8139d2a602
2 changed files with 64 additions and 57 deletions

View File

@ -73,22 +73,10 @@ class Generator {
} }
/** /**
* Add a mapping that contains the first 2, 4, or all of the following values: * Adds a mapping for generated code without a corresponding source location.
*
* 1. line offset in the generated source
* 2. column offset in the generated source
* 3. line offset in the original source
* 4. column offset in the original source
* 5. name of the symbol in the original source.
*/ */
addMapping( addSimpleMapping(generatedLine: number, generatedColumn: number): void {
generatedLine: number, const last = this.last;
generatedColumn: number,
sourceLine?: number,
sourceColumn?: number,
name?: string,
): void {
var {last} = this;
if (this.source === -1 || if (this.source === -1 ||
generatedLine === last.generatedLine && generatedLine === last.generatedLine &&
generatedColumn < last.generatedColumn || generatedColumn < last.generatedColumn ||
@ -107,28 +95,47 @@ class Generator {
this.builder.startSegment(generatedColumn - last.generatedColumn); this.builder.startSegment(generatedColumn - last.generatedColumn);
last.generatedColumn = generatedColumn; last.generatedColumn = generatedColumn;
}
if (sourceLine != null) { /**
if (sourceColumn == null) { * Adds a mapping for generated code with a corresponding source location.
throw new Error( */
'Received mapping with source line, but without source column'); addSourceMapping(
} generatedLine: number,
generatedColumn: number,
sourceLine: number,
sourceColumn: number,
): void {
this.addSimpleMapping(generatedLine, generatedColumn);
this.builder const last = this.last;
.append(this.source - last.source) this.builder
.append(sourceLine - last.sourceLine) .append(this.source - last.source)
.append(sourceColumn - last.sourceColumn); .append(sourceLine - last.sourceLine)
.append(sourceColumn - last.sourceColumn);
last.source = this.source; last.source = this.source;
last.sourceColumn = sourceColumn; last.sourceColumn = sourceColumn;
last.sourceLine = sourceLine; last.sourceLine = sourceLine;
}
if (name != null) { /**
const nameIndex = this.names.indexFor(name); * Adds a mapping for code with a corresponding source location + symbol name.
this.builder.append(nameIndex - last.name); */
last.name = nameIndex; addNamedSourceMapping(
} generatedLine: number,
} generatedColumn: number,
sourceLine: number,
sourceColumn: number,
name: string,
): void {
this.addSourceMapping(
generatedLine, generatedColumn, sourceLine, sourceColumn);
const last = this.last;
const nameIndex = this.names.indexFor(name);
this.builder.append(nameIndex - last.name);
last.name = nameIndex;
} }
/** /**

View File

@ -17,7 +17,7 @@ import type ModuleTransport from '../../lib/ModuleTransport';
import type {RawMapping as BabelRawMapping} from 'babel-generator'; import type {RawMapping as BabelRawMapping} from 'babel-generator';
type GeneratedCodeMapping = [number, number]; type GeneratedCodeMapping = [number, number];
type SourceMapping = [number, number, number, number, void]; type SourceMapping = [number, number, number, number];
type SourceMappingWithName = [number, number, number, number, string]; type SourceMappingWithName = [number, number, number, number, string];
export type RawMapping = export type RawMapping =
@ -59,15 +59,10 @@ function compactMapping(mapping: BabelRawMapping): RawMapping {
} }
if (typeof name !== 'string') { if (typeof name !== 'string') {
/* $FlowFixMe(>=0.38.0 site=react_native_fb,react_native_oss) - Flow error return [line, column, original.line, original.column];
* detected during the deployment of v0.38.0. To see the error, remove this
* comment and run flow */
return ([line, column, original.line, original.column]: SourceMapping);
} }
return ( return [line, column, original.line, original.column, name];
[line, column, original.line, original.column, name]: SourceMappingWithName
);
} }
function addMappingsForFile(generator, mappings, module, carryOver) { function addMappingsForFile(generator, mappings, module, carryOver) {
@ -75,27 +70,32 @@ function addMappingsForFile(generator, mappings, module, carryOver) {
const columnOffset = module.code.indexOf('{') + 1; const columnOffset = module.code.indexOf('{') + 1;
for (let i = 0, n = mappings.length; i < n; ++i) { for (let i = 0, n = mappings.length; i < n; ++i) {
const mapping = mappings[i]; addMapping(generator, mappings[i], carryOver, columnOffset);
generator.addMapping(
mapping[0] + carryOver,
// lines start at 1, columns start at 0
mapping[0] === 1 && mapping[1] + columnOffset || mapping[1],
/* $FlowFixMe(>=0.38.0 site=react_native_fb,react_native_oss) - Flow error
* detected during the deployment of v0.38.0. To see the error, remove
* this comment and run flow */
mapping[2],
/* $FlowFixMe(>=0.38.0 site=react_native_fb,react_native_oss) - Flow error
* detected during the deployment of v0.38.0. To see the error, remove
* this comment and run flow */
mapping[3],
//$FlowIssue #15417846
mapping[4],
);
} }
generator.endFile(); generator.endFile();
} }
function addMapping(generator, mapping, carryOver, columnOffset) {
const n = mapping.length;
const line = mapping[0] + carryOver;
// lines start at 1, columns start at 0
const column = mapping[0] === 1 ? mapping[1] + columnOffset : mapping[1];
if (n === 2) {
generator.addSimpleMapping(line, column);
} else if (n === 4) {
// $FlowIssue #15579526
generator.addSourceMapping(line, column, mapping[2], mapping[3]);
} else if (n === 5) {
generator.addNamedSourceMapping(
// $FlowIssue #15579526
line, column, mapping[2], mapping[3], mapping[4]);
} else {
throw new Error(`Invalid mapping: [${mapping.join(', ')}]`);
}
}
function countLines(string) { function countLines(string) {
return string.split('\n').length; return string.split('\n').length;
} }