Skip to content

Commit

Permalink
Reduce memory overhead of sourcemapLocations
Browse files Browse the repository at this point in the history
It was using an object to store positions in the string. This meant that
those offsets were first stringified and then added as object
properties. For a 200K JS code file (as parsed by rollup), the
sourcemapLocations object was taking up 980K. Switching it to a BitSet
that uses one bit per offset makes it take up 36K instead.

Fixes Rich-Harris#167
  • Loading branch information
mihaip committed Nov 19, 2019
1 parent fae92f8 commit 15604f7
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 6 deletions.
15 changes: 15 additions & 0 deletions src/BitSet.js
@@ -0,0 +1,15 @@
export default class BitSet {
constructor(arg) {
this.bits = arg instanceof BitSet ? arg.bits.slice() : [];
}

add(n) {
this.bits[Math.floor(n / BITS)] |= 1 << n % BITS;
}

has(n) {
return !!(this.bits[Math.floor(n / BITS)] & (1 << n % BITS));
}
}

const BITS = 32;
9 changes: 4 additions & 5 deletions src/MagicString.js
@@ -1,3 +1,4 @@
import BitSet from './BitSet.js';
import Chunk from './Chunk.js';
import SourceMap from './SourceMap.js';
import guessIndent from './utils/guessIndent.js';
Expand Down Expand Up @@ -30,7 +31,7 @@ export default class MagicString {
byEnd: { writable: true, value: {} },
filename: { writable: true, value: options.filename },
indentExclusionRanges: { writable: true, value: options.indentExclusionRanges },
sourcemapLocations: { writable: true, value: {} },
sourcemapLocations: { writable: true, value: new BitSet() },
storedNames: { writable: true, value: {} },
indentStr: { writable: true, value: guessIndent(string) }
});
Expand All @@ -44,7 +45,7 @@ export default class MagicString {
}

addSourcemapLocation(char) {
this.sourcemapLocations[char] = true;
this.sourcemapLocations.add(char);
}

append(content) {
Expand Down Expand Up @@ -121,9 +122,7 @@ export default class MagicString {
cloned.indentExclusionRanges = this.indentExclusionRanges.slice();
}

Object.keys(this.sourcemapLocations).forEach(loc => {
cloned.sourcemapLocations[loc] = true;
});
cloned.sourcemapLocations = new BitSet(this.sourcemapLocations);

cloned.intro = this.intro;
cloned.outro = this.outro;
Expand Down
2 changes: 1 addition & 1 deletion src/utils/Mappings.js
Expand Up @@ -28,7 +28,7 @@ export default class Mappings {
let first = true;

while (originalCharIndex < chunk.end) {
if (this.hires || first || sourcemapLocations[originalCharIndex]) {
if (this.hires || first || sourcemapLocations.has(originalCharIndex)) {
this.rawSegments.push([this.generatedCodeColumn, sourceIndex, loc.line, loc.column]);
}

Expand Down

0 comments on commit 15604f7

Please sign in to comment.