| // 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); |
| }); |
| } |
| } |