Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(module-caching): loads module based on origin #152

Merged
merged 4 commits into from
Dec 26, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions compiler+runtime/include/cpp/jank/runtime/module/loader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,19 @@ namespace jank::runtime::module
latest,
};

enum class module_type : uint8_t
{
o,
cpp,
jank,
cljc
};

struct file_entry
{
object_ptr to_runtime_data() const;
native_bool exists() const;
std::time_t last_modified_at() const;

/* If the file is within a JAR, this will be the path to the JAR. */
option<native_persistent_string> archive_path;
Expand Down Expand Up @@ -68,6 +78,14 @@ namespace jank::runtime::module
option<file_entry> cljc;
};

struct find_result
{
/* All the sources for a module */
entry sources;
/* On the basis of origin, source that should be loaded. */
option<module_type> to_load;
};

/* These separators match what the JVM does on each system. */
#ifdef _WIN32
static constexpr char module_separator{ ';' };
Expand All @@ -80,6 +98,7 @@ namespace jank::runtime::module
native_bool is_loaded(native_persistent_string_view const &) const;
void set_loaded(native_persistent_string_view const &);

string_result<find_result> find(native_persistent_string_view const &module, origin const ori);
string_result<void> load(native_persistent_string_view const &module, origin const ori);

string_result<void>
Expand Down
142 changes: 114 additions & 28 deletions compiler+runtime/src/cpp/jank/runtime/module/loader.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <boost/filesystem/operations.hpp>
#include <regex>
#include <iostream>

Expand Down Expand Up @@ -139,7 +140,7 @@
}

auto const &zip_entry(zf.getEntry(std::string{ entry.path }));
fn(zip_entry.readAsText());
fn(zip_entry);

Check warning on line 143 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L143

Added line #L143 was not covered by tests
}

static void register_entry(native_unordered_map<native_persistent_string, loader::entry> &entries,
Expand Down Expand Up @@ -202,11 +203,11 @@

if(registered)
{
//fmt::println("register_entry {} {} {} {}",
// entry.archive_path,
// entry.path,
// module_path.string(),
// path_to_module(module_path));
// fmt::println("register_entry {} {} {} {}",
// entry.archive_path.unwrap_or("None"),
// entry.path,
// module_path.string(),
// path_to_module(module_path));
}
}

Expand Down Expand Up @@ -317,6 +318,31 @@
make_box(path));
}

native_bool file_entry::exists() const
{
auto const is_archive{ archive_path.is_some() };
if(is_archive && !boost::filesystem::exists(native_transient_string{ archive_path.unwrap() }))
{
return false;

Check warning on line 326 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L322-L326

Added lines #L322 - L326 were not covered by tests
}
else
{
native_bool source_exists{};
if(is_archive)
{
visit_jar_entry(*this, [&](auto const &zip_entry) { source_exists = zip_entry.isFile(); });

Check warning on line 333 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L328-L333

Added lines #L328 - L333 were not covered by tests
}

return source_exists || boost::filesystem::exists(native_transient_string{ path });

Check warning on line 336 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L336

Added line #L336 was not covered by tests
}
}

std::time_t file_entry::last_modified_at() const
{
auto const source_path{ archive_path.unwrap_or(path) };
return boost::filesystem::last_write_time(native_transient_string{ source_path });

Check warning on line 343 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L341-L343

Added lines #L341 - L343 were not covered by tests
}

native_bool loader::is_loaded(native_persistent_string_view const &module) const
{
return loaded.contains(module);
Expand All @@ -327,7 +353,8 @@
loaded.emplace(module);
}

string_result<void> loader::load(native_persistent_string_view const &module, origin const ori)
string_result<loader::find_result>
loader::find(native_persistent_string_view const &module, origin const ori)
{
static std::regex const underscore{ "_" };
native_transient_string patched_module{ module };
Expand All @@ -338,53 +365,109 @@
return err(fmt::format("unable to find module: {}", module));
}

string_result<void> res{ err(fmt::format("no sources for registered module: {}", module)) };

//fmt::println("loading nested module {}", module);

