// 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 .getMember('dart:collection', '_UnmodifiableSet', '_map') as Field; 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 kvListPairs = new List.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, [ constant.keyType, constant.valueType, ], { // 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 entries = constant.entries; final List mapEntries = new List.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], {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); }); } }