Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit e025726

Browse files
rakudramacommit-bot@chromium.org
authored andcommitted
[dart2js] Fix for #41890
- Use JS inline code instead of '%' in assertion (#41890) Other changes help code work without inlining or type inference - Use annotation to ensure isTopType has no entry check. - Use JS_STRING_CONCAT instead of '+'. Fixed: 41890 Change-Id: I1958f1ebbb6049a350fad07a975e8e851db2b115 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/148006 Commit-Queue: Stephen Adams <[email protected]> Reviewed-by: Mayank Patke <[email protected]>
1 parent 70f228d commit e025726

File tree

2 files changed

+138
-39
lines changed

2 files changed

+138
-39
lines changed

sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart

Lines changed: 64 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import 'dart:_foreign_helper'
1414
JS_EMBEDDED_GLOBAL,
1515
JS_GET_FLAG,
1616
JS_GET_NAME,
17+
JS_STRING_CONCAT,
1718
RAW_DART_FUNCTION_REF,
1819
TYPE_REF,
1920
LEGACY_TYPE_REF;
@@ -571,7 +572,7 @@ Object? _substituteNamed(
571572
Object? universe, Object? namedArray, Object? typeArguments, int depth) {
572573
bool changed = false;
573574
int length = _Utils.arrayLength(namedArray);
574-
assert(length % 3 == 0);
575+
assert(_Utils.isMultipleOf(length, 3));
575576
Object? result = JS('', '[]');
576577
for (int i = 0; i < length; i += 3) {
577578
String name = _Utils.asString(_Utils.arrayAt(namedArray, i));
@@ -1696,6 +1697,27 @@ class _Universe {
16961697
return rti;
16971698
}
16981699

1700+
// These helpers are used for creating canonical recipes. The key feature of
1701+
// the generated code is that it makes no reference to the constant pool,
1702+
// which does not exist when the type$ pool is created.
1703+
//
1704+
// The strange association is so that usage like
1705+
//
1706+
// s = _recipeJoin3(s, a, b);
1707+
//
1708+
// associates as `s+=(a+b)` rather than `s=s+a+b`. As recipe fragments are
1709+
// small, this tends to create smaller cons-string trees.
1710+
1711+
static String _recipeJoin(String s1, String s2) => JS_STRING_CONCAT(s1, s2);
1712+
static String _recipeJoin3(String s1, String s2, String s3) =>
1713+
JS_STRING_CONCAT(s1, JS_STRING_CONCAT(s2, s3));
1714+
static String _recipeJoin4(String s1, String s2, String s3, String s4) =>
1715+
JS_STRING_CONCAT(s1, JS_STRING_CONCAT(JS_STRING_CONCAT(s2, s3), s4));
1716+
static String _recipeJoin5(
1717+
String s1, String s2, String s3, String s4, String s5) =>
1718+
JS_STRING_CONCAT(s1,
1719+
JS_STRING_CONCAT(JS_STRING_CONCAT(JS_STRING_CONCAT(s2, s3), s4), s5));
1720+
16991721
// For each kind of Rti there are three methods:
17001722
//
17011723
// * `lookupXXX` which takes the component parts and returns an existing Rti
@@ -1714,19 +1736,19 @@ class _Universe {
17141736
static String _canonicalRecipeOfDynamic() => Recipe.pushDynamicString;
17151737
static String _canonicalRecipeOfVoid() => Recipe.pushVoidString;
17161738
static String _canonicalRecipeOfNever() =>
1717-
Recipe.pushNeverExtensionString + Recipe.extensionOpString;
1739+
_recipeJoin(Recipe.pushNeverExtensionString, Recipe.extensionOpString);
17181740
static String _canonicalRecipeOfAny() =>
1719-
Recipe.pushAnyExtensionString + Recipe.extensionOpString;
1741+
_recipeJoin(Recipe.pushAnyExtensionString, Recipe.extensionOpString);
17201742

17211743
static String _canonicalRecipeOfStar(Rti baseType) =>
1722-
Rti._getCanonicalRecipe(baseType) + Recipe.wrapStarString;
1744+
_recipeJoin(Rti._getCanonicalRecipe(baseType), Recipe.wrapStarString);
17231745
static String _canonicalRecipeOfQuestion(Rti baseType) =>
1724-
Rti._getCanonicalRecipe(baseType) + Recipe.wrapQuestionString;
1746+
_recipeJoin(Rti._getCanonicalRecipe(baseType), Recipe.wrapQuestionString);
17251747
static String _canonicalRecipeOfFutureOr(Rti baseType) =>
1726-
Rti._getCanonicalRecipe(baseType) + Recipe.wrapFutureOrString;
1748+
_recipeJoin(Rti._getCanonicalRecipe(baseType), Recipe.wrapFutureOrString);
17271749

17281750
static String _canonicalRecipeOfGenericFunctionParameter(int index) =>
1729-
'$index' + Recipe.genericFunctionTypeParameterIndexString;
1751+
_recipeJoin('$index', Recipe.genericFunctionTypeParameterIndexString);
17301752

17311753
static Rti _lookupErasedRti(Object? universe) {
17321754
return _lookupTerminalRti(
@@ -1888,7 +1910,7 @@ class _Universe {
18881910
for (int i = 0; i < length; i++) {
18891911
Rti argument = _Utils.asRti(_Utils.arrayAt(arguments, i));
18901912
String subrecipe = Rti._getCanonicalRecipe(argument);
1891-
s += sep + subrecipe;
1913+
s = _recipeJoin3(s, sep, subrecipe);
18921914
sep = Recipe.separatorString;
18931915
}
18941916
return s;
@@ -1897,17 +1919,16 @@ class _Universe {
18971919
static String _canonicalRecipeJoinNamed(Object? arguments) {
18981920
String s = '', sep = '';
18991921
int length = _Utils.arrayLength(arguments);
1900-
assert(length % 3 == 0);
1922+
assert(_Utils.isMultipleOf(length, 3));
19011923
for (int i = 0; i < length; i += 3) {
1902-
s += sep;
19031924
String name = _Utils.asString(_Utils.arrayAt(arguments, i));
19041925
bool isRequired = _Utils.asBool(_Utils.arrayAt(arguments, i + 1));
19051926
String nameSep = isRequired
19061927
? Recipe.requiredNameSeparatorString
19071928
: Recipe.nameSeparatorString;
19081929
Rti type = _Utils.asRti(_Utils.arrayAt(arguments, i + 2));
19091930
String subrecipe = Rti._getCanonicalRecipe(type);
1910-
s += name + nameSep + subrecipe;
1931+
s = _recipeJoin5(s, sep, name, nameSep, subrecipe);
19111932
sep = Recipe.separatorString;
19121933
}
19131934
return s;
@@ -1918,9 +1939,8 @@ class _Universe {
19181939
String s = _Utils.asString(name);
19191940
int length = _Utils.arrayLength(arguments);
19201941
if (length != 0) {
1921-
s += Recipe.startTypeArgumentsString +
1922-
_canonicalRecipeJoin(arguments) +
1923-
Recipe.endTypeArgumentsString;
1942+
s = _recipeJoin4(s, Recipe.startTypeArgumentsString,
1943+
_canonicalRecipeJoin(arguments), Recipe.endTypeArgumentsString);
19241944
}
19251945
return s;
19261946
}
@@ -1954,13 +1974,13 @@ class _Universe {
19541974
JS_GET_NAME(JsGetName.FUTURE_CLASS_TYPE_NAME), JS('', '[#]', base));
19551975

19561976
static String _canonicalRecipeOfBinding(Rti base, Object? arguments) {
1957-
String s = Rti._getCanonicalRecipe(base);
1958-
s += Recipe
1959-
.toTypeString; // TODO(sra): Omit when base encoding is Rti without ToType.
1960-
s += Recipe.startTypeArgumentsString +
1961-
_canonicalRecipeJoin(arguments) +
1962-
Recipe.endTypeArgumentsString;
1963-
return s;
1977+
return _recipeJoin5(
1978+
Rti._getCanonicalRecipe(base),
1979+
// TODO(sra): Omit when base encoding is Rti without ToType:
1980+
Recipe.toTypeString,
1981+
Recipe.startTypeArgumentsString,
1982+
_canonicalRecipeJoin(arguments),
1983+
Recipe.endTypeArgumentsString);
19641984
}
19651985

19661986
/// [arguments] becomes owned by the created Rti.
@@ -1992,8 +2012,8 @@ class _Universe {
19922012

19932013
static String _canonicalRecipeOfFunction(
19942014
Rti returnType, _FunctionParameters parameters) =>
1995-
Rti._getCanonicalRecipe(returnType) +
1996-
_canonicalRecipeOfFunctionParameters(parameters);
2015+
_recipeJoin(Rti._getCanonicalRecipe(returnType),
2016+
_canonicalRecipeOfFunctionParameters(parameters));
19972017

19982018
static String _canonicalRecipeOfFunctionParameters(
19992019
_FunctionParameters parameters) {
@@ -2007,26 +2027,26 @@ class _Universe {
20072027
int namedLength = _Utils.arrayLength(named);
20082028
assert(optionalPositionalLength == 0 || namedLength == 0);
20092029

2010-
String recipe = Recipe.startFunctionArgumentsString +
2011-
_canonicalRecipeJoin(requiredPositional);
2030+
String recipe = _recipeJoin(Recipe.startFunctionArgumentsString,
2031+
_canonicalRecipeJoin(requiredPositional));
20122032

20132033
if (optionalPositionalLength > 0) {
20142034
String sep = requiredPositionalLength > 0 ? Recipe.separatorString : '';
2015-
recipe += sep +
2016-
Recipe.startOptionalGroupString +
2017-
_canonicalRecipeJoin(optionalPositional) +
2018-
Recipe.endOptionalGroupString;
2035+
recipe = _recipeJoin5(
2036+
recipe,
2037+
sep,
2038+
Recipe.startOptionalGroupString,
2039+
_canonicalRecipeJoin(optionalPositional),
2040+
Recipe.endOptionalGroupString);
20192041
}
20202042

20212043
if (namedLength > 0) {
20222044
String sep = requiredPositionalLength > 0 ? Recipe.separatorString : '';
2023-
recipe += sep +
2024-
Recipe.startNamedGroupString +
2025-
_canonicalRecipeJoinNamed(named) +
2026-
Recipe.endNamedGroupString;
2045+
recipe = _recipeJoin5(recipe, sep, Recipe.startNamedGroupString,
2046+
_canonicalRecipeJoinNamed(named), Recipe.endNamedGroupString);
20272047
}
20282048

2029-
return recipe + Recipe.endFunctionArgumentsString;
2049+
return _recipeJoin(recipe, Recipe.endFunctionArgumentsString);
20302050
}
20312051

20322052
static Rti _lookupFunctionRti(
@@ -2051,10 +2071,11 @@ class _Universe {
20512071

20522072
static String _canonicalRecipeOfGenericFunction(
20532073
Rti baseFunctionType, Object? bounds) =>
2054-
Rti._getCanonicalRecipe(baseFunctionType) +
2055-
Recipe.startTypeArgumentsString +
2056-
_canonicalRecipeJoin(bounds) +
2057-
Recipe.endTypeArgumentsString;
2074+
_recipeJoin4(
2075+
Rti._getCanonicalRecipe(baseFunctionType),
2076+
Recipe.startTypeArgumentsString,
2077+
_canonicalRecipeJoin(bounds),
2078+
Recipe.endTypeArgumentsString);
20582079

20592080
static Rti _lookupGenericFunctionRti(
20602081
Object? universe, Rti baseFunctionType, Object? bounds, bool normalize) {
@@ -2552,7 +2573,7 @@ class _Parser {
25522573

25532574
static void toTypesNamed(Object? universe, Rti environment, Object? items) {
25542575
int length = _Utils.arrayLength(items);
2555-
assert(length % 3 == 0);
2576+
assert(_Utils.isMultipleOf(length, 3));
25562577
for (int i = 2; i < length; i += 3) {
25572578
var item = _Utils.arrayAt(items, i);
25582579
Rti type = toType(universe, environment, item);
@@ -2995,6 +3016,7 @@ bool isNullable(Rti t) {
29953016
kind == Rti.kindFutureOr && isNullable(Rti._getFutureOrArgument(t));
29963017
}
29973018

3019+
@pragma('dart2js:parameter:trust')
29983020
bool isTopType(Rti t) =>
29993021
isStrongTopType(t) ||
30003022
isLegacyObjectType(t) ||
@@ -3040,6 +3062,8 @@ class _Utils {
30403062
static bool isNotIdentical(Object? s, Object? t) =>
30413063
JS('bool', '# !== #', s, t);
30423064

3065+
static bool isMultipleOf(int n, int d) => JS('bool', '# % # === 0', n, d);
3066+
30433067
static JSArray objectKeys(Object? o) =>
30443068
JS('returns:JSArray;new:true;', 'Object.keys(#)', o);
30453069

@@ -3089,6 +3113,7 @@ class _Utils {
30893113
JS('', '#.set(#, #)', cache, key, value);
30903114
}
30913115
}
3116+
30923117
// -------- Entry points for testing -------------------------------------------
30933118

30943119
String testingCanonicalRecipe(Rti rti) {
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// dart2jsOptions=--enable-asserts --disable-inlining --disable-type-inference --no-minify
6+
7+
import 'dart:async';
8+
import 'package:expect/expect.dart';
9+
10+
// This test contains many different Rti instances that are initialized at
11+
// startup.
12+
13+
typedef F1 = String Function(String, {int opt1});
14+
typedef F2 = String Function(String, {required int req1, int opt1});
15+
16+
class Thingy {
17+
const Thingy();
18+
}
19+
20+
class Generic<AA> {
21+
const Generic();
22+
}
23+
24+
bool isObject(o) => o is Object;
25+
bool isF1(o) => o is F1;
26+
bool isF2(o) => o is F2;
27+
bool isThingy(o) => o is Thingy;
28+
bool isGenericF1(o) => o is Generic<F1>;
29+
bool isGenericF2Q(o) => o is Generic<F2?>;
30+
bool isG3(o) => o is FutureOr<AA> Function<AA>(AA);
31+
32+
String foo1(String s) => s;
33+
String foo2(String s, {int opt1 = 0}) => '$s $opt1';
34+
String foo3(String s, {int opt1 = 0, required int req1}) => '$s $req1 $opt1';
35+
Never foo4() => throw 'never';
36+
37+
// TODO(sra): Use 'isStrongMode' from package:expect.
38+
final bool strong = () {
39+
try {
40+
int i = null as dynamic;
41+
return false;
42+
} catch (e) {
43+
return true;
44+
}
45+
}();
46+
47+
void test() {
48+
var items = [foo1, foo2, foo3, foo4, Thingy(), Generic<F1>()];
49+
50+
void check(String answers, bool Function(dynamic) predicate) {
51+
Expect.equals(items.length, answers.length);
52+
for (int i = 0; i < items.length; i++) {
53+
var item = items[i];
54+
String code = answers[i];
55+
bool expected =
56+
code == 'T' || (code == 'S' && strong) || (code == 'W' && !strong);
57+
Expect.equals(expected, predicate(item), "$predicate '$code' $item");
58+
}
59+
}
60+
61+
// T = true, S = true only in strong mode, W = true only in weak mode.
62+
check('TTTTTT', isObject);
63+
check('.TW...', isF1);
64+
check('..T...', isF2);
65+
check('....T.', isThingy);
66+
check('.....T', isGenericF1);
67+
check('......', isGenericF2Q);
68+
check('......', isG3);
69+
}
70+
71+
void main() {
72+
test();
73+
test();
74+
}

0 commit comments

Comments
 (0)