diff --git a/lib/array-set.js b/lib/array-set.js index fbd5c81c..3bf62379 100644 --- a/lib/array-set.js +++ b/lib/array-set.js @@ -44,22 +44,35 @@ ArraySet.prototype.size = function ArraySet_size() { /** * Add the given string to this set. * + * Returns the index of the string within the set: the existing index for a + * duplicate insert, or the new index for a fresh one. Hot generator/consumer + * paths use this return value to avoid a follow-up `indexOf` call (one Map + * lookup per mapping for source and one for name). + * * @param String aStr */ ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { - var sStr = hasNativeMap ? aStr : util.toSetString(aStr); - var isDuplicate = hasNativeMap ? this.has(aStr) : has.call(this._set, sStr); - var idx = this._array.length; - if (!isDuplicate || aAllowDuplicates) { + if (hasNativeMap) { + var existing = this._set.get(aStr); + if (existing !== undefined) { + if (aAllowDuplicates) this._array.push(aStr); + return existing; + } + var idx = this._array.length; this._array.push(aStr); + this._set.set(aStr, idx); + return idx; } - if (!isDuplicate) { - if (hasNativeMap) { - this._set.set(aStr, idx); - } else { - this._set[sStr] = idx; - } + var sStr = util.toSetString(aStr); + if (has.call(this._set, sStr)) { + var existingIdx = this._set[sStr]; + if (aAllowDuplicates) this._array.push(aStr); + return existingIdx; } + var newIdx = this._array.length; + this._array.push(aStr); + this._set[sStr] = newIdx; + return newIdx; }; /** diff --git a/lib/source-map-consumer.js b/lib/source-map-consumer.js index f31964c0..a7cabc86 100644 --- a/lib/source-map-consumer.js +++ b/lib/source-map-consumer.js @@ -1445,14 +1445,11 @@ IndexedSourceMapConsumer.prototype._parseMappings = if(source !== null) { source = util.computeSourceURL(section.consumer.sourceRoot, source, this._sourceMapURL); } - this._sources.add(source); - source = this._sources.indexOf(source); + source = this._sources.add(source); var name = null; if (mapping.name) { - name = section.consumer._names.at(mapping.name); - this._names.add(name); - name = this._names.indexOf(name); + name = this._names.add(section.consumer._names.at(mapping.name)); } // The mappings coming from the consumer for the section have diff --git a/lib/source-map-generator.js b/lib/source-map-generator.js index 5d8f6d0a..fa506418 100644 --- a/lib/source-map-generator.js +++ b/lib/source-map-generator.js @@ -128,19 +128,16 @@ SourceMapGenerator.prototype.addMapping = } // Resolve source/name to integer indices once here so MappingList.add - // can store them as i32s in the slab. ArraySet.add is idempotent (its - // own has() check internally), and indexOf is a fast Map.get afterward. + // can store them as i32s in the slab. ArraySet.add returns the index + // (existing or new), so this is one Map op per source/name instead of + // the add+indexOf pair. var srcIdx = -1; if (source != null) { - source = String(source); - this._sources.add(source); - srcIdx = this._sources.indexOf(source); + srcIdx = this._sources.add(String(source)); } var nameIdx = -1; if (name != null) { - name = String(name); - this._names.add(name); - nameIdx = this._names.indexOf(name); + nameIdx = this._names.add(String(name)); } // _validateMapping enforces numeric original.line/column when original is @@ -279,16 +276,8 @@ SourceMapGenerator.prototype.applySourceMap = } } - var newSrcIdx = -1; - if (source != null) { - newSources.add(source); - newSrcIdx = newSources.indexOf(source); - } - var newNameIdx = -1; - if (name != null) { - newNames.add(name); - newNameIdx = newNames.indexOf(name); - } + var newSrcIdx = source == null ? -1 : newSources.add(source); + var newNameIdx = name == null ? -1 : newNames.add(name); newMappings.add(genLine, genCol, origLine, origCol, newSrcIdx, newNameIdx); }