IvanR

IvanR

How to read the BEAM bytecode compiled into memory and that is not on the disk?

Hi,
I’m the author of the Domo library that validates struct’s data against its @type spec and would like to upgrade it to support in-memory modules.

In the library, I read struct’s types by Code.Typespec.fetch_types(module_atom) that works for the module that has the compiled BEAM file on the disk. At the same time, for an in-memory module that you can make in iex, it returns :error like the following:

iex(1)> defmodule Ms do
...(1)>   defstruct [:id]
...(1)>   @type t :: %__MODULE__{id: atom}
...(1)> end
{:module, Ms, ...}

iex(2)> Code.Typespec.fetch_types(Ms)
:error

The Code.Typespec.fetch_types/1 delegates to Erlang’s :code.get_object_code/1 that, from my understanding searches bytecode on the disk. That fails for modules that exist only in memory.

How can I get the bytecode for the module that is in memory only by its name in iex/Livebook?

Marked As Solved

garazdawi

garazdawi

Erlang Core Team

It is not possible to do because during loading the original module is destroyed and it is not possible to reverse-load the module from what is loaded. So to implement such functionality we would be to keep the original module which would double the memory usage of the code for each loaded module.

Also Liked

IvanR

IvanR

Types can be read from the module’s bytecode like the following at compile-time:

defmodule MyModule do
  @type one_type :: atom()
  @opaque another_type :: integer()

  @after_compile {MyModule, :_collect_types}

  def _collect_types(_env, bytecode) do
    {:ok, types} = Code.Typespec.fetch_types(bytecode)

    Enum.map(types, fn {kind, type} ->
      type_ast = Code.Typespec.type_to_quoted(type)

      type_ast
      |> Macro.to_string()
      |> IO.inspect(label: kind)
    end)
  end
end

it prints:

opaque: "another_type() :: integer()"
type: "one_type() :: atom()"
hauleth

hauleth

You cannot. I have asked for such thing on the Erlang Issue Tracker and IRC and there is no way to achieve what you want. The only solution is to manually store 3rd element of the tuple returned by defmodule and use that as a BEAM data.

IvanR

IvanR

Good to know. It seems OTP has no public interface to get in-memory modules yet.

IvanR

IvanR

So I’ve solved my problem by simply collecting types from the bytecode with @after_compile {module, fun} hook because the library should be used explicitly in the modules anyway.

The other way to get bytecodes is a {:on_module, bytecode, :none} compilation tracer introduced in Elixir v1.13.0. The tracer can be added to the elixir compiler configuration dynamically from a custom mix compile task that should go first in compilers list in project’s mix.exs file.

feifan

feifan

Hi @IvanR! Thanks for asking this — I’m also wondering about the same. Do you have any code examples you could share with details on how specifically you can get the types with an @after_compile hook? I understand the general idea but I’m not clear how to specifically do it in code.

Where Next?

Popular in Questions Top

belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
New
sacepums
Hey guys. I'm new to elixir and im really stocked about it. But I ran into a bit of problem - I need to convert a date sting, for examp...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
mathew4509
I have a list say x = ["23gh", "56kh", "97mh"] I would like to pass each element to Val in each iteration. Say, in iteration 1 -------...
New
Mooodi
Given a string, how can I get access to its character by index? Enum.at("my_string", 2) doesn't work. Or rather, not char, but a substr...
New

Other popular topics Top

9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New

We're in Beta

About us Mission Statement