| // 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:convert'; | |
| import 'package:analyzer/dart/element/type.dart'; | |
| import 'package:analyzer/src/wolf/ir/call_descriptor.dart'; | |
| import 'package:analyzer/src/wolf/ir/ir.dart'; | |
| /// Container for a sequence of IR instructions, along with auxiliary tables | |
| /// representing types, literal values, etc. that those instructions refer to. | |
| /// | |
| /// See [BaseIRContainer] for additional information. | |
| /// | |
| /// To construct a sequence of IR instructions, see [CodedIRWriter]. | |
| class CodedIRContainer extends BaseIRContainer { | |
| final List<CallDescriptor> _callDescriptorTable; | |
| final List<Object?> _literalTable; | |
| final List<DartType> _typeTable; | |
| CodedIRContainer(CodedIRWriter super.writer) | |
| : _callDescriptorTable = writer._callDescriptorTable, | |
| _literalTable = writer._literalTable, | |
| _typeTable = writer._typeTable; | |
| @override | |
| String callDescriptorRefToString(CallDescriptorRef callDescriptor) => | |
| decodeCallDescriptor(callDescriptor).toString(); | |
| @override | |
| int countParameters(TypeRef type) => | |
| (decodeType(type) as FunctionType).formalParameters.length; | |
| CallDescriptor decodeCallDescriptor(CallDescriptorRef callDescriptorRef) => | |
| _callDescriptorTable[callDescriptorRef.index]; | |
| Object? decodeLiteral(LiteralRef literal) => _literalTable[literal.index]; | |
| DartType decodeType(TypeRef type) => _typeTable[type.index]; | |
| @override | |
| String literalRefToString(LiteralRef value) => | |
| json.encode(decodeLiteral(value)); | |
| /// Applies [f] to each call descriptor in the call descriptor table, and | |
| /// gathers the results into a list. | |
| List<T> mapCallDescriptors<T>(T Function(CallDescriptor) f) => | |
| _callDescriptorTable.map(f).toList(); | |
| @override | |
| String typeRefToString(TypeRef type) => decodeType(type).toString(); | |
| } | |
| /// Writer of an IR instruction stream, which can encode types, literal values, | |
| /// etc. into auxiliary tables. | |
| /// | |
| /// See [RawIRWriter] for more information. | |
| class CodedIRWriter extends RawIRWriter { | |
| final _callDescriptorTable = <CallDescriptor>[]; | |
| final _callDescriptorToRef = <CallDescriptor, CallDescriptorRef>{}; | |
| final _literalTable = <Object?>[]; | |
| final _literalToRef = <Object?, LiteralRef>{}; | |
| final _typeTable = <DartType>[]; | |
| final _typeToRef = <DartType, TypeRef>{}; | |
| CallDescriptorRef encodeCallDescriptor(CallDescriptor callDescriptor) => | |
| // TODO(paulberry): is `putIfAbsent` the best-performing way to do this? | |
| _callDescriptorToRef.putIfAbsent(callDescriptor, () { | |
| var encoding = CallDescriptorRef(_callDescriptorTable.length); | |
| _callDescriptorTable.add(callDescriptor); | |
| return encoding; | |
| }); | |
| LiteralRef encodeLiteral(Object? value) => | |
| // TODO(paulberry): is `putIfAbsent` the best-performing way to do this? | |
| _literalToRef.putIfAbsent(value, () { | |
| var encoding = LiteralRef(_literalTable.length); | |
| _literalTable.add(value); | |
| return encoding; | |
| }); | |
| TypeRef encodeType(DartType type) => | |
| // TODO(paulberry): is `putIfAbsent` the best-performing way to do this? | |
| _typeToRef.putIfAbsent(type, () { | |
| var encoding = TypeRef(_typeTable.length); | |
| _typeTable.add(type); | |
| return encoding; | |
| }); | |
| } |