// 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 types = []; 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.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 blocks = []; 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.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(); } }