[dart2js] Constant-fold indexers of constant Lists and Maps

Change-Id: Id2a15047759d3b1b8230379adff314e9052c922c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/235283
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Stephen Adams <sra@google.com>
This commit is contained in:
Stephen Adams 2022-03-05 02:14:31 +00:00 committed by Commit Bot
parent 641255b292
commit 6231245e80
4 changed files with 94 additions and 9 deletions

View file

@ -27,6 +27,7 @@ const greaterEqual = GreaterEqualOperation();
const greater = GreaterOperation();
const identity = IdentityOperation();
const ifNull = IfNullOperation();
const index = _IndexOperation();
const lessEqual = LessEqualOperation();
const less = LessOperation();
const modulo = ModuloOperation();
@ -990,6 +991,38 @@ class ToIntOperation implements UnaryOperation {
}
}
class _IndexOperation implements BinaryOperation {
@override
final String name = '[]';
const _IndexOperation();
@override
ConstantValue fold(ConstantValue left, ConstantValue right) {
if (left is ListConstantValue) {
if (right is IntConstantValue) {
List<ConstantValue> entries = left.entries;
if (right.isUInt32()) {
int index = right.intValue.toInt();
if (index >= 0 && index < entries.length) {
return entries[index];
}
}
}
}
if (left is MapConstantValue) {
ConstantValue value = left.lookup(right);
if (value != null) return value;
return const NullConstantValue();
}
return null;
}
@override
apply(left, right) => throw UnsupportedError('punned indexing');
}
class UnfoldedUnaryOperation implements UnaryOperation {
@override
final String name;

View file

@ -274,6 +274,11 @@ class IndexAssignSpecializer extends InvokeDynamicSpecializer {
class IndexSpecializer extends InvokeDynamicSpecializer {
const IndexSpecializer();
@override
constant_system.BinaryOperation operation() {
return constant_system.index;
}
@override
HInstruction tryConvertToBuiltin(
HInvokeDynamic instruction,

View file

@ -1493,15 +1493,15 @@ class SsaInstructionSimplifier extends HBaseVisitor
@override
HInstruction visitIndex(HIndex node) {
if (node.receiver.isConstantList() && node.index.isConstantInteger()) {
HConstant instruction = node.receiver;
ListConstantValue list = instruction.constant;
List<ConstantValue> entries = list.entries;
HConstant indexInstruction = node.index;
IntConstantValue indexConstant = indexInstruction.constant;
int index = indexConstant.intValue.toInt();
if (index >= 0 && index < entries.length) {
return _graph.addConstant(entries[index], _closedWorld);
HInstruction receiver = node.receiver;
if (receiver is HConstant) {
HInstruction index = node.index;
if (index is HConstant) {
ConstantValue foldedValue =
constant_system.index.fold(receiver.constant, index.constant);
if (foldedValue != null) {
return _graph.addConstant(foldedValue, _closedWorld);
}
}
}
return node;

View file

@ -0,0 +1,47 @@
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
const kList = ['first', 'second'];
const kMap = {0: 'zero', 1: 'one', 2: "two"};
@pragma('dart2js:noInline')
/*member: list1:function() {
return "second";
}*/
list1() {
return kList[1]; // Constant folds to `"second"`.
}
@pragma('dart2js:noInline')
/*member: list2:function() {
return A.ioore(B.List_first_second, 10);
return B.List_first_second[10];
}*/
list2() {
return kList[10]; // Does not constant-fold.
}
@pragma('dart2js:noInline')
/*member: map1:function() {
return "one";
}*/
map1() {
return kMap[1]; // Constant folds to `"one"`.
}
@pragma('dart2js:noInline')
/*member: map2:function() {
return null;
}*/
map2() {
return kMap[10]; // Constant folds to `null`.
}
/*member: main:ignore*/
main() {
list1();
list2();
map1();
map2();
}