/* When we're compiling, we always load from source. Otherwise, we
* load from source if we specifically chose to do so. */
bool const compiling{ truthy(rt_ctx.compile_files_var->deref()) };
if(compiling || ori == origin::source)
if(ori == origin::source)
{
if(entry->second.jank.is_some())
{
res = load_jank(entry->second.jank.unwrap());
return find_result{ entry->second, module_type::jank };
}
else if(entry->second.cljc.is_some())
{
res = load_cljc(entry->second.cljc.unwrap());
return find_result{ entry->second, module_type::cljc };

Check warning on line 376 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L376

Added line #L376 was not covered by tests
}
}
else
{
/* TODO: origin must be latest, so we need to find that. Even if there
* is a binary, we need to only choose it if it's as new, or newer, than
* the source. */
if(entry->second.o.is_some())
if(entry->second.o.is_some() && entry->second.o.unwrap().archive_path.is_none()
Samy-33 marked this conversation as resolved.
Show resolved Hide resolved
&& (entry->second.jank.is_some() || entry->second.cljc.is_some()))

Check warning on line 382 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L381-L382

Added lines #L381 - L382 were not covered by tests
{
res = load_o(module, entry->second.o.unwrap());
auto const o_file_path{ native_transient_string{ entry->second.o.unwrap().path } };

Check warning on line 384 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L384

Added line #L384 was not covered by tests
Samy-33 marked this conversation as resolved.
Show resolved Hide resolved

std::time_t source_modified_time{};
module_type module_type{};

Check warning on line 387 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L386-L387

Added lines #L386 - L387 were not covered by tests

if(entry->second.jank.is_some() && entry->second.jank.unwrap().exists())
{
source_modified_time = entry->second.jank.unwrap().last_modified_at();
module_type = module_type::jank;

Check warning on line 392 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L389-L392

Added lines #L389 - L392 were not covered by tests
}
else if(entry->second.cljc.is_some() && entry->second.cljc.unwrap().exists())
{
source_modified_time = entry->second.cljc.unwrap().last_modified_at();
module_type = module_type::cljc;

Check warning on line 397 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L394-L397

Added lines #L394 - L397 were not covered by tests
}
else
{
return err(
fmt::format("Found a binary ({}), without a source", entry->second.o.unwrap().path));

Check warning on line 402 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L399-L402

Added lines #L399 - L402 were not covered by tests
}

if(boost::filesystem::last_write_time(o_file_path) >= source_modified_time)
{
return find_result{ entry->second, module_type::o };

Check warning on line 407 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L405-L407

Added lines #L405 - L407 were not covered by tests
}
else
{
return find_result{ entry->second, module_type };

Check warning on line 411 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L409-L411

Added lines #L409 - L411 were not covered by tests
}
}
else if(entry->second.cpp.is_some())
{
res = load_cpp(entry->second.cpp.unwrap());
return find_result{ entry->second, module_type::cpp };

Check warning on line 416 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L416

Added line #L416 was not covered by tests
}
else if(entry->second.jank.is_some())
{
res = load_jank(entry->second.jank.unwrap());
return find_result{ entry->second, module_type::jank };

Check warning on line 420 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L420

Added line #L420 was not covered by tests
}
else if(entry->second.cljc.is_some())
{
res = load_cljc(entry->second.cljc.unwrap());
return find_result{ entry->second, module_type::cljc };

Check warning on line 424 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L424

Added line #L424 was not covered by tests
}
}

return err(fmt::format("no sources for registered module: {}", module));

Check warning on line 428 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L428

Added line #L428 was not covered by tests
}

string_result<void> loader::load(native_persistent_string_view const &module, origin const ori)
{
if(loader::is_loaded(module))
{
return ok();

Check warning on line 435 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L434-L435

Added lines #L434 - L435 were not covered by tests
}

auto const &found_module{ loader::find(module, ori) };
if(found_module.is_err())
{
return err(std::move(found_module.expect_err()));

Check warning on line 441 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L440-L441

Added lines #L440 - L441 were not covered by tests
Samy-33 marked this conversation as resolved.
Show resolved Hide resolved
}

string_result<void> res(err(fmt::format("Couldn't load module: {}", module)));

auto const module_type_to_load{ found_module.expect_ok().to_load.unwrap() };
auto const &module_sources{ found_module.expect_ok().sources };

switch(module_type_to_load)
{
case module_type::jank:
res = load_jank(module_sources.jank.unwrap());
break;
case module_type::o:
res = load_o(module, module_sources.o.unwrap());
break;
case module_type::cpp:
res = load_cpp(module_sources.cpp.unwrap());
break;
case module_type::cljc:
res = load_cljc(module_sources.cljc.unwrap());
break;

Check warning on line 462 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L454-L462

Added lines #L454 - L462 were not covered by tests
}

if(res.is_err())
{
return res;
}

loaded.emplace(module);
loader::set_loaded(module);

return ok();
}
Expand Down Expand Up @@ -413,7 +496,9 @@
{
if(entry.archive_path.is_some())
{
visit_jar_entry(entry, [&](auto const &str) { rt_ctx.jit_prc.eval_string(str); });
visit_jar_entry(entry, [&](auto const &zip_entry) {
rt_ctx.jit_prc.eval_string(zip_entry.readAsText());
});

Check warning on line 501 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L499-L501

Added lines #L499 - L501 were not covered by tests
}
else
{
Expand All @@ -433,7 +518,8 @@
{
if(entry.archive_path.is_some())
{
visit_jar_entry(entry, [&](auto const &str) { rt_ctx.eval_string(str); });
visit_jar_entry(entry,
[&](auto const &zip_entry) { rt_ctx.eval_string(zip_entry.readAsText()); });

Check warning on line 522 in compiler+runtime/src/cpp/jank/runtime/module/loader.cpp

View check run for this annotation

Codecov / codecov/patch

compiler+runtime/src/cpp/jank/runtime/module/loader.cpp#L521-L522

Added lines #L521 - L522 were not covered by tests
}
else
{
Expand Down
Loading