Skip to content

Commit 06402ab

Browse files
jensjohaCommit Queue
authored andcommitted
[parser] Optimize mayFollowTypeArgs
Doing benchmarks before and after I get the below. Notice that this is on tokens/ms, i.e. higher is better. JIT: pkg/analyzer/lib/src/dart/ast/ast.dart: ``` Difference at 95.0% confidence 1.27922 +/- 0.393002 6.47159% +/- 1.9882% (Student's t, pooled s = 0.418268) ``` pkg/front_end/lib/src/type_inference/inference_visitor.dart: ``` Difference at 95.0% confidence 0.968609 +/- 0.287367 6.8824% +/- 2.04187% (Student's t, pooled s = 0.305841) ``` In both cases it processes a little over 6% more tokens per ms. AOT: pkg/analyzer/lib/src/dart/ast/ast.dart: ``` Difference at 95.0% confidence 2.39988 +/- 0.429312 9.50898% +/- 1.70105% (Student's t, pooled s = 0.456911) ``` pkg/front_end/lib/src/type_inference/inference_visitor.dart: ``` Difference at 95.0% confidence 2.28604 +/- 0.279366 12.9521% +/- 1.58282% (Student's t, pooled s = 0.297326) ``` It processes between 9-13% more tokens per ms. Additionally, for AOT, I ran it through the benchmarker and got this: pkg/analyzer/lib/src/dart/ast/ast.dart: ``` msec task-clock:u: -8.5488% +/- 2.1840% (-275.52 +/- 70.39) (3222.95 -> 2947.42) cycles:u: -8.6402% +/- 2.1619% (-1210657004.60 +/- 302921394.06) (14011942063.40 -> 12801285058.80) instructions:u: -9.0870% +/- 0.0000% (-2746030853.20 +/- 876.33) (30219334757.30 -> 27473303904.10) branch-misses:u: -13.3846% +/- 10.1850% (-5542357.40 +/- 4217459.09) (41408381.20 -> 35866023.80) seconds time elapsed: -8.5442% +/- 2.1816% (-0.28 +/- 0.07) (3.22 -> 2.95) seconds user: -8.5614% +/- 2.2098% (-0.27 +/- 0.07) (3.20 -> 2.93) ``` pkg/front_end/lib/src/type_inference/inference_visitor.dart ``` msec task-clock:u: -11.6033% +/- 0.9079% (-402.51 +/- 31.50) (3468.96 -> 3066.45) cycles:u: -11.6826% +/- 0.9053% (-1765194611.60 +/- 136793475.00) (15109578869.80 -> 13344384258.20) instructions:u: -11.4435% +/- 0.0000% (-3905886611.70 +/- 1150.33) (34131775222.10 -> 30225888610.40) branch-misses:u: -17.5244% +/- 4.6453% (-8196278.70 +/- 2172645.25) (46770630.60 -> 38574351.90) seconds time elapsed: -11.6004% +/- 0.9056% (-0.40 +/- 0.03) (3.47 -> 3.07) seconds user: -11.6215% +/- 0.9879% (-0.40 +/- 0.03) (3.45 -> 3.05) ``` I.e. in both cases it's 8-11% less work (instructions, time etc). Compiling the CFE with the CFE before and after (AOT) I get this change: ``` msec task-clock:u: -0.4356% +/- 0.3110% (-23.07 +/- 16.47) (5295.49 -> 5272.42) page-faults:u: 0.1135% +/- 0.0534% (123.64 +/- 58.22) (108956.82 -> 109080.46) cycles:u: -0.5004% +/- 0.3175% (-109702416.52 +/- 69596415.67) (21921571730.18 -> 21811869313.66) instructions:u: -0.3994% +/- 0.0005% (-104979706.80 +/- 138268.02) (26284569470.80 -> 26179589764.00) branch-misses:u: -1.6117% +/- 1.4644% (-1285239.90 +/- 1167813.84) (79746730.52 -> 78461490.62) seconds time elapsed: -0.4291% +/- 0.3090% (-0.02 +/- 0.02) (5.30 -> 5.28) seconds user: -0.3992% +/- 0.3801% (-0.02 +/- 0.02) (5.04 -> 5.02) ``` So this improvement to the parser reduces the runtime of compiling by ~0.4%. Change-Id: Ia89d02e8cce2655fb23ffe18ecbab63521ce75e3 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/439721 Commit-Queue: Jens Johansen <[email protected]> Reviewed-by: Johnni Winther <[email protected]>
1 parent 9c5eea2 commit 06402ab

File tree

1 file changed

+73
-18
lines changed

1 file changed

+73
-18
lines changed

pkg/_fe_analyzer_shared/lib/src/parser/type_info.dart

