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

Commit b5a1f6c

Browse files
askeksacommit-bot@chromium.org
authored andcommitted
Reland "[CFE] Move constant evaluation number semantics handling to front end."
This is a reland of c2b466b Original change's description: > [CFE] Move constant evaluation number semantics handling to front end. > > JavaScript number semantics is currently implemented as the simplistic > version previously present in DDC. This is a starting point for fully > detailed JS number semantics. > > Change-Id: Id728b3dacec892a5cbf7ece0d9faea51427f5f9b > Reviewed-on: https://dart-review.googlesource.com/c/94746 > Commit-Queue: Aske Simon Christensen <askesc@google.com> > Reviewed-by: Sigmund Cherem <sigmund@google.com> Change-Id: I1a488ef41bda819d34cb45cd481fd8fd88bfb01e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/95460 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Aske Simon Christensen <askesc@google.com>
1 parent ea6e830 commit b5a1f6c

File tree

6 files changed

+82
-67
lines changed

6 files changed

+82
-67
lines changed

pkg/compiler/lib/src/kernel/dart2js_target.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ class Dart2jsTarget extends Target {
146146
// TODO(askesc): Return specialized dart2js constants backend.
147147
@override
148148
ConstantsBackend constantsBackend(CoreTypes coreTypes) =>
149-
new ConstantsBackend();
149+
const ConstantsBackend();
150150
}
151151

152152
// TODO(sigmund): this "extraRequiredLibraries" needs to be removed...

