dart-sdk/pkg/dart2wasm/lib/records.dart
Alexander Markov 110b0f0eba [tfa,dart2wasm] Create separate class for each record shape in TFA
This allows us to better track all kinds of accesses to record
implementation classes in dart2wasm, which generates separate
record implementation class per record shape.

This change also allows us to remove mutable dispatch targets
which were used to implement dynamic accesses to record fields,
and make tracking of record field types more accurate
(record fields are now versioned per shape).

This is also a step towards inferring actual record types.

TEST=pkg/vm/testcases/transformations/type_flow/transformer/records.dart
TEST=pkg/vm/testcases/transformations/type_flow/transformer/records_dart2wasm.dart
TEST=language/records/simple/dynamic_field_access_test

Issue https://github.com/dart-lang/sdk/issues/49719
Fixes https://github.com/dart-lang/sdk/issues/51363

Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-nnbd-linux-release-x64-try
Change-Id: Icba62a7ca8cfd8ddbc7f2b7c38aeabbef5caec4b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/286950
Reviewed-by: Slava Egorov <vegorov@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
2023-03-07 18:06:42 +00:00

80 lines
2.3 KiB
Dart

// Copyright (c) 2023, 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.
import 'dart:collection' show SplayTreeMap;
import 'package:dart2wasm/class_info.dart';
import 'package:kernel/ast.dart';
/// Describes shape of a record as the number of positionals + set of field
/// names.
class RecordShape {
/// Number of positional fields.
final int positionals;
/// Maps names of the named fields in the record to their indices in the
/// record payload.
final SplayTreeMap<String, int> _names;
/// Names of named fields, sorted.
Iterable<String> get names => _names.keys;
/// Total number of fields.
int get numFields => positionals + _names.length;
/// Create a new [RecordShape] object by given number of
/// positional fields and named fields.
/// [names] should be sorted.
RecordShape(this.positionals, Iterable<String> names)
: _names = SplayTreeMap.fromIterables(
names, Iterable.generate(names.length, (i) => i + positionals));
RecordShape.fromType(RecordType recordType)
: this(recordType.positional.length,
recordType.named.map((ty) => ty.name));
@override
String toString() => 'Record(positionals: $positionals, names: $_names)';
@override
bool operator ==(Object other) {
if (other is! RecordShape) {
return false;
}
if (positionals != other.positionals) {
return false;
}
if (_names.length != other._names.length) {
return false;
}
final names1Iter = _names.keys.iterator;
final names2Iter = other._names.keys.iterator;
while (names1Iter.moveNext()) {
names2Iter.moveNext();
if (names1Iter.current != names2Iter.current) {
return false;
}
}
return true;
}
@override
int get hashCode => Object.hash(positionals, Object.hashAll(_names.keys));
/// Struct index of a positional field.
int getPositionalIndex(int position) => FieldIndex.recordFieldBase + position;
/// Struct index of a named field.
int getNameIndex(String name) =>
FieldIndex.recordFieldBase +
(_names[name] ??
(throw 'RecordImplementation.getNameIndex: '
'name $name not in record: $this'));
}