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

ArkScript-lang / Ark / 16124572780

07 Jul 2025 06:11PM UTC coverage: 86.675% (+0.01%) from 86.665%
16124572780

Pull #557

github

web-flow
Merge 3563a7633 into ad314c4dc
Pull Request #557: Feat/contiguous bytecode

24 of 26 new or added lines in 4 files covered. (92.31%)

1 existing line in 1 file now uncovered.

7292 of 8413 relevant lines covered (86.68%)

113275.93 hits per line

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

70.83
/src/arkreactor/VM/State.cpp
1
#include <Ark/VM/State.hpp>
2

3
#include <Ark/Constants.hpp>
4
#include <Ark/Files.hpp>
5
#include <Ark/Compiler/Welder.hpp>
6

7
#ifdef _MSC_VER
8
#    pragma warning(push)
9
#    pragma warning(disable : 4996)
10
#endif
11

12
#include <Proxy/Picosha2.hpp>
13
#include <Ark/Compiler/BytecodeReader.hpp>
14
#include <fmt/core.h>
15
#include <fmt/color.h>
16

17
namespace Ark
18
{
19
    State::State(const std::vector<std::filesystem::path>& libenv) noexcept :
798✔
20
        m_debug_level(0),
266✔
21
        m_libenv(libenv),
266✔
22
        m_filename(ARK_NO_NAME_FILE),
266✔
23
        m_max_page_size(0)
266✔
24
    {
266✔
25
        // default value for builtin__sys:args is empty list
26
        const Value val(ValueType::List);
266✔
27
        m_binded[std::string(internal::Language::SysArgs)] = val;
266✔
28
    }
266✔
29

30
    bool State::feed(const std::string& bytecode_filename)
161✔
31
    {
161✔
32
        if (!Utils::fileExists(bytecode_filename))
161✔
33
            return false;
×
34

35
        return feed(Utils::readFileAsBytes(bytecode_filename));
161✔
36
    }
161✔
37

38
    bool State::feed(const bytecode_t& bytecode)
170✔
39
    {
170✔
40
        BytecodeReader bcr;
170✔
41
        bcr.feed(bytecode);
170✔
42
        if (!bcr.checkMagic())
170✔
43
            return false;
×
44

45
        m_bytecode = bytecode;
170✔
46

47
        try
48
        {
49
            configure(bcr);
170✔
50
            return true;
170✔
51
        }
×
52
        catch (const std::exception& e)  // FIXME I don't like this shit
53
        {
54
            fmt::println("{}", e.what());
×
55
            return false;
×
56
        }
×
57
    }
170✔
58

59
    bool State::compile(const std::string& file, const std::string& output, const uint16_t features) const
257✔
60
    {
257✔
61
        Welder welder(m_debug_level, m_libenv, features);
257✔
62
        for (const auto& p : m_binded)
514✔
63
            welder.registerSymbol(p.first);
257✔
64

65
        if (!welder.computeASTFromFile(file))
257✔
66
            return false;
×
67
        if (!welder.generateBytecode())
195✔
68
            return false;
×
69

70
        const std::string destination = output.empty() ? (file.substr(0, file.find_last_of('.')) + ".arkc") : output;
161✔
71
        if (!welder.saveBytecodeToFile(destination))
161✔
72
            return false;
×
73

74
        return true;
161✔
75
    }
257✔
76

77
    bool State::doFile(const std::string& file, const uint16_t features)
257✔
78
    {
257✔
79
        if (!Utils::fileExists(file))
257✔
80
        {
81
            fmt::print(fmt::fg(fmt::color::red), "Can not find file '{}'\n", file);
×
82
            return false;
×
83
        }
84
        m_filename = file;
257✔
85

86
        const bytecode_t bytecode = Utils::readFileAsBytes(file);
257✔
87
        BytecodeReader bcr;
257✔
88
        bcr.feed(bytecode);
257✔
89
        if (!bcr.checkMagic())  // couldn't read magic number, it's a source file
257✔
90
        {
91
            // check if it's in the arkscript cache
92
            const std::string short_filename = (std::filesystem::path(file)).filename().string();
257✔
93
            const std::string filename = short_filename.substr(0, short_filename.find_last_of('.')) + ".arkc";
257✔
94
            const std::filesystem::path directory = (std::filesystem::path(file)).parent_path() / ARK_CACHE_DIRNAME;
257✔
95
            const std::string path = (directory / filename).string();
257✔
96

97
            if (!exists(directory))  // create ark cache directory
257✔
98
                create_directory(directory);
15✔
99

100
            if (compile(file, path, features) && feed(path))
257✔
101
                return true;
161✔
102
        }
257✔
103
        else if (feed(bytecode))  // it's a bytecode file
×
104
            return true;
×
105
        return false;
×
106
    }
353✔
107

108
    bool State::doString(const std::string& code, const uint16_t features)
9✔
109
    {
9✔
110
        Welder welder(m_debug_level, m_libenv, features);
9✔
111
        for (const auto& p : m_binded)
24✔
112
            welder.registerSymbol(p.first);
15✔
113

114
        if (!welder.computeASTFromString(code))
9✔
115
            return false;
×
116
        if (!welder.generateBytecode())
9✔
117
            return false;
×
118
        return feed(welder.bytecode());
9✔
119
    }
9✔
120

121
    void State::loadFunction(const std::string& name, Procedure::CallbackType&& function) noexcept
6✔
122
    {
6✔
123
        m_binded[name] = Value(std::move(function));
6✔
124
    }
6✔
125

126
    void State::setArgs(const std::vector<std::string>& args) noexcept
10✔
127
    {
10✔
128
        Value val(ValueType::List);
10✔
129
        std::ranges::transform(args, std::back_inserter(val.list()), [](const std::string& arg) {
13✔
130
            return Value(arg);
3✔
131
        });
132

133
        m_binded[std::string(internal::Language::SysArgs)] = val;
10✔
134
    }
10✔
135

136
    void State::setDebug(const unsigned level) noexcept
×
137
    {
×
138
        m_debug_level = level;
×
139
    }
×
140

141
    void State::setLibDirs(const std::vector<std::filesystem::path>& libenv) noexcept
×
142
    {
×
143
        m_libenv = libenv;
×
144
    }
×
145

146
    void State::configure(const BytecodeReader& bcr)
170✔
147
    {
170✔
148
        using namespace internal;
149

150
        const auto [major, minor, patch] = bcr.version();
170✔
151
        if (major != ARK_VERSION_MAJOR)
170✔
152
        {
153
            std::string str_version = std::to_string(major) + "." +
×
154
                std::to_string(minor) + "." +
×
155
                std::to_string(patch);
×
156
            throwStateError(fmt::format("Compiler and VM versions don't match: got {} while running {}", str_version, ARK_VERSION));
×
157
        }
×
158

159
        const auto bytecode_hash = bcr.sha256();
170✔
160

161
        std::vector<unsigned char> hash(picosha2::k_digest_size);
170✔
162
        picosha2::hash256(m_bytecode.begin() + bytecode::HeaderSize + picosha2::k_digest_size, m_bytecode.end(), hash);
170✔
163
        // checking integrity
164
        for (std::size_t j = 0; j < picosha2::k_digest_size; ++j)
5,610✔
165
        {
166
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
167
            if (hash[j] != bytecode_hash[j])
5,440✔
168
                throwStateError("Integrity check failed");
×
169
#endif
170
        }
5,440✔
171

172
        const auto syms = bcr.symbols();
170✔
173
        const auto vals = bcr.values(syms);
170✔
174
        const auto files = bcr.filenames(vals);
170✔
175
        const auto inst_locs = bcr.instLocations(files);
170✔
176
        const auto [pages, _] = bcr.code(inst_locs);
190,564✔
177

178
        m_symbols = syms.symbols;
170✔
179
        m_constants = vals.values;
170✔
180
        m_filenames = files.filenames;
170✔
181
        m_inst_locations = inst_locs.locations;
170✔
182

183
        m_max_page_size = 0;
170✔
184
        for (const bytecode_t& page : pages)
2,658✔
185
        {
186
            if (page.size() > m_max_page_size)
2,318✔
187
                m_max_page_size = page.size();
189✔
188
        }
2,318✔
189

190
        // Make m_code as a big contiguous chunk of instructions,
191
        // aligned on the biggest page size.
192
        // This might have a downside when we have a single big page and
193
        // a bunch of smaller ones, though I couldn't measure it while testing.
194
        m_code.resize(m_max_page_size * pages.size(), Instruction::NOP);
170✔
195
        for (std::size_t i = 0, end = pages.size(); i < end; ++i)
2,658✔
196
        {
197
            for (std::size_t j = 0, end_j = pages[i].size(); j < end_j; ++j)
192,372✔
198
                m_code[i * m_max_page_size + j] = pages[i][j];
187,736✔
199
        }
2,318✔
200
    }
170✔
201

202
    void State::reset() noexcept
×
203
    {
×
204
        m_symbols.clear();
×
205
        m_constants.clear();
×
206
        m_filenames.clear();
×
207
        m_inst_locations.clear();
×
NEW
208
        m_max_page_size = 0;
×
NEW
209
        m_code.clear();
×
UNCOV
210
        m_binded.clear();
×
211

212
        // default value for builtin__sys:args is empty list
213
        const Value val(ValueType::List);
×
214
        m_binded[std::string(internal::Language::SysArgs)] = val;
×
215
    }
×
216
}
217

218
#ifdef _MSC_VER
219
#    pragma warning(pop)
220
#endif
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