mirror of
				https://git.sfja.dk/Mikkel/slige.git
				synced 2025-11-04 15:58:16 +00:00 
			
		
		
		
	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