blob: 911f2ccc5b91e0f142b493130f2bc08fe8410e41 [file] [log] [blame]
// Copyright (c) 2017, 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.
library vm.constants_native_effects;
import '../ast.dart';
import '../target/targets.dart';
import '../core_types.dart';
class VmConstantsBackend extends ConstantsBackend {
final Class immutableMapClass;
final Class unmodifiableSetClass;
final Field unmodifiableSetMap;
VmConstantsBackend._(this.immutableMapClass, this.unmodifiableSetMap,
this.unmodifiableSetClass);
/// If [defines] is not `null` it will be used for handling
/// `const {bool,...}.fromEnvironment()` otherwise the current VM's values
/// will be used.
factory VmConstantsBackend(CoreTypes coreTypes) {
final Library coreLibrary = coreTypes.coreLibrary;
final Class immutableMapClass = coreLibrary.classes
.firstWhere((Class klass) => klass.name == '_ImmutableMap');
// ignore: unnecessary_null_comparison
assert(immutableMapClass != null);
Field unmodifiableSetMap =
coreTypes.index.getField('dart:collection', '_UnmodifiableSet', '_map');
return new VmConstantsBackend._(immutableMapClass, unmodifiableSetMap,
unmodifiableSetMap.enclosingClass!);
}
@override
Constant lowerMapConstant(MapConstant constant) {
// The _ImmutableMap class is implemented via one field pointing to a list
// of key/value pairs -- see runtime/lib/immutable_map.dart!
final List<Constant> kvListPairs =
new List<Constant>.generate(2 * constant.entries.length, (int i) {
final int index = i ~/ 2;
final ConstantMapEntry entry = constant.entries[index];
return i % 2 == 0 ? entry.key : entry.value;
});
// This is a bit fishy, since we merge the key and the value type by
// putting both into the same list.
final ListConstant kvListConstant =
new ListConstant(const DynamicType(), kvListPairs);
assert(immutableMapClass.fields.length == 1);
final Field kvPairListField = immutableMapClass.fields[0];
return new InstanceConstant(immutableMapClass.reference, <DartType>[
constant.keyType,
constant.valueType,
], <Reference, Constant>{
// We use getterReference as we refer to the field itself.
kvPairListField.getterReference: kvListConstant,
});
}
@override
bool isLoweredMapConstant(Constant constant) {
return constant is InstanceConstant &&
constant.classNode == immutableMapClass;
}
@override
void forEachLoweredMapConstantEntry(
Constant constant, void Function(Constant key, Constant value) f) {
assert(isLoweredMapConstant(constant));
final InstanceConstant instance = constant as InstanceConstant;
assert(immutableMapClass.fields.length == 1);
final Field kvPairListField = immutableMapClass.fields[0];
final ListConstant kvListConstant =
instance.fieldValues[kvPairListField.getterReference] as ListConstant;
assert(kvListConstant.entries.length % 2 == 0);
for (int index = 0; index < kvListConstant.entries.length; index += 2) {
f(kvListConstant.entries[index], kvListConstant.entries[index + 1]);
}
}
@override
Constant lowerSetConstant(SetConstant constant) {
final DartType elementType = constant.typeArgument;
final List<Constant> entries = constant.entries;
final List<ConstantMapEntry> mapEntries =
new List<ConstantMapEntry>.generate(entries.length, (int index) {
return new ConstantMapEntry(entries[index], new NullConstant());
});
Constant map = lowerMapConstant(
new MapConstant(elementType, const NullType(), mapEntries));
return new InstanceConstant(unmodifiableSetClass.reference, [elementType],
<Reference, Constant>{unmodifiableSetMap.getterReference: map});
}
@override
bool isLoweredSetConstant(Constant constant) {
if (constant is InstanceConstant &&
constant.classNode == unmodifiableSetClass) {
InstanceConstant instance = constant;
return isLoweredMapConstant(
instance.fieldValues[unmodifiableSetMap.getterReference]!);
}
return false;
}
@override
void forEachLoweredSetConstantElement(
Constant constant, void Function(Constant element) f) {
assert(isLoweredSetConstant(constant));
final InstanceConstant instance = constant as InstanceConstant;
final Constant mapConstant =
instance.fieldValues[unmodifiableSetMap.getterReference]!;
forEachLoweredMapConstantEntry(mapConstant, (Constant key, Constant value) {
f(key);
});
}
}