pkg/dev_compiler/lib/src/kernel/constants.dart

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class DevCompilerConstants {
1919
DevCompilerConstants(
2020
TypeEnvironment types, Map<String, String> declaredVariables)
2121
: _visitor = _ConstantVisitor(types.coreTypes),
22-
_evaluator = ConstantEvaluator(DevCompilerConstantsBackend(),
22+
_evaluator = ConstantEvaluator(const DevCompilerConstantsBackend(),
2323
declaredVariables, types, false, const _ErrorReporter());
2424

2525
/// Determines if an expression is constant.
@@ -170,26 +170,10 @@ class _ConstantVisitor extends ExpressionVisitor<bool> {
170170

171171
/// Implement the class for compiler specific behavior.
172172
class DevCompilerConstantsBackend extends ConstantsBackend {
173-
DevCompilerConstantsBackend();
173+
const DevCompilerConstantsBackend();
174174

175175
@override
176-
Constant lowerConstant(Constant constant) {
177-
// TODO(markzipan): Remove this lowering logic when we switch to
178-
// front-end constant evaluation
179-
if (constant is DoubleConstant) {
180-
// Convert to an integer when possible (matching the runtime behavior
181-
// of `is int`).
182-
var d = constant.value;
183-
if (d.isFinite) {
184-
var i = d.toInt();
185-
if (d == i.toDouble()) return IntConstant(i);
186-
}
187-
}
188-
return constant;
189-
}
190-
191-
// Use doubles to match JS number semantics.
192-
num prepareNumericOperand(num operand) => operand.toDouble();
176+
NumberSemantics get numberSemantics => NumberSemantics.js;
193177
}
194178

195179
class _ErrorReporter extends SimpleErrorReporter {

pkg/dev_compiler/lib/src/kernel/target.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ class DevCompilerTarget extends Target {
151151

152152
@override
153153
ConstantsBackend constantsBackend(CoreTypes coreTypes) =>
154-
new DevCompilerConstantsBackend();
154+
const DevCompilerConstantsBackend();
155155
}
156156

157157
/// Analyzes a component to determine if any covariance checks in private

pkg/kernel/lib/target/targets.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,5 +231,5 @@ class NoneTarget extends Target {
231231

232232
@override
233233
ConstantsBackend constantsBackend(CoreTypes coreTypes) =>
234-
new ConstantsBackend();
234+
const ConstantsBackend();
235235
}

pkg/kernel/lib/transformations/constants.dart

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,7 @@ class ConstantsTransformer extends Transformer {
372372

373373
class ConstantEvaluator extends RecursiveVisitor {
374374
final ConstantsBackend backend;
375+
final NumberSemantics numberSemantics;
375376
Map<String, String> environmentDefines;
376377
final CoreTypes coreTypes;
377378
final TypeEnvironment typeEnvironment;
@@ -396,9 +397,12 @@ class ConstantEvaluator extends RecursiveVisitor {
396397
Set<TreeNode> unevaluatedNodes;
397398
Set<Expression> replacementNodes;
398399

400+
bool get targetingJavaScript => numberSemantics == NumberSemantics.js;
401+
399402
ConstantEvaluator(this.backend, this.environmentDefines, this.typeEnvironment,
400403
this.enableAsserts, this.errorReporter)
401-
: coreTypes = typeEnvironment.coreTypes,
404+
: numberSemantics = backend.numberSemantics,
405+
coreTypes = typeEnvironment.coreTypes,
402406
canonicalizationCache = <Constant, Constant>{},
403407
nodeCache = <Node, Constant>{},
404408
env = new EvaluationEnvironment();
@@ -517,7 +521,7 @@ class ConstantEvaluator extends RecursiveVisitor {
517521
}
518522

519523
visitDoubleLiteral(DoubleLiteral node) {
520-
return canonicalize(new DoubleConstant(node.value));
524+
return canonicalize(makeDoubleConstant(node.value));
521525
}
522526

523527
visitStringLiteral(StringLiteral node) {
@@ -557,7 +561,8 @@ class ConstantEvaluator extends RecursiveVisitor {
557561
typeArgument: node.typeArgument, isConst: true));
558562
}
559563
final DartType typeArgument = evaluateDartType(node, node.typeArgument);
560-
return canonicalize(new ListConstant(typeArgument, entries));
564+
return canonicalize(
565+
backend.lowerListConstant(new ListConstant(typeArgument, entries)));
561566
}
562567

563568
visitSetLiteral(SetLiteral node) {
@@ -580,7 +585,8 @@ class ConstantEvaluator extends RecursiveVisitor {
580585
typeArgument: node.typeArgument, isConst: true));
581586
}
582587
final DartType typeArgument = evaluateDartType(node, node.typeArgument);
583-
return canonicalize(new SetConstant(typeArgument, entries));
588+
return canonicalize(
589+
backend.lowerSetConstant(new SetConstant(typeArgument, entries)));
584590
}
585591

586592
visitMapLiteral(MapLiteral node) {
@@ -616,7 +622,8 @@ class ConstantEvaluator extends RecursiveVisitor {
616622
}
617623
final DartType keyType = evaluateDartType(node, node.keyType);
618624
final DartType valueType = evaluateDartType(node, node.valueType);
619-
return canonicalize(new MapConstant(keyType, valueType, entries));
625+
return canonicalize(
626+
backend.lowerMapConstant(new MapConstant(keyType, valueType, entries)));
620627
}
621628

622629
visitFunctionExpression(FunctionExpression node) {
@@ -1037,7 +1044,7 @@ class ConstantEvaluator extends RecursiveVisitor {
10371044
if (arguments.length == 0) {
10381045
switch (node.name.name) {
10391046
case 'unary-':
1040-
return canonicalize(new DoubleConstant(-receiver.value));
1047+
return canonicalize(makeDoubleConstant(-receiver.value));
10411048
}
10421049
} else if (arguments.length == 1) {
10431050
final Constant other = arguments[0];
@@ -1390,6 +1397,18 @@ class ConstantEvaluator extends RecursiveVisitor {
13901397

13911398
// Helper methods:
13921399

1400+
Constant makeDoubleConstant(double value) {
1401+
if (targetingJavaScript) {
1402+
// Convert to an integer when possible (matching the runtime behavior
1403+
// of `is int`).
1404+
if (value.isFinite) {
1405+
var i = value.toInt();
1406+
if (value == i.toDouble()) return new IntConstant(i);
1407+
}
1408+
}
1409+
return new DoubleConstant(value);
1410+
}
1411+
13931412
void ensureIsSubtype(Constant constant, DartType type, TreeNode node) {
13941413
DartType constantType = constant.getType(typeEnvironment);
13951414

@@ -1456,7 +1475,6 @@ class ConstantEvaluator extends RecursiveVisitor {
14561475
}
14571476

14581477
Constant canonicalize(Constant constant) {
1459-
constant = backend.lowerConstant(constant);
14601478
return canonicalizationCache.putIfAbsent(constant, () => constant);
14611479
}
14621480

@@ -1482,8 +1500,10 @@ class ConstantEvaluator extends RecursiveVisitor {
14821500

14831501
Constant evaluateBinaryNumericOperation(
14841502
String op, num a, num b, TreeNode node) {
1485-
a = backend.prepareNumericOperand(a);
1486-
b = backend.prepareNumericOperand(b);
1503+
if (targetingJavaScript) {
1504+
a = a.toDouble();
1505+
b = b.toDouble();
1506+
}
14871507
num result;
14881508
switch (op) {
14891509
case '+':
@@ -1506,10 +1526,11 @@ class ConstantEvaluator extends RecursiveVisitor {
15061526
break;
15071527
}
15081528

1509-
if (result != null) {
1510-
return canonicalize(result is int
1511-
? new IntConstant(result.toSigned(64))
1512-
: new DoubleConstant(result as double));
1529+
if (result is int) {
1530+
return canonicalize(new IntConstant(result.toSigned(64)));
1531+
}
1532+
if (result is double) {
1533+
return canonicalize(makeDoubleConstant(result));
15131534
}
15141535

15151536
switch (op) {
@@ -1605,16 +1626,30 @@ class EvaluationEnvironment {
16051626
}
16061627
}
16071628

1629+
/// The different kinds of number semantics supported by the constant evaluator.
1630+
enum NumberSemantics {
1631+
/// Dart VM number semantics.
1632+
vm,
1633+
1634+
/// JavaScript (Dart2js and DDC) number semantics.
1635+
js,
1636+
}
1637+
16081638
// Backend specific constant evaluation behavior
16091639
class ConstantsBackend {
1610-
/// Transformation of constants prior to canonicalization, e.g. to change the
1611-
/// representation of certain kinds of constants, or to implement specific
1612-
/// number semantics.
1613-
Constant lowerConstant(Constant constant) => constant;
1614-
1615-
/// Transformation of numeric operands prior to a binary operation,
1616-
/// e.g. to implement specific number semantics.
1617-
num prepareNumericOperand(num operand) => operand;
1640+
const ConstantsBackend();
1641+
1642+
/// Lowering of a list constant to a backend-specific representation.
1643+
Constant lowerListConstant(ListConstant constant) => constant;
1644+
1645+
/// Lowering of a set constant to a backend-specific representation.
1646+
Constant lowerSetConstant(SetConstant constant) => constant;
1647+
1648+
/// Lowering of a map constant to a backend-specific representation.
1649+
Constant lowerMapConstant(MapConstant constant) => constant;
1650+
1651+
/// Number semantics to use for this backend.
1652+
NumberSemantics get numberSemantics => NumberSemantics.vm;
16181653
}
16191654

16201655
// Used as control-flow to abort the current evaluation.

pkg/kernel/lib/vm/constants_native_effects.dart

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,30 +26,26 @@ class VmConstantsBackend extends ConstantsBackend {
2626
}
2727

2828
@override
29-
Constant lowerConstant(Constant constant) {
30-
if (constant is MapConstant) {
31-
// The _ImmutableMap class is implemented via one field pointing to a list
32-
// of key/value pairs -- see runtime/lib/immutable_map.dart!
33-
final List<Constant> kvListPairs =
34-
new List<Constant>(2 * constant.entries.length);
35-
for (int i = 0; i < constant.entries.length; i++) {
36-
final ConstantMapEntry entry = constant.entries[i];
37-
kvListPairs[2 * i] = entry.key;
38-
kvListPairs[2 * i + 1] = entry.value;
39-
}
40-
// This is a bit fishy, since we merge the key and the value type by
41-
// putting both into the same list.
42-
final kvListConstant = new ListConstant(const DynamicType(), kvListPairs);
43-
assert(immutableMapClass.fields.length == 1);
44-
final Field kvPairListField = immutableMapClass.fields[0];
45-
return new InstanceConstant(immutableMapClass.reference, <DartType>[
46-
constant.keyType,
47-
constant.valueType,
48-
], <Reference, Constant>{
49-
kvPairListField.reference: kvListConstant,
50-
});
29+
Constant lowerMapConstant(MapConstant constant) {
30+
// The _ImmutableMap class is implemented via one field pointing to a list
31+
// of key/value pairs -- see runtime/lib/immutable_map.dart!
32+
final List<Constant> kvListPairs =
33+
new List<Constant>(2 * constant.entries.length);
34+
for (int i = 0; i < constant.entries.length; i++) {
35+
final ConstantMapEntry entry = constant.entries[i];
36+
kvListPairs[2 * i] = entry.key;
37+
kvListPairs[2 * i + 1] = entry.value;
5138
}
52-
53-
return constant;
39+
// This is a bit fishy, since we merge the key and the value type by
40+
// putting both into the same list.
41+
final kvListConstant = new ListConstant(const DynamicType(), kvListPairs);
42+
assert(immutableMapClass.fields.length == 1);
43+
final Field kvPairListField = immutableMapClass.fields[0];
44+
return new InstanceConstant(immutableMapClass.reference, <DartType>[
45+
constant.keyType,
46+
constant.valueType,
47+
], <Reference, Constant>{
48+
kvPairListField.reference: kvListConstant,
49+
});
5450
}
5551
}

0 commit comments

Comments
 (0)