[vm] Change the encoding of token positions in the coverage array

The source report RPC needs to be able to distinguish branch coverage vs
normal coverage token positions. So encode normal positions as 2 * pos
and branch positions as 2 * pos + 1.

TEST=CI

Change-Id: I247796d1eb4c97947f9b38aa56bc318ecea09425
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/224320
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Liam Appelbe <liama@google.com>
This commit is contained in:
Liam Appelbe 2021-12-15 23:12:19 +00:00 committed by Commit Bot
parent 9aedcb47b0
commit a9b33cfcd2
5 changed files with 57 additions and 21 deletions

View file

@ -1244,33 +1244,44 @@ Fragment BaseFlowGraphBuilder::MathUnary(MathUnaryInstr::MathUnaryKind kind) {
}
Fragment BaseFlowGraphBuilder::RecordCoverage(TokenPosition position) {
return RecordCoverageImpl(position, false /** is_branch_coverage **/);
}
Fragment BaseFlowGraphBuilder::RecordBranchCoverage(TokenPosition position) {
return RecordCoverageImpl(position, true /** is_branch_coverage **/);
}
Fragment BaseFlowGraphBuilder::RecordCoverageImpl(TokenPosition position,
bool is_branch_coverage) {
Fragment instructions;
if (SupportsCoverage()) {
const intptr_t coverage_index = GetCoverageIndexFor(position);
instructions <<= new (Z) RecordCoverageInstr(
coverage_array(), coverage_index, InstructionSource(position));
}
if (!SupportsCoverage()) return instructions;
if (!position.IsReal()) return instructions;
if (is_branch_coverage && !IG->branch_coverage()) return instructions;
const intptr_t coverage_index =
GetCoverageIndexFor(position.EncodeCoveragePosition(is_branch_coverage));
instructions <<= new (Z) RecordCoverageInstr(coverage_array(), coverage_index,
InstructionSource(position));
return instructions;
}
intptr_t BaseFlowGraphBuilder::GetCoverageIndexFor(TokenPosition token_pos) {
intptr_t BaseFlowGraphBuilder::GetCoverageIndexFor(intptr_t encoded_position) {
if (coverage_array_.IsNull()) {
// We have not yet created coverage_array, this is the first time
// we are building the graph for this function. Collect coverage
// positions.
// We have not yet created coverage_array, this is the first time we are
// building the graph for this function. Collect coverage positions.
for (intptr_t i = 0; i < coverage_array_positions_.length(); i++) {
if (coverage_array_positions_.At(i) == token_pos) {
if (coverage_array_positions_.At(i) == encoded_position) {
return 2 * i + 1;
}
}
const auto index = 2 * coverage_array_positions_.length() + 1;
coverage_array_positions_.Add(token_pos);
coverage_array_positions_.Add(encoded_position);
return index;
}
for (intptr_t i = 0; i < coverage_array_.Length(); i += 2) {
if (TokenPosition::Deserialize(Smi::Value(
static_cast<SmiPtr>(coverage_array_.At(i)))) == token_pos) {
if (Smi::Value(static_cast<SmiPtr>(coverage_array_.At(i))) ==
encoded_position) {
return i + 1;
}
}
@ -1294,7 +1305,7 @@ void BaseFlowGraphBuilder::FinalizeCoverageArray() {
Smi& value = Smi::Handle();
for (intptr_t i = 0; i < coverage_array_positions_.length(); i++) {
value = Smi::New(coverage_array_positions_[i].Serialize());
value = Smi::New(coverage_array_positions_[i]);
coverage_array_.SetAt(2 * i, value);
value = Smi::New(0); // no coverage recorded.
coverage_array_.SetAt(2 * i + 1, value);

View file

@ -166,7 +166,6 @@ class BaseFlowGraphBuilder {
const Array& coverage_array() const { return coverage_array_; }
intptr_t GetCoverageIndexFor(TokenPosition token_pos);
void FinalizeCoverageArray();
Fragment LoadField(const Field& field, bool calls_initializer);
@ -473,6 +472,7 @@ class BaseFlowGraphBuilder {
// Records coverage for this position, if the current VM mode supports it.
Fragment RecordCoverage(TokenPosition position);
Fragment RecordBranchCoverage(TokenPosition position);
// Returns whether this function has a saved arguments descriptor array.
bool has_saved_args_desc_array() {
@ -487,6 +487,8 @@ class BaseFlowGraphBuilder {
protected:
intptr_t AllocateBlockId() { return ++last_used_block_id_; }
Fragment RecordCoverageImpl(TokenPosition position, bool is_branch_coverage);
intptr_t GetCoverageIndexFor(intptr_t encoded_position);
const ParsedFunction* parsed_function_;
const Function& function_;
@ -507,7 +509,7 @@ class BaseFlowGraphBuilder {
const bool inlining_unchecked_entry_;
const Array& saved_args_desc_array_;
GrowableArray<TokenPosition> coverage_array_positions_;
GrowableArray<intptr_t> coverage_array_positions_;
Array& coverage_array_;
friend class StreamingFlowGraphBuilder;

View file

@ -346,11 +346,14 @@ void SourceReport::PrintCoverageData(JSONObject* jsobj,
const Array& coverage_array = Array::Handle(function.GetCoverageArray());
if (!coverage_array.IsNull()) {
for (intptr_t i = 0; i < coverage_array.Length(); i += 2) {
const TokenPosition token_pos = TokenPosition::Deserialize(
Smi::Value(Smi::RawCast(coverage_array.At(i))));
const bool was_executed =
Smi::Value(Smi::RawCast(coverage_array.At(i + 1))) != 0;
update_coverage(token_pos, was_executed);
bool is_branch_coverage;
const TokenPosition token_pos = TokenPosition::DecodeCoveragePosition(
Smi::Value(Smi::RawCast(coverage_array.At(i))), &is_branch_coverage);
if (!is_branch_coverage) {
const bool was_executed =
Smi::Value(Smi::RawCast(coverage_array.At(i + 1))) != 0;
update_coverage(token_pos, was_executed);
}
}
}

View file

@ -21,6 +21,19 @@ int32_t TokenPosition::Serialize() const {
return static_cast<int32_t>(value_);
}
intptr_t TokenPosition::EncodeCoveragePosition(bool is_branch_coverage) {
// Normal coverage positions are encoded as 2 * pos, and branch coverage are
// encoded as 2 * pos + 1.
intptr_t encoded_position = 2 * static_cast<intptr_t>(value_);
return is_branch_coverage ? encoded_position + 1 : encoded_position;
}
TokenPosition TokenPosition::DecodeCoveragePosition(intptr_t encoded_position,
bool* is_branch_coverage) {
*is_branch_coverage = ((encoded_position % 2) == 1);
return TokenPosition(encoded_position / 2);
}
#define DEFINE_VALUES(name, value) \
const TokenPosition TokenPosition::k##name(value);
SENTINEL_TOKEN_DESCRIPTORS(DEFINE_VALUES);

View file

@ -202,6 +202,13 @@ class TokenPosition {
return TokenPosition((kLastPos - 1) - value);
}
// Encode the token position for storage in the coverage array.
intptr_t EncodeCoveragePosition(bool is_branch_coverage);
// Decode a token position that was stored in the coverage array.
static TokenPosition DecodeCoveragePosition(intptr_t encoded_position,
bool* is_branch_coverage);
const char* ToCString() const;
private: