8f7a0f400b
Change-Id: I83963771db301089317823f6bf14eb4a2728dbfb Reviewed-on: https://dart-review.googlesource.com/c/81740 Auto-Submit: Alexander Markov <alexmarkov@google.com> Commit-Queue: Régis Crelier <regis@google.com> Reviewed-by: Régis Crelier <regis@google.com>
175 lines
4.1 KiB
Dart
175 lines
4.1 KiB
Dart
// Copyright (c) 2018, 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.bytecode.source_positions;
|
|
|
|
import 'dart:io' show BytesBuilder;
|
|
|
|
/// Maintains mapping between bytecode instructions and source positions.
|
|
class SourcePositions {
|
|
final Map<int, int> mapping = <int, int>{}; // PC -> fileOffset
|
|
int _lastPc = 0;
|
|
int _lastOffset = 0;
|
|
|
|
SourcePositions();
|
|
|
|
void add(int pc, int fileOffset) {
|
|
assert(pc > _lastPc);
|
|
assert(fileOffset >= 0);
|
|
if (fileOffset != _lastOffset) {
|
|
mapping[pc] = fileOffset;
|
|
_lastPc = pc;
|
|
_lastOffset = fileOffset;
|
|
}
|
|
}
|
|
|
|
List<int> toBytes() {
|
|
final write = new BufferedWriter();
|
|
write.writePackedUInt30(mapping.length);
|
|
final encodePC = new PackedUInt30DeltaEncoder();
|
|
final encodeOffset = new SLEB128DeltaEncoder();
|
|
mapping.forEach((int pc, int fileOffset) {
|
|
encodePC.write(write, pc);
|
|
encodeOffset.write(write, fileOffset);
|
|
});
|
|
return write.buffer.takeBytes();
|
|
}
|
|
|
|
SourcePositions.fromBytes(List<int> bytes) {
|
|
final reader = new BufferedReader(bytes);
|
|
final int length = reader.readPackedUInt30();
|
|
final decodePC = new PackedUInt30DeltaDecoder();
|
|
final decodeOffset = new SLEB128DeltaDecoder();
|
|
for (int i = 0; i < length; ++i) {
|
|
int pc = decodePC.read(reader);
|
|
int fileOffset = decodeOffset.read(reader);
|
|
add(pc, fileOffset);
|
|
}
|
|
}
|
|
|
|
@override
|
|
String toString() => mapping.toString();
|
|
|
|
Map<int, String> getBytecodeAnnotations() {
|
|
return mapping.map((int pc, int fileOffset) =>
|
|
new MapEntry(pc, 'source position $fileOffset'));
|
|
}
|
|
}
|
|
|
|
class BufferedWriter {
|
|
final BytesBuilder buffer = new BytesBuilder();
|
|
|
|
void writePackedUInt30(int value) {
|
|
if ((value >> 30) != 0) {
|
|
throw 'Value $value is out of range';
|
|
}
|
|
if (value < 0x80) {
|
|
buffer.addByte(value);
|
|
} else if (value < 0x4000) {
|
|
buffer.addByte((value >> 8) | 0x80);
|
|
buffer.addByte(value & 0xFF);
|
|
} else {
|
|
buffer.addByte((value >> 24) | 0xC0);
|
|
buffer.addByte((value >> 16) & 0xFF);
|
|
buffer.addByte((value >> 8) & 0xFF);
|
|
buffer.addByte(value & 0xFF);
|
|
}
|
|
}
|
|
|
|
void writeSLEB128(int value) {
|
|
bool last = false;
|
|
do {
|
|
int part = value & 0x7f;
|
|
value >>= 7;
|
|
if ((value == 0 && (part & 0x40) == 0) ||
|
|
(value == -1 && (part & 0x40) != 0)) {
|
|
last = true;
|
|
} else {
|
|
part |= 0x80;
|
|
}
|
|
buffer.addByte(part);
|
|
} while (!last);
|
|
}
|
|
}
|
|
|
|
class BufferedReader {
|
|
final List<int> _buffer;
|
|
int _pos = 0;
|
|
|
|
BufferedReader(this._buffer);
|
|
|
|
int readByte() => _buffer[_pos++];
|
|
|
|
int readPackedUInt30() {
|
|
var byte = readByte();
|
|
if (byte & 0x80 == 0) {
|
|
// 0xxxxxxx
|
|
return byte;
|
|
} else if (byte & 0x40 == 0) {
|
|
// 10xxxxxx
|
|
return ((byte & 0x3F) << 8) | readByte();
|
|
} else {
|
|
// 11xxxxxx
|
|
return ((byte & 0x3F) << 24) |
|
|
(readByte() << 16) |
|
|
(readByte() << 8) |
|
|
readByte();
|
|
}
|
|
}
|
|
|
|
int readSLEB128() {
|
|
int value = 0;
|
|
int shift = 0;
|
|
int part = 0;
|
|
do {
|
|
part = readByte();
|
|
value |= (part & 0x7f) << shift;
|
|
shift += 7;
|
|
} while ((part & 0x80) != 0);
|
|
const int kBitsPerInt = 64;
|
|
if ((shift < kBitsPerInt) && ((part & 0x40) != 0)) {
|
|
value |= (-1) << shift;
|
|
}
|
|
return value;
|
|
}
|
|
}
|
|
|
|
class PackedUInt30DeltaEncoder {
|
|
int _last = 0;
|
|
|
|
void write(BufferedWriter write, int value) {
|
|
write.writePackedUInt30(value - _last);
|
|
_last = value;
|
|
}
|
|
}
|
|
|
|
class PackedUInt30DeltaDecoder {
|
|
int _last = 0;
|
|
|
|
int read(BufferedReader reader) {
|
|
int value = reader.readPackedUInt30() + _last;
|
|
_last = value;
|
|
return value;
|
|
}
|
|
}
|
|
|
|
class SLEB128DeltaEncoder {
|
|
int _last = 0;
|
|
|
|
void write(BufferedWriter writer, int value) {
|
|
writer.writeSLEB128(value - _last);
|
|
_last = value;
|
|
}
|
|
}
|
|
|
|
class SLEB128DeltaDecoder {
|
|
int _last = 0;
|
|
|
|
int read(BufferedReader reader) {
|
|
int value = reader.readSLEB128() + _last;
|
|
_last = value;
|
|
return value;
|
|
}
|
|
}
|