• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ArkScript-lang / Ark / 14647441324

24 Apr 2025 05:07PM UTC coverage: 83.165% (+2.7%) from 80.417%
14647441324

push

github

SuperFola
feat(vm): compressing identical traces when displaying the stacktrace of an error

21 of 21 new or added lines in 1 file covered. (100.0%)

270 existing lines in 10 files now uncovered.

6580 of 7912 relevant lines covered (83.16%)

79046.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

47.81
/src/arkreactor/Compiler/BytecodeReader.cpp
1
#include <Ark/Compiler/BytecodeReader.hpp>
2

3
#include <Ark/Compiler/Instructions.hpp>
4
#include <Ark/Builtins/Builtins.hpp>
5

6
#include <unordered_map>
7
#include <Proxy/Picosha2.hpp>
8
#include <Ark/Compiler/Serialization/IEEE754Serializer.hpp>
9
#include <Ark/Compiler/Serialization/IntegerSerializer.hpp>
10
#include <fmt/core.h>
11
#include <fmt/color.h>
12

13
namespace Ark
14
{
15
    using namespace Ark::internal;
16

17
    void BytecodeReader::feed(const bytecode_t& bytecode)
312✔
18
    {
312✔
19
        m_bytecode = bytecode;
312✔
20
    }
312✔
21

22
    void BytecodeReader::feed(const std::string& file)
×
23
    {
×
24
        std::ifstream ifs(file, std::ios::binary | std::ios::ate);
×
25
        if (!ifs.good())
×
26
            throw std::runtime_error(fmt::format("[BytecodeReader] Couldn't open file '{}'", file));
×
27

28
        const auto pos = ifs.tellg();
×
29
        // reserve appropriate number of bytes
30
        std::vector<char> temp(static_cast<std::size_t>(pos));
×
31
        ifs.seekg(0, std::ios::beg);
×
32
        ifs.read(&temp[0], pos);
×
33
        ifs.close();
×
34

35
        m_bytecode = bytecode_t(static_cast<std::size_t>(pos));
×
36
        for (std::size_t i = 0; i < static_cast<std::size_t>(pos); ++i)
×
37
            m_bytecode[i] = static_cast<uint8_t>(temp[i]);
×
38
    }
×
39

40
    bool BytecodeReader::checkMagic() const
1,096✔
41
    {
1,096✔
42
        return m_bytecode.size() >= bytecode::Magic.size() &&
2,191✔
43
            m_bytecode[0] == bytecode::Magic[0] &&
1,095✔
44
            m_bytecode[1] == bytecode::Magic[1] &&
896✔
45
            m_bytecode[2] == bytecode::Magic[2] &&
1,792✔
46
            m_bytecode[3] == bytecode::Magic[3];
896✔
47
    }
UNCOV
48

×
49
    Version BytecodeReader::version() const
112✔
50
    {
112✔
51
        if (!checkMagic() || m_bytecode.size() < bytecode::Magic.size() + bytecode::Version.size())
112✔
52
            return Version { 0, 0, 0 };
×
53

54
        return Version {
448✔
55
            .major = static_cast<uint16_t>((m_bytecode[4] << 8) + m_bytecode[5]),
112✔
56
            .minor = static_cast<uint16_t>((m_bytecode[6] << 8) + m_bytecode[7]),
112✔
57
            .patch = static_cast<uint16_t>((m_bytecode[8] << 8) + m_bytecode[9])
112✔
58
        };
59
    }
112✔
60

61
    unsigned long long BytecodeReader::timestamp() const
1✔
62
    {
1✔
63
        // 4 (ark\0) + version (2 bytes / number) + timestamp = 18 bytes
64
        if (!checkMagic() || m_bytecode.size() < bytecode::HeaderSize)
1✔
65
            return 0;
×
66

67
        // reading the timestamp in big endian
68
        using timestamp_t = unsigned long long;
69
        return (static_cast<timestamp_t>(m_bytecode[10]) << 56) +
3✔
70
            (static_cast<timestamp_t>(m_bytecode[11]) << 48) +
2✔
71
            (static_cast<timestamp_t>(m_bytecode[12]) << 40) +
2✔
72
            (static_cast<timestamp_t>(m_bytecode[13]) << 32) +
2✔
73
            (static_cast<timestamp_t>(m_bytecode[14]) << 24) +
2✔
74
            (static_cast<timestamp_t>(m_bytecode[15]) << 16) +
2✔
75
            (static_cast<timestamp_t>(m_bytecode[16]) << 8) +
2✔
76
            static_cast<timestamp_t>(m_bytecode[17]);
1✔
77
    }
1✔
78

79
    std::vector<unsigned char> BytecodeReader::sha256() const
112✔
80
    {
112✔
81
        if (!checkMagic() || m_bytecode.size() < bytecode::HeaderSize + picosha2::k_digest_size)
112✔
82
            return {};
×
83

84
        std::vector<unsigned char> sha(picosha2::k_digest_size);
112✔
85
        for (std::size_t i = 0; i < picosha2::k_digest_size; ++i)
3,696✔
86
            sha[i] = m_bytecode[bytecode::HeaderSize + i];
3,584✔
87
        return sha;
112✔
88
    }
224✔
89

90
    Symbols BytecodeReader::symbols() const
112✔
91
    {
112✔
92
        if (!checkMagic() || m_bytecode.size() < bytecode::HeaderSize + picosha2::k_digest_size ||
224✔
93
            m_bytecode[bytecode::HeaderSize + picosha2::k_digest_size] != SYM_TABLE_START)
112✔
94
            return {};
×
95

96
        std::size_t i = bytecode::HeaderSize + picosha2::k_digest_size + 1;
112✔
97
        const uint16_t size = readNumber(i);
112✔
98
        i++;
112✔
99

100
        Symbols block;
112✔
101
        block.start = bytecode::HeaderSize + picosha2::k_digest_size;
112✔
102
        block.symbols.reserve(size);
112✔
103

104
        for (uint16_t j = 0; j < size; ++j)
2,625✔
105
        {
106
            std::string content;
2,513✔
107
            while (m_bytecode[i] != 0)
25,445✔
108
                content.push_back(static_cast<char>(m_bytecode[i++]));
22,932✔
109
            i++;
2,513✔
110

111
            block.symbols.push_back(content);
2,513✔
112
        }
2,513✔
113

114
        block.end = i;
112✔
115
        return block;
112✔
116
    }
112✔
117

118
    Values BytecodeReader::values(const Symbols& symbols) const
112✔
119
    {
112✔
120
        if (!checkMagic())
112✔
121
            return {};
×
122

123
        std::size_t i = symbols.end;
112✔
124
        if (m_bytecode[i] != VAL_TABLE_START)
112✔
125
            return {};
×
126
        i++;
112✔
127

128
        const uint16_t size = readNumber(i);
112✔
129
        i++;
112✔
130
        Values block;
112✔
131
        block.start = symbols.end;
112✔
132
        block.values.reserve(size);
112✔
133

134
        for (uint16_t j = 0; j < size; ++j)
3,143✔
135
        {
136
            const uint8_t type = m_bytecode[i];
3,031✔
137
            i++;
3,031✔
138

139
            if (type == NUMBER_TYPE)
3,031✔
140
            {
141
                auto exp = deserializeLE<decltype(ieee754::DecomposedDouble::exponent)>(
1,142✔
142
                    m_bytecode.begin() + static_cast<std::vector<uint8_t>::difference_type>(i), m_bytecode.end());
571✔
143
                i += sizeof(decltype(exp));
571✔
144
                auto mant = deserializeLE<decltype(ieee754::DecomposedDouble::mantissa)>(
1,142✔
145
                    m_bytecode.begin() + static_cast<std::vector<uint8_t>::difference_type>(i), m_bytecode.end());
571✔
146
                i += sizeof(decltype(mant));
571✔
147

148
                const ieee754::DecomposedDouble d { exp, mant };
571✔
149
                double val = ieee754::deserialize(d);
571✔
150
                block.values.emplace_back(val);
571✔
151
            }
571✔
152
            else if (type == STRING_TYPE)
2,460✔
153
            {
154
                std::string val;
1,194✔
155
                while (m_bytecode[i] != 0)
21,701✔
156
                    val.push_back(static_cast<char>(m_bytecode[i++]));
20,507✔
157
                block.values.emplace_back(val);
1,194✔
158
            }
1,194✔
159
            else if (type == FUNC_TYPE)
1,266✔
160
            {
161
                const uint16_t addr = readNumber(i);
1,266✔
162
                i++;
1,266✔
163
                block.values.emplace_back(addr);
1,266✔
164
            }
1,266✔
165
            else
166
                throw std::runtime_error(fmt::format("Unknown value type: {:x}", type));
×
167
            i++;
3,031✔
168
        }
3,031✔
169

170
        block.end = i;
112✔
171
        return block;
112✔
172
    }
112✔
173

174
    Filenames BytecodeReader::filenames(const Ark::Values& values) const
112✔
175
    {
112✔
176
        if (!checkMagic())
112✔
177
            return {};
×
178

179
        std::size_t i = values.end;
112✔
180
        if (m_bytecode[i] != FILENAMES_TABLE_START)
112✔
UNCOV
181
            return {};
×
182
        i++;
112✔
183

184
        const uint16_t size = readNumber(i);
112✔
185
        i++;
112✔
186

187
        Filenames block;
112✔
188
        block.start = values.end;
112✔
189
        block.filenames.reserve(size);
112✔
190

191
        for (uint16_t j = 0; j < size; ++j)
311✔
192
        {
193
            std::string val;
199✔
194
            while (m_bytecode[i] != 0)
14,752✔
195
                val.push_back(static_cast<char>(m_bytecode[i++]));
14,553✔
196
            block.filenames.emplace_back(val);
199✔
197
            i++;
199✔
198
        }
199✔
199

200
        block.end = i;
112✔
201
        return block;
112✔
202
    }
112✔
203

204
    InstLocations BytecodeReader::instLocations(const Ark::Filenames& filenames) const
112✔
205
    {
112✔
206
        if (!checkMagic())
112✔
UNCOV
207
            return {};
×
208

209
        std::size_t i = filenames.end;
112✔
210
        if (m_bytecode[i] != INST_LOC_TABLE_START)
112✔
UNCOV
211
            return {};
×
212
        i++;
112✔
213

214
        const uint16_t size = readNumber(i);
112✔
215
        i++;
112✔
216

217
        InstLocations block;
112✔
218
        block.start = filenames.end;
112✔
219
        block.locations.reserve(size);
112✔
220

221
        for (uint16_t j = 0; j < size; ++j)
8,595✔
222
        {
223
            auto pp = readNumber(i);
8,483✔
224
            i++;
8,483✔
225

226
            auto ip = readNumber(i);
8,483✔
227
            i++;
8,483✔
228

229
            auto file_id = readNumber(i);
8,483✔
230
            i++;
8,483✔
231

232
            auto line = deserializeBE<uint32_t>(
16,966✔
233
                m_bytecode.begin() + static_cast<std::vector<uint8_t>::difference_type>(i), m_bytecode.end());
8,483✔
234
            i += 4;
8,483✔
235

236
            block.locations.push_back(
8,483✔
237
                { .page_pointer = pp,
33,932✔
238
                  .inst_pointer = ip,
8,483✔
239
                  .filename_id = file_id,
8,483✔
240
                  .line = line });
8,483✔
241
        }
8,483✔
242

243
        block.end = i;
112✔
244
        return block;
112✔
245
    }
112✔
246

247
    Code BytecodeReader::code(const InstLocations& instLocations) const
112✔
248
    {
112✔
249
        if (!checkMagic())
112✔
UNCOV
250
            return {};
×
251

252
        std::size_t i = instLocations.end;
112✔
253

254
        Code block;
112✔
255
        block.start = i;
112✔
256

257
        while (m_bytecode[i] == CODE_SEGMENT_START)
1,378✔
258
        {
259
            i++;
1,378✔
260
            const std::size_t size = readNumber(i) * 4;
1,378✔
261
            i++;
1,378✔
262

263
            block.pages.emplace_back().reserve(size);
1,378✔
264
            for (std::size_t j = 0; j < size; ++j)
155,998✔
265
                block.pages.back().push_back(m_bytecode[i++]);
154,620✔
266

267
            if (i == m_bytecode.size())
1,378✔
268
                break;
112✔
269
        }
1,378✔
270

271
        return block;
112✔
272
    }
112✔
273

274
    void BytecodeReader::display(const BytecodeSegment segment,
×
275
                                 const std::optional<uint16_t> sStart,
276
                                 const std::optional<uint16_t> sEnd,
277
                                 const std::optional<uint16_t> cPage) const
278
    {
×
UNCOV
279
        if (!checkMagic())
×
280
        {
UNCOV
281
            fmt::println("Invalid format");
×
282
            return;
×
283
        }
284

285
        auto [major, minor, patch] = version();
×
UNCOV
286
        fmt::println("Version:   {}.{}.{}", major, minor, patch);
×
287
        fmt::println("Timestamp: {}", timestamp());
×
288
        fmt::print("SHA256:    ");
×
UNCOV
289
        for (const auto sha = sha256(); unsigned char h : sha)
×
290
            fmt::print("{:02x}", h);
×
291
        fmt::print("\n\n");
×
292

293
        // reading the different tables, one after another
294

UNCOV
295
        if ((sStart.has_value() && !sEnd.has_value()) || (!sStart.has_value() && sEnd.has_value()))
×
296
        {
297
            fmt::print(fmt::fg(fmt::color::red), "Both start and end parameter need to be provided together\n");
×
UNCOV
298
            return;
×
299
        }
300
        if (sStart.has_value() && sEnd.has_value() && sStart.value() >= sEnd.value())
×
301
        {
302
            fmt::print(fmt::fg(fmt::color::red), "Invalid slice start and end arguments\n");
×
303
            return;
×
304
        }
305

306
        const auto syms = symbols();
×
307
        const auto vals = values(syms);
×
308
        const auto files = filenames(vals);
×
309
        const auto inst_locs = instLocations(files);
×
UNCOV
310
        const auto code_block = code(inst_locs);
×
311

312
        // symbols table
313
        {
UNCOV
314
            std::size_t size = syms.symbols.size();
×
315
            std::size_t sliceSize = size;
×
UNCOV
316
            bool showSym = (segment == BytecodeSegment::All || segment == BytecodeSegment::Symbols);
×
317

UNCOV
318
            if (showSym && sStart.has_value() && sEnd.has_value() && (sStart.value() > size || sEnd.value() > size))
×
319
                fmt::print(fmt::fg(fmt::color::red), "Slice start or end can't be greater than the segment size: {}\n", size);
×
UNCOV
320
            else if (showSym && sStart.has_value() && sEnd.has_value())
×
321
                sliceSize = sEnd.value() - sStart.value() + 1;
×
322

323
            if (showSym || segment == BytecodeSegment::HeadersOnly)
×
UNCOV
324
                fmt::println("{} (length: {})", fmt::styled("Symbols table", fmt::fg(fmt::color::cyan)), sliceSize);
×
325

UNCOV
326
            for (std::size_t j = 0; j < size; ++j)
×
327
            {
UNCOV
328
                if (auto start = sStart; auto end = sEnd)
×
UNCOV
329
                    showSym = showSym && (j >= start.value() && j <= end.value());
×
330

UNCOV
331
                if (showSym)
×
UNCOV
332
                    fmt::println("{}) {}", j, syms.symbols[j]);
×
UNCOV
333
            }
×
334

UNCOV
335
            if (showSym)
×
UNCOV
336
                fmt::print("\n");
×
UNCOV
337
            if (segment == BytecodeSegment::Symbols)
×
UNCOV
338
                return;
×
339
        }
×
340

341
        // values table
342
        {
UNCOV
343
            std::size_t size = vals.values.size();
×
UNCOV
344
            std::size_t sliceSize = size;
×
345

UNCOV
346
            bool showVal = (segment == BytecodeSegment::All || segment == BytecodeSegment::Values);
×
UNCOV
347
            if (showVal && sStart.has_value() && sEnd.has_value() && (sStart.value() > size || sEnd.value() > size))
×
UNCOV
348
                fmt::print(fmt::fg(fmt::color::red), "Slice start or end can't be greater than the segment size: {}\n", size);
×
UNCOV
349
            else if (showVal && sStart.has_value() && sEnd.has_value())
×
UNCOV
350
                sliceSize = sEnd.value() - sStart.value() + 1;
×
351

UNCOV
352
            if (showVal || segment == BytecodeSegment::HeadersOnly)
×
UNCOV
353
                fmt::println("{} (length: {})", fmt::styled("Constants table", fmt::fg(fmt::color::cyan)), sliceSize);
×
354

UNCOV
355
            for (std::size_t j = 0; j < size; ++j)
×
356
            {
UNCOV
357
                if (auto start = sStart; auto end = sEnd)
×
UNCOV
358
                    showVal = showVal && (j >= start.value() && j <= end.value());
×
359

UNCOV
360
                if (showVal)
×
361
                {
UNCOV
362
                    switch (const auto val = vals.values[j]; val.valueType())
×
363
                    {
×
364
                        case ValueType::Number:
365
                            fmt::println("{}) (Number) {}", j, val.number());
×
UNCOV
366
                            break;
×
367
                        case ValueType::String:
368
                            fmt::println("{}) (String) {}", j, val.string());
×
UNCOV
369
                            break;
×
370
                        case ValueType::PageAddr:
371
                            fmt::println("{}) (PageAddr) {}", j, val.pageAddr());
×
UNCOV
372
                            break;
×
373
                        default:
374
                            fmt::print(fmt::fg(fmt::color::red), "Value type not handled: {}\n", types_to_str[static_cast<std::size_t>(val.valueType())]);
×
UNCOV
375
                            break;
×
376
                    }
×
377
                }
×
UNCOV
378
            }
×
379

380
            if (showVal)
×
381
                fmt::print("\n");
×
382
            if (segment == BytecodeSegment::Values)
×
UNCOV
383
                return;
×
384
        }
×
385

386
        // inst locs + file
387
        {
UNCOV
388
            std::size_t size = inst_locs.locations.size();
×
389
            std::size_t sliceSize = size;
×
390

391
            bool showVal = (segment == BytecodeSegment::All || segment == BytecodeSegment::InstructionLocation);
×
UNCOV
392
            if (showVal && sStart.has_value() && sEnd.has_value() && (sStart.value() > size || sEnd.value() > size))
×
393
                fmt::print(fmt::fg(fmt::color::red), "Slice start or end can't be greater than the segment size: {}\n", size);
×
UNCOV
394
            else if (showVal && sStart.has_value() && sEnd.has_value())
×
395
                sliceSize = sEnd.value() - sStart.value() + 1;
×
396

UNCOV
397
            if (showVal || segment == BytecodeSegment::HeadersOnly)
×
398
                fmt::println("{} (length: {})", fmt::styled("Instruction locations table", fmt::fg(fmt::color::cyan)), sliceSize);
×
399
            if (showVal && size > 0)
×
400
                fmt::println(" PP, IP");
×
401

402
            for (std::size_t j = 0; j < size; ++j)
×
403
            {
UNCOV
404
                if (auto start = sStart; auto end = sEnd)
×
405
                    showVal = showVal && (j >= start.value() && j <= end.value());
×
406

407
                const auto& location = inst_locs.locations[j];
×
408
                if (showVal)
×
409
                    fmt::println("{:>3},{:>3} -> {}:{}", location.page_pointer, location.inst_pointer, files.filenames[location.filename_id], location.line);
×
UNCOV
410
            }
×
411

412
            if (showVal)
×
413
                fmt::print("\n");
×
414
        }
×
415

416
        const auto stringify_value = [](const Value& val) -> std::string {
×
UNCOV
417
            switch (val.valueType())
×
418
            {
×
419
                case ValueType::Number:
UNCOV
420
                    return fmt::format("{} (Number)", val.number());
×
421
                case ValueType::String:
422
                    return fmt::format("{} (String)", val.string());
×
423
                case ValueType::PageAddr:
424
                    return fmt::format("{} (PageAddr)", val.pageAddr());
×
425
                default:
426
                    return "";
×
427
            }
UNCOV
428
        };
×
429

430
        enum class ArgKind
431
        {
432
            Symbol,
433
            Value,
434
            Builtin,
435
            Raw
436
        };
437

438
        struct Arg
439
        {
440
            ArgKind kind;
441
            uint16_t arg;
442
        };
443

444
        const std::unordered_map<Instruction, ArgKind> arg_kinds = {
×
445
            { LOAD_SYMBOL, ArgKind::Symbol },
446
            { LOAD_SYMBOL_BY_INDEX, ArgKind::Raw },
447
            { LOAD_CONST, ArgKind::Value },
448
            { POP_JUMP_IF_TRUE, ArgKind::Raw },
449
            { STORE, ArgKind::Symbol },
450
            { SET_VAL, ArgKind::Symbol },
451
            { POP_JUMP_IF_FALSE, ArgKind::Raw },
452
            { JUMP, ArgKind::Raw },
453
            { CALL, ArgKind::Raw },
454
            { CALL_BUILTIN, ArgKind::Raw },
455
            { CAPTURE, ArgKind::Symbol },
456
            { BUILTIN, ArgKind::Builtin },
457
            { DEL, ArgKind::Symbol },
458
            { MAKE_CLOSURE, ArgKind::Value },
459
            { GET_FIELD, ArgKind::Symbol },
460
            { PLUGIN, ArgKind::Value },
461
            { LIST, ArgKind::Raw },
462
            { APPEND, ArgKind::Raw },
463
            { CONCAT, ArgKind::Raw },
464
            { APPEND_IN_PLACE, ArgKind::Raw },
465
            { CONCAT_IN_PLACE, ArgKind::Raw }
466
        };
467

UNCOV
468
        const auto color_print_inst = [&syms, &vals, &stringify_value](const std::string& name, std::optional<Arg> arg = std::nullopt) {
×
UNCOV
469
            fmt::print("{}", fmt::styled(name, fmt::fg(fmt::color::gold)));
×
UNCOV
470
            if (arg.has_value())
×
471
            {
UNCOV
472
                switch (auto [kind, idx] = arg.value(); kind)
×
UNCOV
473
                {
×
474
                    case ArgKind::Symbol:
UNCOV
475
                        fmt::print(fmt::fg(fmt::color::green), " {}\n", syms.symbols[idx]);
×
UNCOV
476
                        break;
×
477
                    case ArgKind::Value:
UNCOV
478
                        fmt::print(fmt::fg(fmt::color::magenta), " {}\n", stringify_value(vals.values[idx]));
×
UNCOV
479
                        break;
×
480
                    case ArgKind::Builtin:
UNCOV
481
                        fmt::print(" {}\n", Builtins::builtins[idx].first);
×
UNCOV
482
                        break;
×
483
                    case ArgKind::Raw:
UNCOV
484
                        fmt::print(fmt::fg(fmt::color::red), " ({})\n", idx);
×
UNCOV
485
                        break;
×
UNCOV
486
                }
×
UNCOV
487
            }
×
488
            else
UNCOV
489
                fmt::print("\n");
×
UNCOV
490
        };
×
491

UNCOV
492
        if (segment == BytecodeSegment::All || segment == BytecodeSegment::Code || segment == BytecodeSegment::HeadersOnly)
×
493
        {
UNCOV
494
            uint16_t pp = 0;
×
495

UNCOV
496
            for (const auto& page : code_block.pages)
×
497
            {
UNCOV
498
                bool displayCode = true;
×
499

UNCOV
500
                if (auto wanted_page = cPage)
×
UNCOV
501
                    displayCode = pp == wanted_page.value();
×
502

UNCOV
503
                if (displayCode)
×
UNCOV
504
                    fmt::println(
×
UNCOV
505
                        "{} {} (length: {})",
×
UNCOV
506
                        fmt::styled("Code segment", fmt::fg(fmt::color::magenta)),
×
UNCOV
507
                        fmt::styled(pp, fmt::fg(fmt::color::magenta)),
×
UNCOV
508
                        page.size());
×
509

UNCOV
510
                if (page.empty())
×
511
                {
UNCOV
512
                    if (displayCode)
×
UNCOV
513
                        fmt::print("NOP");
×
UNCOV
514
                }
×
515
                else
516
                {
UNCOV
517
                    if (cPage.value_or(pp) != pp)
×
UNCOV
518
                        continue;
×
UNCOV
519
                    if (segment == BytecodeSegment::HeadersOnly)
×
UNCOV
520
                        continue;
×
UNCOV
521
                    if (sStart.has_value() && sEnd.has_value() && ((sStart.value() > page.size()) || (sEnd.value() > page.size())))
×
522
                    {
UNCOV
523
                        fmt::print(fmt::fg(fmt::color::red), "Slice start or end can't be greater than the segment size: {}\n", page.size());
×
UNCOV
524
                        return;
×
525
                    }
526

UNCOV
527
                    for (std::size_t j = sStart.value_or(0), end = sEnd.value_or(page.size()); j < end; j += 4)
×
528
                    {
UNCOV
529
                        const uint8_t inst = page[j];
×
530
                        // TEMP
UNCOV
531
                        const uint8_t padding = page[j + 1];
×
UNCOV
532
                        const auto arg = static_cast<uint16_t>((page[j + 2] << 8) + page[j + 3]);
×
533

534
                        // instruction number
UNCOV
535
                        fmt::print(fmt::fg(fmt::color::cyan), "{:>4}", j / 4);
×
536
                        // padding inst arg arg
UNCOV
537
                        fmt::print(" {:02x} {:02x} {:02x} {:02x} ", inst, padding, page[j + 2], page[j + 3]);
×
538

UNCOV
539
                        if (const auto idx = static_cast<std::size_t>(inst); idx < InstructionNames.size())
×
540
                        {
UNCOV
541
                            const auto inst_name = InstructionNames[idx];
×
UNCOV
542
                            if (const auto iinst = static_cast<Instruction>(inst); arg_kinds.contains(iinst))
×
UNCOV
543
                                color_print_inst(inst_name, Arg { arg_kinds.at(iinst), arg });
×
544
                            else
UNCOV
545
                                color_print_inst(inst_name);
×
UNCOV
546
                        }
×
547
                        else
UNCOV
548
                            fmt::println("Unknown instruction");
×
UNCOV
549
                    }
×
550
                }
UNCOV
551
                if (displayCode && segment != BytecodeSegment::HeadersOnly)
×
UNCOV
552
                    fmt::print("\n");
×
553

UNCOV
554
                ++pp;
×
UNCOV
555
            }
×
UNCOV
556
        }
×
UNCOV
557
    }
×
558

559
    uint16_t BytecodeReader::readNumber(std::size_t& i) const
28,541✔
560
    {
28,541✔
561
        const auto x = static_cast<uint16_t>(m_bytecode[i] << 8);
28,541✔
562
        const uint16_t y = m_bytecode[++i];
28,541✔
563
        return x + y;
57,082✔
564
    }
28,541✔
565
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc