diff --git a/lib/source-map-consumer.js b/lib/source-map-consumer.js index 963e4240..b1784072 100644 --- a/lib/source-map-consumer.js +++ b/lib/source-map-consumer.js @@ -1115,19 +1115,54 @@ BasicSourceMapConsumer.prototype.generatedPositionFor = } if (index < 0) { - var needle = { - source: source, - originalLine: needleLine, - originalColumn: needleColumn - }; - index = this._findMapping( - needle, - mappings, - "originalLine", - "originalColumn", - util.compareByOriginalPositions, - bias - ); + if (bias === SourceMapConsumer.GREATEST_LOWER_BOUND) { + // Cold-path inline GLB binary search. _originalMappings is sorted by + // (source, originalLine, originalColumn). Direct field access avoids + // the indirect aCompare callback through binarySearch.search and + // skips the per-call {source, originalLine, originalColumn} needle + // allocation that the _findMapping call site otherwise pays. + var lo = -1; + var hi = mappings.length; + while (hi - lo > 1) { + var mid = (lo + hi) >>> 1; + var m = mappings[mid]; + var cmp; + if (m.source !== source) cmp = m.source - source; + else if (m.originalLine !== needleLine) cmp = m.originalLine - needleLine; + else cmp = m.originalColumn - needleColumn; + if (cmp <= 0) lo = mid; + else hi = mid; + } + if (lo >= 0) { + // Rewind through any tie cluster to match binarySearch.search's + // smallest-equal semantics. + while (lo > 0) { + var cur = mappings[lo]; + var prev = mappings[lo - 1]; + if (prev.source !== cur.source || + prev.originalLine !== cur.originalLine || + prev.originalColumn !== cur.originalColumn) { + break; + } + lo--; + } + index = lo; + } + } else { + var needle = { + source: source, + originalLine: needleLine, + originalColumn: needleColumn + }; + index = this._findMapping( + needle, + mappings, + "originalLine", + "originalColumn", + util.compareByOriginalPositions, + bias + ); + } } if (index >= 0) {