Skip to content

Commit 803b891

Browse files
committed
Figured out how to compile in memory beam data
1 parent ee725fd commit 803b891

File tree

4 files changed

+87
-11
lines changed

4 files changed

+87
-11
lines changed

lib/elixir_script/beam.ex

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ defmodule ElixirScript.Beam do
77
For protocols, this will return a list of
88
all the protocol implementations
99
"""
10-
@spec debug_info(atom) :: {:ok | :error, map | binary}
10+
@spec debug_info(atom | bitstring) :: {:ok | :error, map | binary}
1111
def debug_info(module)
1212

1313
# We get debug info from String and then replace
@@ -39,9 +39,23 @@ defmodule ElixirScript.Beam do
3939
do_debug_info(module)
4040
end
4141

42-
defp do_debug_info(module) when is_atom(module) do
43-
with {_, beam, beam_path} <- :code.get_object_code(module),
44-
{:ok, {^module, [debug_info: {:debug_info_v1, backend, data}]}} <- :beam_lib.chunks(beam, [:debug_info]),
42+
def debug_info(beam) when is_bitstring(beam) do
43+
do_debug_info(beam)
44+
end
45+
46+
defp do_debug_info(module, path \\ nil)
47+
48+
defp do_debug_info(module, _) when is_atom(module) do
49+
case :code.get_object_code(module) do
50+
{_, beam, beam_path} ->
51+
do_debug_info(beam, beam_path)
52+
:error ->
53+
{:error, "Unknown module"}
54+
end
55+
end
56+
57+
defp do_debug_info(beam, beam_path) do
58+
with {:ok, {module, [debug_info: {:debug_info_v1, backend, data}]}} <- :beam_lib.chunks(beam, [:debug_info]),
4559
{:ok, {^module, attribute_info}} = :beam_lib.chunks(beam, [:attributes]) do
4660

4761
if Keyword.get(attribute_info[:attributes], :protocol) do
@@ -62,6 +76,11 @@ defmodule ElixirScript.Beam do
6276
end
6377
end
6478

79+
defp process_debug_info({:ok, info}, nil) do
80+
info = Map.put(info, :last_modified, nil)
81+
{:ok, info}
82+
end
83+
6584
defp process_debug_info({:ok, info}, beam_path) do
6685
info = case File.stat(beam_path, time: :posix) do
6786
{:ok, file_info} ->

lib/elixir_script/compiler.ex

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,40 @@ defmodule ElixirScript.Compiler do
2222
2323
* `root`: Optional root for imports of FFI JavaScript modules. Defaults to `.`.
2424
"""
25-
@spec compile(atom | [atom], []) :: nil
26-
def compile(entry_modules, opts \\ []) do
25+
@spec compile(atom | [atom] | binary, []) :: nil
26+
def compile(path, opts \\ [])
27+
28+
def compile(path, opts) when is_binary(path) do
29+
opts = build_compiler_options(opts, [])
30+
{:ok, pid} = ElixirScript.State.start_link()
31+
32+
path = if String.ends_with?(path, ".ex") or String.ends_with?(path, ".exs") do
33+
path
34+
else
35+
Path.join([path, "**", "*.{ex,exs}"])
36+
end
37+
38+
files = Path.wildcard(path)
39+
40+
Kernel.ParallelCompiler.files(files, [each_module: &on_module_compile(pid, &1, &2, &3)])
41+
42+
entry_modules = pid
43+
|> ElixirScript.State.get_in_memory_modules
44+
|> Keyword.keys
45+
46+
do_compile(entry_modules, pid, opts)
47+
end
48+
49+
def compile(entry_modules, opts) do
2750
opts = build_compiler_options(opts, entry_modules)
2851
{:ok, pid} = ElixirScript.State.start_link()
2952

3053
entry_modules = List.wrap(entry_modules)
3154

55+
do_compile(entry_modules, pid, opts)
56+
end
57+
58+
defp do_compile(entry_modules, pid, opts) do
3259
ElixirScript.FindUsedModules.execute(entry_modules, pid)
3360

3461
ElixirScript.FindUsedFunctions.execute(entry_modules, pid)
@@ -54,4 +81,8 @@ defmodule ElixirScript.Compiler do
5481
options = default_options
5582
Map.put(options, :module_formatter, ElixirScript.ModuleSystems.ES)
5683
end
84+
85+
defp on_module_compile(pid, _file, module, beam) do
86+
ElixirScript.State.put_in_memory_module(pid, module, beam)
87+
end
5788
end

lib/elixir_script/passes/find_used_modules.ex

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,19 @@ defmodule ElixirScript.FindUsedModules do
1111
modules
1212
|> List.wrap
1313
|> Enum.each(fn(module) ->
14-
if ElixirScript.State.get_module(pid, module) == nil do
15-
do_execute(module, pid)
16-
end
14+
do_execute(module, pid)
1715
end)
1816
end
1917

2018
defp do_execute(module, pid) do
21-
case ElixirScript.Beam.debug_info(module) do
19+
result = case ModuleState.get_in_memory_module(pid, module) do
20+
nil ->
21+
ElixirScript.Beam.debug_info(module)
22+
beam ->
23+
ElixirScript.Beam.debug_info(beam)
24+
end
25+
26+
case result do
2227
{:ok, info} ->
2328
walk_module(module, info, pid)
2429
{:ok, module, implementations} ->

lib/elixir_script/state.ex

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ defmodule ElixirScript.State do
77
Agent.start_link(fn ->
88
%{
99
modules: Keyword.new,
10-
js_modules: []
10+
js_modules: [],
11+
in_memory_modules: []
1112
}
1213
end)
1314
end
@@ -88,4 +89,24 @@ defmodule ElixirScript.State do
8889
state.modules
8990
end)
9091
end
92+
93+
def get_in_memory_module(pid, module) do
94+
Agent.get(pid, fn(state) ->
95+
Keyword.get(state.in_memory_modules, module)
96+
end)
97+
end
98+
99+
def get_in_memory_modules(pid) do
100+
Agent.get(pid, fn(state) ->
101+
state.in_memory_modules
102+
end)
103+
end
104+
105+
def put_in_memory_module(pid, module, beam) do
106+
Agent.update(pid, fn(state) ->
107+
in_memory_modules = Map.get(state, :in_memory_modules, [])
108+
in_memory_modules = [{module, beam} | in_memory_modules]
109+
%{ state | in_memory_modules: in_memory_modules }
110+
end)
111+
end
91112
end

0 commit comments

Comments
 (0)