|  | // Copyright (c) 2024, 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 'bytecode_serialization.dart' show BufferedWriter, BufferedReader; | 
|  |  | 
|  | class TryBlock { | 
|  | static const int flagNeedsStackTrace = 1 << 0; | 
|  | static const int flagIsSynthetic = 1 << 1; | 
|  |  | 
|  | final int tryIndex; | 
|  | final int outerTryIndex; | 
|  | final int startPC; | 
|  | int endPC = -1; | 
|  | int handlerPC = -1; | 
|  | int flags = 0; | 
|  | List<int> types = <int>[]; | 
|  |  | 
|  | TryBlock._(this.tryIndex, this.outerTryIndex, this.startPC); | 
|  |  | 
|  | bool get needsStackTrace => (flags & flagNeedsStackTrace) != 0; | 
|  |  | 
|  | void set needsStackTrace(bool value) { | 
|  | flags = (flags & ~flagNeedsStackTrace) | (value ? flagNeedsStackTrace : 0); | 
|  | } | 
|  |  | 
|  | bool get isSynthetic => (flags & flagIsSynthetic) != 0; | 
|  |  | 
|  | void set isSynthetic(bool value) { | 
|  | flags = (flags & ~flagIsSynthetic) | (value ? flagIsSynthetic : 0); | 
|  | } | 
|  |  | 
|  | void write(BufferedWriter writer) { | 
|  | writer.writePackedUInt30(outerTryIndex + 1); | 
|  | writer.writePackedUInt30(startPC); | 
|  | writer.writePackedUInt30(endPC); | 
|  | writer.writePackedUInt30(handlerPC); | 
|  | writer.writeByte(flags); | 
|  | writer.writePackedUInt30(types.length); | 
|  | types.forEach(writer.writePackedUInt30); | 
|  | } | 
|  |  | 
|  | factory TryBlock.read(BufferedReader reader, int tryIndex) { | 
|  | final outerTryIndex = reader.readPackedUInt30() - 1; | 
|  | final startPC = reader.readPackedUInt30(); | 
|  | final tryBlock = new TryBlock._(tryIndex, outerTryIndex, startPC); | 
|  |  | 
|  | tryBlock.endPC = reader.readPackedUInt30(); | 
|  | tryBlock.handlerPC = reader.readPackedUInt30(); | 
|  | tryBlock.flags = reader.readByte(); | 
|  | tryBlock.types = new List<int>.generate( | 
|  | reader.readPackedUInt30(), (_) => reader.readPackedUInt30()); | 
|  |  | 
|  | return tryBlock; | 
|  | } | 
|  |  | 
|  | @override | 
|  | String toString() => 'try-index $tryIndex, outer $outerTryIndex, ' | 
|  | 'start $startPC, end $endPC, handler $handlerPC, ' | 
|  | '${needsStackTrace ? 'needs-stack-trace, ' : ''}' | 
|  | '${isSynthetic ? 'synthetic, ' : ''}' | 
|  | 'types ${types.map((t) => 'CP#$t').toList()}'; | 
|  | } | 
|  |  | 
|  | class ExceptionsTable { | 
|  | List<TryBlock> blocks = <TryBlock>[]; | 
|  |  | 
|  | ExceptionsTable(); | 
|  |  | 
|  | TryBlock enterTryBlock(int startPC) { | 
|  | assert(blocks.isEmpty || blocks.last.startPC <= startPC); | 
|  | final tryBlock = | 
|  | new TryBlock._(blocks.length, _outerTryBlockIndex(startPC), startPC); | 
|  | blocks.add(tryBlock); | 
|  | return tryBlock; | 
|  | } | 
|  |  | 
|  | int _outerTryBlockIndex(int startPC) { | 
|  | for (int i = blocks.length - 1; i >= 0; --i) { | 
|  | final tryBlock = blocks[i]; | 
|  | if (tryBlock.endPC < 0 || tryBlock.endPC > startPC) { | 
|  | return i; | 
|  | } | 
|  | } | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | void write(BufferedWriter writer) { | 
|  | writer.writePackedUInt30(blocks.length); | 
|  | blocks.forEach((b) => b.write(writer)); | 
|  | } | 
|  |  | 
|  | ExceptionsTable.read(BufferedReader reader) | 
|  | : blocks = new List<TryBlock>.generate(reader.readPackedUInt30(), | 
|  | (int index) => new TryBlock.read(reader, index)); | 
|  |  | 
|  | @override | 
|  | String toString() { | 
|  | if (blocks.isEmpty) { | 
|  | return ''; | 
|  | } | 
|  | StringBuffer sb = new StringBuffer(); | 
|  | sb.writeln('ExceptionsTable {'); | 
|  | for (var tryBlock in blocks) { | 
|  | sb.writeln('  $tryBlock'); | 
|  | } | 
|  | sb.writeln('}'); | 
|  | return sb.toString(); | 
|  | } | 
|  | } |