fix code coverage
This commit is contained in:
parent
1760913909
commit
f8b573c135
52
runtime/instruction_size.cpp
Normal file
52
runtime/instruction_size.cpp
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#include "arch.hpp"
|
||||||
|
#include "vm.hpp"
|
||||||
|
|
||||||
|
using namespace sliger;
|
||||||
|
|
||||||
|
size_t VM::instruction_size(size_t i) const
|
||||||
|
{
|
||||||
|
switch (static_cast<Op>(this->program.at(i))) {
|
||||||
|
case Op::Nop:
|
||||||
|
case Op::PushNull:
|
||||||
|
return 1;
|
||||||
|
case Op::PushInt:
|
||||||
|
case Op::PushBool:
|
||||||
|
return 2;
|
||||||
|
case Op::PushString: {
|
||||||
|
auto string_length = this->program.at(i + 1);
|
||||||
|
return 2 + string_length;
|
||||||
|
}
|
||||||
|
case Op::PushPtr:
|
||||||
|
return 2;
|
||||||
|
case Op::Pop:
|
||||||
|
return 1;
|
||||||
|
case Op::ReserveStatic:
|
||||||
|
case Op::LoadStatic:
|
||||||
|
case Op::StoreStatic:
|
||||||
|
case Op::LoadLocal:
|
||||||
|
case Op::StoreLocal:
|
||||||
|
case Op::Call:
|
||||||
|
return 2;
|
||||||
|
case Op::Return:
|
||||||
|
case Op::Jump:
|
||||||
|
case Op::JumpIfTrue:
|
||||||
|
return 1;
|
||||||
|
case Op::Builtin:
|
||||||
|
return 2;
|
||||||
|
case Op::Add:
|
||||||
|
case Op::Subtract:
|
||||||
|
case Op::Multiply:
|
||||||
|
case Op::Divide:
|
||||||
|
case Op::Remainder:
|
||||||
|
case Op::Equal:
|
||||||
|
case Op::LessThan:
|
||||||
|
case Op::And:
|
||||||
|
case Op::Or:
|
||||||
|
case Op::Xor:
|
||||||
|
case Op::Not:
|
||||||
|
return 1;
|
||||||
|
case Op::SourceMap:
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
@ -451,7 +451,8 @@ void VM::run_file_builtin(Builtin builtin_id)
|
|||||||
auto filename = stack_pop().as_string().value;
|
auto filename = stack_pop().as_string().value;
|
||||||
FILE* fp = std::fopen(filename.c_str(), mode.c_str());
|
FILE* fp = std::fopen(filename.c_str(), mode.c_str());
|
||||||
if (fp == nullptr) {
|
if (fp == nullptr) {
|
||||||
std::cerr << std::format("error: could not open file '{}'\n", filename);
|
std::cerr << std::format(
|
||||||
|
"error: could not open file '{}'\n", filename);
|
||||||
std::exit(1);
|
std::exit(1);
|
||||||
}
|
}
|
||||||
auto file_id = this->file_id_counter;
|
auto file_id = this->file_id_counter;
|
||||||
@ -568,6 +569,14 @@ auto VM::stack_repr_string(size_t max_items) const -> std::string
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void VM::assert_program_has(size_t count)
|
||||||
|
{
|
||||||
|
if (this->pc + count > program.size()) {
|
||||||
|
std::cerr << std::format("malformed program, pc = {}", this->pc);
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void VM::assert_fn_stack_has(size_t count)
|
void VM::assert_fn_stack_has(size_t count)
|
||||||
{
|
{
|
||||||
if (this->stack.size() - this->bp < count) {
|
if (this->stack.size() - this->bp < count) {
|
||||||
@ -583,11 +592,3 @@ void VM::assert_stack_has(size_t count)
|
|||||||
std::exit(1);
|
std::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VM::assert_program_has(size_t count)
|
|
||||||
{
|
|
||||||
if (this->pc + count > program.size()) {
|
|
||||||
std::cerr << std::format("malformed program, pc = {}", this->pc);
|
|
||||||
std::exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace sliger {
|
namespace sliger {
|
||||||
@ -108,6 +109,11 @@ struct CCPosEntry {
|
|||||||
|
|
||||||
class CodeCoverageBuilder : public json::ToAndFromJson {
|
class CodeCoverageBuilder : public json::ToAndFromJson {
|
||||||
public:
|
public:
|
||||||
|
inline void make_sure_entry_exists(SourcePos pos)
|
||||||
|
{
|
||||||
|
find_or_create_entry(pos);
|
||||||
|
}
|
||||||
|
|
||||||
/// call when leaving a source location
|
/// call when leaving a source location
|
||||||
inline void report_cover(SourcePos pos)
|
inline void report_cover(SourcePos pos)
|
||||||
{
|
{
|
||||||
@ -166,8 +172,19 @@ public:
|
|||||||
return json::to_json(this->flame_graph);
|
return json::to_json(this->flame_graph);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto code_coverage_json() const -> std::string
|
inline auto code_coverage_json() -> std::string
|
||||||
{
|
{
|
||||||
|
for (size_t i = 0; i < this->program.size(); ++i) {
|
||||||
|
if (this->program.at(i) == std::to_underlying(Op::SourceMap)
|
||||||
|
&& this->program.size() - 1 - i >= 3) {
|
||||||
|
auto index = static_cast<int32_t>(this->program.at(i + 1));
|
||||||
|
auto line = static_cast<int32_t>(this->program.at(i + 2));
|
||||||
|
auto col = static_cast<int32_t>(this->program.at(i + 3));
|
||||||
|
this->code_coverage.make_sure_entry_exists(
|
||||||
|
{ index, line, col });
|
||||||
|
}
|
||||||
|
i += instruction_size(i);
|
||||||
|
}
|
||||||
return json::to_json(this->code_coverage);
|
return json::to_json(this->code_coverage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,6 +240,7 @@ private:
|
|||||||
{
|
{
|
||||||
return this->stack.at(this->bp + idx);
|
return this->stack.at(this->bp + idx);
|
||||||
}
|
}
|
||||||
|
void assert_program_has(size_t count);
|
||||||
void assert_fn_stack_has(size_t count);
|
void assert_fn_stack_has(size_t count);
|
||||||
void assert_stack_has(size_t count);
|
void assert_stack_has(size_t count);
|
||||||
inline void stack_push(Value&& value) { this->stack.push_back(value); }
|
inline void stack_push(Value&& value) { this->stack.push_back(value); }
|
||||||
@ -233,7 +251,7 @@ private:
|
|||||||
this->stack.pop_back();
|
this->stack.pop_back();
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
void assert_program_has(size_t count);
|
size_t instruction_size(size_t i) const;
|
||||||
|
|
||||||
VMOpts opts;
|
VMOpts opts;
|
||||||
uint32_t pc = 0;
|
uint32_t pc = 0;
|
||||||
|
@ -97,21 +97,6 @@ export function loadCodeCoverage(
|
|||||||
elements.push(span);
|
elements.push(span);
|
||||||
col += 1;
|
col += 1;
|
||||||
}
|
}
|
||||||
function positionInBox(
|
|
||||||
position: [number, number],
|
|
||||||
boundingRect: {
|
|
||||||
left: number;
|
|
||||||
top: number;
|
|
||||||
right: number;
|
|
||||||
bottom: number;
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
const [x, y] = position;
|
|
||||||
const outside = x < boundingRect.left ||
|
|
||||||
x >= boundingRect.right || y < boundingRect.top ||
|
|
||||||
y >= boundingRect.bottom;
|
|
||||||
return !outside;
|
|
||||||
}
|
|
||||||
container.append(...elements);
|
container.append(...elements);
|
||||||
document.addEventListener("mousemove", (event) => {
|
document.addEventListener("mousemove", (event) => {
|
||||||
const [x, y] = [event.clientX, event.clientY];
|
const [x, y] = [event.clientX, event.clientY];
|
||||||
@ -146,3 +131,19 @@ export function loadCodeCoverage(
|
|||||||
});
|
});
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function positionInBox(
|
||||||
|
position: [number, number],
|
||||||
|
boundingRect: {
|
||||||
|
left: number;
|
||||||
|
top: number;
|
||||||
|
right: number;
|
||||||
|
bottom: number;
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
const [x, y] = position;
|
||||||
|
const outside = x < boundingRect.left ||
|
||||||
|
x >= boundingRect.right || y < boundingRect.top ||
|
||||||
|
y >= boundingRect.bottom;
|
||||||
|
return !outside;
|
||||||
|
}
|
||||||
|
@ -57,6 +57,26 @@ function sourceCode(view: Element, codeData: string) {
|
|||||||
view.replaceChildren(outerContainer);
|
view.replaceChildren(outerContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createRadio(
|
||||||
|
id: string,
|
||||||
|
content: string,
|
||||||
|
checked: boolean,
|
||||||
|
): [HTMLDivElement, HTMLInputElement] {
|
||||||
|
const label = document.createElement("label");
|
||||||
|
label.htmlFor = id;
|
||||||
|
label.innerText = content;
|
||||||
|
const input = document.createElement("input");
|
||||||
|
input.id = id;
|
||||||
|
input.name = "coverage-radio";
|
||||||
|
input.type = "radio";
|
||||||
|
input.hidden = true;
|
||||||
|
input.checked = checked;
|
||||||
|
const container = document.createElement("div");
|
||||||
|
container.classList.add("coverage-radio-group");
|
||||||
|
container.append(input, label);
|
||||||
|
return [container, input];
|
||||||
|
}
|
||||||
|
|
||||||
async function codeCoverage(view: Element, codeData: string) {
|
async function codeCoverage(view: Element, codeData: string) {
|
||||||
const codeCoverageData = await data.codeCoverageData();
|
const codeCoverageData = await data.codeCoverageData();
|
||||||
|
|
||||||
@ -66,25 +86,6 @@ async function codeCoverage(view: Element, codeData: string) {
|
|||||||
const innerContainer = document.createElement("div");
|
const innerContainer = document.createElement("div");
|
||||||
innerContainer.classList.add("code-container-inner");
|
innerContainer.classList.add("code-container-inner");
|
||||||
|
|
||||||
function createRadio(
|
|
||||||
id: string,
|
|
||||||
content: string,
|
|
||||||
checked: boolean,
|
|
||||||
): [HTMLDivElement, HTMLInputElement] {
|
|
||||||
const label = document.createElement("label");
|
|
||||||
label.htmlFor = id;
|
|
||||||
label.innerText = content;
|
|
||||||
const input = document.createElement("input");
|
|
||||||
input.id = id;
|
|
||||||
input.name = "coverage-radio";
|
|
||||||
input.type = "radio";
|
|
||||||
input.hidden = true;
|
|
||||||
input.checked = checked;
|
|
||||||
const container = document.createElement("div");
|
|
||||||
container.classList.add("coverage-radio-group");
|
|
||||||
container.append(input, label);
|
|
||||||
return [container, input];
|
|
||||||
}
|
|
||||||
const [perfGroup, perfInput] = createRadio(
|
const [perfGroup, perfInput] = createRadio(
|
||||||
"performance-coverage",
|
"performance-coverage",
|
||||||
"Performance view",
|
"Performance view",
|
||||||
|
@ -159,6 +159,7 @@ main #cover {
|
|||||||
.coverage-radio {
|
.coverage-radio {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.coverage-radio-group {
|
.coverage-radio-group {
|
||||||
@ -166,6 +167,7 @@ main #cover {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
|
max-width: max-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
.coverage-radio-group label {
|
.coverage-radio-group label {
|
||||||
@ -173,6 +175,8 @@ main #cover {
|
|||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border: 2px solid var(--code-status);
|
border: 2px solid var(--code-status);
|
||||||
|
width: 280px;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.coverage-radio-group input:checked ~ label {
|
.coverage-radio-group input:checked ~ label {
|
||||||
|
Loading…
Reference in New Issue
Block a user