Files
sdk/pkg/vm/lib/bytecode/source_positions.dart
T
Alexander Markov 9f49b47823 [vm/bytecode] Revise representation of objects and strings in bytecode
This is a major revamp of bytecode metadata format. Now bytecode has
its own serialization mechanisms.

This CL adds 'bytecode component' metadata, which contains bytecode
object table and string table. All references from bytecode (constant
pools) to libraries, classes, members, types and strings now have a new
format. References to frequently used objects are represented as indices
in object table, while rarely used objects are written inline.
This allows VM to cache frequently used objects while reading bytecode.

Representation of strings is aligned with VM - string characters are
stored in separate pools of one-byte and two-byte strings. This allows
VM to avoid UTF-8 decoding and extra copying.

Closure declarations are now explicit. Type parameters no longer require
enslosing scopes when reading/writing them.

Benchmarks:
GenKernelKernelReadAllBytecode (Intel Core i5) +29.84%
GenKernelKernelReadAllBytecode (Intel Xeon) +28.74%
Change-Id: I4b80009733a8f8c038264af74f97c4e094b9e311
Reviewed-on: https://dart-review.googlesource.com/c/85469
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
Reviewed-by: Zach Anderson <zra@google.com>
2018-12-03 19:08:42 +00:00

105 lines
2.7 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 'bytecode_serialization.dart' show BufferedWriter, BufferedReader;
/// 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;
}
}
void writeContents(BufferedWriter writer) {
writer.writePackedUInt30(mapping.length);
final encodePC = new PackedUInt30DeltaEncoder();
final encodeOffset = new SLEB128DeltaEncoder();
mapping.forEach((int pc, int fileOffset) {
encodePC.write(writer, pc);
encodeOffset.write(writer, fileOffset);
});
}
void write(BufferedWriter writer) {
// TODO(alexmarkov): write source positions in a separate section
BufferedWriter contentsWriter = new BufferedWriter.fromWriter(writer);
writeContents(contentsWriter);
final contents = contentsWriter.takeBytes();
writer.writePackedUInt30(contents.length);
writer.writeBytes(contents);
}
SourcePositions.read(BufferedReader reader) {
reader.readPackedUInt30(); // Contents length in 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 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;
}
}