Skip to content

Commit 9db9324

Browse files
committed
Add erlang:loaded/0 NIF
A more memory effective way of getting loaded modules (on BEAM), used by Elixir 1.20 Add erlang:loaded/0 which returns a list of all currently loaded modules, matching the OTP behavior. Changes: Implement erlang:loaded/0 NIF in nifs.c Register in nifs.gperf Add Erlang stub with edoc in estdlib/erlang.erl Add test test_erlang_loaded Update CHANGELOG Signed-off-by: Peter M <petermm@gmail.com>
1 parent 231060c commit 9db9324

File tree

7 files changed

+77
-0
lines changed

7 files changed

+77
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99
### Added
1010
- Added a limited implementation of the OTP `ets` interface
1111
- Added `code:all_loaded/0` and `code:all_available/0`
12+
- Added `erlang:loaded/0`
1213
- Added `erlang:split_binary/2`
1314
- Added `inet:getaddr/2`
1415
- Added support for external pids and encoded pids in external terms

libs/estdlib/src/erlang.erl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
erase/0,
5353
erase/1,
5454
function_exported/3,
55+
loaded/0,
5556
module_loaded/1,
5657
display/1,
5758
list_to_atom/1,
@@ -670,6 +671,15 @@ erase(_Key) ->
670671
function_exported(_Module, _Function, _Arity) ->
671672
erlang:nif_error(undefined).
672673

674+
%%-----------------------------------------------------------------------------
675+
%% @returns list of loaded modules
676+
%% @doc Returns all loaded modules.
677+
%% @end
678+
%%-----------------------------------------------------------------------------
679+
-spec loaded() -> [module()].
680+
loaded() ->
681+
erlang:nif_error(undefined).
682+
673683
%% @param Module name of module
674684
%% @returns boolean
675685
%% @doc Returns true if module is loaded without attempting to do it.

src/libAtomVM/nifs.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ static term nif_code_server_type_resolver(Context *ctx, int argc, term argv[]);
265265
static term nif_code_server_import_resolver(Context *ctx, int argc, term argv[]);
266266
static term nif_code_server_set_native_code(Context *ctx, int argc, term argv[]);
267267
#endif
268+
static term nif_erlang_loaded(Context *ctx, int argc, term argv[]);
268269
static term nif_erlang_module_loaded(Context *ctx, int argc, term argv[]);
269270
static term nif_erlang_nif_error(Context *ctx, int argc, term argv[]);
270271
#ifndef AVM_NO_JIT
@@ -849,6 +850,10 @@ static const struct Nif code_server_set_native_code_nif = {
849850
.nif_ptr = nif_code_server_set_native_code
850851
};
851852
#endif
853+
static const struct Nif erlang_loaded_nif = {
854+
.base.type = NIFFunctionType,
855+
.nif_ptr = nif_erlang_loaded
856+
};
852857

853858
static const struct Nif module_loaded_nif = {
854859
.base.type = NIFFunctionType,
@@ -5946,6 +5951,25 @@ static term nif_code_server_set_native_code(Context *ctx, int argc, term argv[])
59465951
}
59475952
#endif
59485953

5954+
static term nif_erlang_loaded(Context *ctx, int argc, term argv[])
5955+
{
5956+
UNUSED(argc);
5957+
UNUSED(argv);
5958+
5959+
term result = term_nil();
5960+
int loaded_modules_count = ctx->global->loaded_modules_count;
5961+
if (UNLIKELY(memory_ensure_free(ctx, LIST_SIZE(loaded_modules_count, 0)) != MEMORY_GC_OK)) {
5962+
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
5963+
}
5964+
5965+
for (int ix = 0; ix < loaded_modules_count; ix++) {
5966+
Module *module = globalcontext_get_module_by_index(ctx->global, ix);
5967+
result = term_list_prepend(module_get_name(module), result, &ctx->heap);
5968+
}
5969+
5970+
return result;
5971+
}
5972+
59495973
static term nif_erlang_module_loaded(Context *ctx, int argc, term argv[])
59505974
{
59515975
UNUSED(argc);

src/libAtomVM/nifs.gperf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ erlang:setnode/3, &setnode_3_nif
149149
erlang:dist_ctrl_get_data_notification/1, &dist_ctrl_get_data_notification_nif
150150
erlang:dist_ctrl_get_data/1, &dist_ctrl_get_data_nif
151151
erlang:dist_ctrl_put_data/2, &dist_ctrl_put_data_nif
152+
erlang:loaded/0, &erlang_loaded_nif
152153
erlang:module_loaded/1,&module_loaded_nif
153154
erlang:nif_error/1,&nif_error_nif
154155
erlang:list_to_bitstring/1, &list_to_bitstring_nif

tests/erlang_tests/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,7 @@ compile_erlang(test_close_avm_pack DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/code_load
590590

591591
compile_erlang(test_module_info)
592592
compile_erlang(erlang_module_loaded)
593+
compile_erlang(test_erlang_loaded)
593594

594595
compile_erlang(int64_build_binary)
595596

@@ -1153,6 +1154,7 @@ set(erlang_test_beams
11531154

11541155
test_module_info.beam
11551156
erlang_module_loaded.beam
1157+
test_erlang_loaded.beam
11561158

11571159
int64_build_binary.beam
11581160

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
%
2+
% This file is part of AtomVM.
3+
%
4+
% Copyright 2026 AtomVM Contributors
5+
%
6+
% Licensed under the Apache License, Version 2.0 (the "License");
7+
% you may not use this file except in compliance with the License.
8+
% You may obtain a copy of the License at
9+
%
10+
% http://www.apache.org/licenses/LICENSE-2.0
11+
%
12+
% Unless required by applicable law or agreed to in writing, software
13+
% distributed under the License is distributed on an "AS IS" BASIS,
14+
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
% See the License for the specific language governing permissions and
16+
% limitations under the License.
17+
%
18+
% SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
19+
%
20+
21+
-module(test_erlang_loaded).
22+
23+
-export([start/0]).
24+
25+
start() ->
26+
Loaded = erlang:loaded(),
27+
true = is_list(Loaded),
28+
true = length(Loaded) > 0,
29+
true = contains(?MODULE, Loaded),
30+
true = all_atoms(Loaded),
31+
0.
32+
33+
contains(_Module, []) -> false;
34+
contains(Module, [Module | _]) -> true;
35+
contains(Module, [_H | Tail]) -> contains(Module, Tail).
36+
37+
all_atoms([]) -> true;
38+
all_atoms([H | Tail]) -> is_atom(H) andalso all_atoms(Tail).

tests/test.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,7 @@ struct Test tests[] = {
562562

563563
TEST_CASE(test_module_info),
564564
TEST_CASE(erlang_module_loaded),
565+
TEST_CASE(test_erlang_loaded),
565566

566567
TEST_CASE(test_op_bs_start_match),
567568
TEST_CASE(test_op_bs_create_bin),

0 commit comments

Comments
 (0)