From 702a7ee7a18c0265f8f90ff1155268e477dd77cf Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Thu, 6 Apr 2023 14:44:29 -0700 Subject: [PATCH] Fix the performance of selector span expansion (#1929) Instead of calling `SourceFile.getText()`, which creates string copies of a substantial subset of the text of the file every time, this directly accesses the file's underlying code units without doing any copies. Closes #1913 --- CHANGELOG.md | 2 ++ lib/src/interpolation_map.dart | 32 ++++++++++++++++---------------- pkg/sass_api/CHANGELOG.md | 4 ++++ pkg/sass_api/pubspec.yaml | 4 ++-- pubspec.yaml | 4 ++-- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ffc63e44..446755ebb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ * **Potentially breaking change:** Drop support for End-of-Life Node.js 12. +* Fix remaining cases for the performance regression introduced in 1.59.0. + ### Embedded Sass * The JS embedded host now loads files from the working directory when using the diff --git a/lib/src/interpolation_map.dart b/lib/src/interpolation_map.dart index eb52e4009..8cb81e09b 100644 --- a/lib/src/interpolation_map.dart +++ b/lib/src/interpolation_map.dart @@ -6,7 +6,6 @@ import 'dart:math' as math; import 'package:charcode/charcode.dart'; import 'package:source_span/source_span.dart'; -import 'package:string_scanner/string_scanner.dart'; import 'ast/sass.dart'; import 'util/character.dart'; @@ -125,21 +124,21 @@ class InterpolationMap { /// comment before the expression, but since it's only used for error /// reporting that's probably fine. int _expandInterpolationSpanLeft(FileLocation start) { - var source = start.file.getText(0, start.offset); + var source = start.file.codeUnits; var i = start.offset - 1; - while (true) { - var prev = source.codeUnitAt(i--); + while (i >= 0) { + var prev = source[i--]; if (prev == $lbrace) { - if (source.codeUnitAt(i) == $hash) break; + if (source[i] == $hash) break; } else if (prev == $slash) { - var second = source.codeUnitAt(i--); + var second = source[i--]; if (second == $asterisk) { while (true) { - var char = source.codeUnitAt(i--); + var char = source[i--]; if (char != $asterisk) continue; do { - char = source.codeUnitAt(i--); + char = source[i--]; } while (char == $asterisk); if (char == $slash) break; } @@ -153,21 +152,22 @@ class InterpolationMap { /// Given the end of a [FileSpan] covering an interpolated expression, returns /// the offset of the interpolation's closing `}`. int _expandInterpolationSpanRight(FileLocation end) { - var scanner = StringScanner(end.file.getText(end.offset)); - while (true) { - var next = scanner.readChar(); + var source = end.file.codeUnits; + var i = end.offset; + while (i < source.length) { + var next = source[i++]; if (next == $rbrace) break; if (next == $slash) { - var second = scanner.readChar(); + var second = source[i++]; if (second == $slash) { - while (!isNewline(scanner.readChar())) {} + while (!isNewline(source[i++])) {} } else if (second == $asterisk) { while (true) { - var char = scanner.readChar(); + var char = source[i++]; if (char != $asterisk) continue; do { - char = scanner.readChar(); + char = source[i++]; } while (char == $asterisk); if (char == $slash) break; } @@ -175,6 +175,6 @@ class InterpolationMap { } } - return end.offset + scanner.position; + return i; } } diff --git a/pkg/sass_api/CHANGELOG.md b/pkg/sass_api/CHANGELOG.md index 7a48adbe4..e251836b1 100644 --- a/pkg/sass_api/CHANGELOG.md +++ b/pkg/sass_api/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.2.0 + +* No user-visible changes. + ## 6.1.0 * No user-visible changes. diff --git a/pkg/sass_api/pubspec.yaml b/pkg/sass_api/pubspec.yaml index 039c65adf..a85600509 100644 --- a/pkg/sass_api/pubspec.yaml +++ b/pkg/sass_api/pubspec.yaml @@ -2,7 +2,7 @@ name: sass_api # Note: Every time we add a new Sass AST node, we need to bump the *major* # version because it's a breaking change for anyone who's implementing the # visitor interface(s). -version: 6.1.0 +version: 6.2.0 description: Additional APIs for Dart Sass. homepage: https://github.com/sass/dart-sass @@ -10,7 +10,7 @@ environment: sdk: ">=2.17.0 <3.0.0" dependencies: - sass: 1.60.0 + sass: 1.61.0 dev_dependencies: dartdoc: ^5.0.0 diff --git a/pubspec.yaml b/pubspec.yaml index c79520d7d..1e967c589 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: sass -version: 1.61.0-dev +version: 1.61.0 description: A Sass implementation in Dart. homepage: https://github.com/sass/dart-sass @@ -23,7 +23,7 @@ dependencies: path: ^1.8.0 pub_semver: ^2.0.0 source_maps: ^0.10.10 - source_span: ^1.8.1 + source_span: ^1.10.0 stack_trace: ^1.10.0 stream_transform: ^2.0.0 string_scanner: ^1.1.0