Lines changed: 73 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,8 @@ TypeParamOrArgInfo computeTypeParamOrArg(
470470
/// possible other constructs will pass (e.g., 'a < C, D > 3').
471471
TypeParamOrArgInfo computeMethodTypeArguments(Token token) {
472472
TypeParamOrArgInfo typeArg = computeTypeParamOrArg(token);
473-
return mayFollowTypeArgs(typeArg.skip(token).next!) && !typeArg.recovered
473+
return _mayFollowTypeArgs(typeArg.skip(token).next!.typeIndex) &&
474+
!typeArg.recovered
474475
? typeArg
475476
: noTypeParamOrArg;
476477
}
@@ -480,8 +481,10 @@ TypeParamOrArgInfo computeMethodTypeArguments(Token token) {
480481
/// pattern.
481482
const Set<String> illegalPatternIdentifiers = {'when', 'as'};
482483

483-
/// Indicates whether the given [token] is allowed to follow a list of type
484-
/// arguments used as a selector after an expression.
484+
/// Indicates whether the given [tokenTypeIndex] is allowed to follow a list of
485+
/// type arguments used as a selector after an expression.
486+
///
487+
/// Get the index from a token via `Token.typeIndex`.
485488
///
486489
/// This is used for disambiguating constructs like `f(a<b,c>(d))` and
487490
/// `f(a<b,c>-d)`. In the case of `f(a<b,c>(d))`, `true` will be returned,
@@ -490,19 +493,71 @@ const Set<String> illegalPatternIdentifiers = {'when', 'as'};
490493
/// function `a`). In the case of `f(a<b,c>-d)`, `false` will be returned,
491494
/// indicating that the `<` and `>` should be interpreted as operators (so two
492495
/// arguments are being passed to `f`: `a < b` and `c > -d`).
493-
bool mayFollowTypeArgs(Token token) {
494-
const Set<String> continuationTokens = {'(', '.', '==', '!='};
495-
const Set<String> stopTokens = {')', ']', '}', ';', ':', ','};
496-
const Set<String> tokensThatMayFollowTypeArg = {
497-
...continuationTokens,
498-
...stopTokens,
499-
};
500-
if (token.isA(TokenType.EOF)) {
501-
// The spec doesn't have anything to say about this case, since an
502-
// expression can't occur at the end of a file, but for testing it's to our
503-
// advantage to allow EOF after type arguments, so that an isolated `f<x>`
504-
// can be parsed as an expression.
505-
return true;
506-
}
507-
return tokensThatMayFollowTypeArg.contains(token.lexeme);
496+
///
497+
// DartDocTest(() {
498+
// for (int i = 0; i < 256; i++) {
499+
// if (_mayFollowTypeArgs(i) !=
500+
// _mayFollowTypeArgs_helper_for_testing(i)) {
501+
// return false;
502+
// }
503+
// }
504+
// return true;
505+
// }(), true);
506+
@pragma("vm:prefer-inline")
507+
bool _mayFollowTypeArgs(int tokenTypeIndex) {
508+
// Table has size 256 to avoid bounds checks as this is called with
509+
// `Token.typeIndex` which is know to be in [0-255].
510+
const List<bool> table = [
511+
// format hack.
512+
true, false, false, false, false, false, false, false,
513+
false, false, false, false, false, false, false, false,
514+
false, false, true, false, false, false, false, false,
515+
true, true, false, false, true, true, true, false,
516+
true, false, false, false, false, false, false, false,
517+
false, false, false, false, false, false, false, false,
518+
false, false, false, false, true, false, false, false,
519+
true, false, false, false, false, false, false, false,
520+
false, true, false, false, false, false, false, false,
521+
false, false, false, false, false, false, false, false,
522+
false, false, false, false, false, false, false, false,
523+
false, false, false, false, false, false, false, false,
524+
false, false, false, false, false, false, false, false,
525+
false, false, false, false, false, false, false, false,
526+
false, false, false, false, false, false, false, false,
527+
false, false, false, false, false, false, false, false,
528+
false, false, false, false, false, false, false, false,
529+
false, false, false, false, false, false, false, false,
530+
false, false, false, false, false, false, false, false,
531+
false, false, false, false, false, false, false, false,
532+
false, false, false, false, false, false, false, false,
533+
false, false, false, false, false, false, false, false,
534+
false, false, false, false, false, false, false, false,
535+
false, false, false, false, false, false, false, false,
536+
false, false, false, false, false, false, false, false,
537+
false, false, false, false, false, false, false, false,
538+
false, false, false, false, false, false, false, false,
539+
false, false, false, false, false, false, false, false,
540+
false, false, false, false, false, false, false, false,
541+
false, false, false, false, false, false, false, false,
542+
false, false, false, false, false, false, false, false,
543+
false, false, false, false, false, false, false, false,
544+
// format hack.
545+
];
546+
547+
return table[tokenTypeIndex];
548+
}
549+
550+
// ignore: unused_element
551+
bool _mayFollowTypeArgs_helper_for_testing(int tokenTypeIndex) {
552+
return tokenTypeIndex == TokenType.OPEN_PAREN.index ||
553+
tokenTypeIndex == TokenType.PERIOD.index ||
554+
tokenTypeIndex == TokenType.EQ_EQ.index ||
555+
tokenTypeIndex == TokenType.BANG_EQ.index ||
556+
tokenTypeIndex == TokenType.CLOSE_PAREN.index ||
557+
tokenTypeIndex == TokenType.CLOSE_SQUARE_BRACKET.index ||
558+
tokenTypeIndex == TokenType.CLOSE_CURLY_BRACKET.index ||
559+
tokenTypeIndex == TokenType.SEMICOLON.index ||
560+
tokenTypeIndex == TokenType.COLON.index ||
561+
tokenTypeIndex == TokenType.COMMA.index ||
562+
tokenTypeIndex == TokenType.EOF.index;
508563
}

0 commit comments

Comments
 (0)