[vm,dynamic_modules] Add RecordCoverage instruction.
The RecordCoverage instruction has an A/E encoding. The A argument is the type of coverage being recorded, whereas the E argument is the logical index into the coverage array for updating whether that source position has been hit. Also adds new metadata to the bytecode component for the coverage arrays associated with bytecode containing RecordCoverage instructions and a new runtime entry for lazily allocate the coverage array for an interpreted function when needed. The type of coverage is encoded in the RecordCoverage instruction, despite being redundant with the information in the coverage array, so that checking whether that type of coverage is currently enabled at runtime doesn't require either accessing the coverage array (which may be lazily allocated), forcing allocation of the coverage array just to discover that type of coverage is currently disabled, or reading the serialized bytecode component to avoid that forced allocation. ------ Other changes: Source reporting now treats unexecuted interpreted functions when not forcing compilation as if they were uncompiled native functions, so that the source report from running the same code gives the same result whether using the interpreter or the native compiler. Bytecode closures are no longer skipped in source reports. Previously any closure without a context scope was skipped, but bytecode closures don't have those. TEST=vm/cc/SourceReport_Coverage Cq-Include-Trybots: luci.dart.try:vm-dyn-linux-debug-x64-try,vm-aot-dyn-linux-debug-x64-try,vm-aot-dyn-linux-product-x64-try Change-Id: I7557e5dd4c98331c7ca2f5c867dd5f6d03e9d756 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/501520 Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
@@ -47,7 +47,7 @@ which reside in different sections such as libraries, classes, members, code, et
|
||||
```
|
||||
type BytecodeFile {
|
||||
UInt32 magic = 0x44424333; // 'DBC3'
|
||||
UInt32 formatVersion = 2;
|
||||
UInt32 formatVersion = 3;
|
||||
|
||||
// Descriptors of the sections below.
|
||||
// Each section has a fixed index in the descriptors array.
|
||||
@@ -69,6 +69,7 @@ type BytecodeFile {
|
||||
SourceFile[] sourceFiles;
|
||||
LineStarts[] lineStarts;
|
||||
LocalVariables[] localVariables;
|
||||
RecordedCoverageArray[] recordedCoverage;
|
||||
PackedObject[] annotations;
|
||||
}
|
||||
|
||||
@@ -604,7 +605,8 @@ Code section contains bodies of members (including field initializers).
|
||||
type Code {
|
||||
UInt flags = (hasExceptionsTable, hasSourcePositions, hasNullableFields,
|
||||
hasClosures, hasParameterFlags, hasForwardingStubTarget,
|
||||
hasDefaultFunctionTypeArgs, hasLocalVariables)
|
||||
hasDefaultFunctionTypeArgs, hasLocalVariables,
|
||||
hasRecordedCoverage)
|
||||
|
||||
if hasParameterFlags
|
||||
// For all parameters: (isCovariant, isCovariantByClass)
|
||||
@@ -635,6 +637,11 @@ type Code {
|
||||
// Offset of LocalVariables in ‘localVariables’ section of BytecodeFile.
|
||||
UInt localVariablesOffset;
|
||||
|
||||
if hasRecordedCoverage
|
||||
// Offset of RecordedCoverageArray in ‘recordedCoverage’ section of
|
||||
// BytecodeFile.
|
||||
Uint recordedCoverageOffset;
|
||||
|
||||
if hasNullableFields
|
||||
List<PackedObject> nullableFields;
|
||||
|
||||
@@ -681,7 +688,8 @@ type ClosureDeclaration {
|
||||
|
||||
type ClosureCode {
|
||||
UInt flags = (hasExceptionsTable, hasSourcePositions, hasLocalVariables,
|
||||
capturesOnlyFinalNotLateVars, hasLocalFunctionId)
|
||||
capturesOnlyFinalNotLateVars, hasLocalFunctionId,
|
||||
hasRecordedCoverage)
|
||||
|
||||
if hasLocalFunctionId
|
||||
UInt localFunctionId;
|
||||
@@ -699,6 +707,11 @@ type ClosureCode {
|
||||
if hasLocalVariables
|
||||
// Offset of LocalVariables in ‘localVariables’ section of BytecodeFile.
|
||||
UInt localVariablesOffset;
|
||||
|
||||
if hasRecordedCoverage
|
||||
// Offset of RecordedCoverageArray in ‘recordedCoverage’ section of
|
||||
// BytecodeFile.
|
||||
UInt recordedCoverageOffset;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -968,6 +981,28 @@ type ContextVariable extends LocalVariableEntry {
|
||||
}
|
||||
```
|
||||
|
||||
### Recorded coverage
|
||||
|
||||
```
|
||||
type RecordedCoverageArray {
|
||||
UInt numEntries;
|
||||
// Unordered encoded list of entries.
|
||||
RecordedCoverageEntry[numEntries] entries;
|
||||
}
|
||||
|
||||
type RecordedCoverageEntry = {
|
||||
// The index of the entry's type in the RecordedEntryType enum.
|
||||
UInt type;
|
||||
// Delta-encoded file offset.
|
||||
SLEB128 fileOffset;
|
||||
}
|
||||
|
||||
enum RecordedCoverageType = {
|
||||
regular = 0,
|
||||
branchTarget = 1;
|
||||
}
|
||||
```
|
||||
|
||||
## Bytecode instructions
|
||||
|
||||
### Execution state
|
||||
@@ -1445,3 +1480,14 @@ Store object SP[0] into the element [D] of closure SP[-1].
|
||||
|
||||
No-op. Provides a unique PC offset to ensure an emitted source position is not
|
||||
overwritten by a different source position emitted by the next instruction.
|
||||
|
||||
#### RecordCoverage A, E
|
||||
|
||||
Records coverage. [A] is the index in the RecordedCoverageType enum for the type
|
||||
of coverage being recorded, and [E] is the index of the entry in
|
||||
the RecordedCoverageArray.
|
||||
|
||||
The information in [A] is redundant, but allows the interpreter to check to see
|
||||
if the isolate group is currently recorded that type of coverage without needing
|
||||
either to iterate over the serialized RecordedCoverageArray or to index into the
|
||||
bytecode's coverage array, which may be lazily allocated.
|
||||
Reference in New Issue
Block a user