Skip to content

Commit

Permalink
Fix tests in 1.16 and 1.15. Make cache warmup prettier. Remove unused…
Browse files Browse the repository at this point in the history
… deps
  • Loading branch information
hissssst committed Mar 31, 2024
1 parent 88777d3 commit c146eef
Show file tree
Hide file tree
Showing 16 changed files with 209 additions and 65 deletions.
12 changes: 7 additions & 5 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
description = "Tria: optimizing Elixir compiler and infrastructure";
outputs = { self, nixpkgs, ... }:
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
outputs = { nixpkgs, ... }:
let pkgs = nixpkgs.legacyPackages.x86_64-linux;
in {
devShells.x86_64-linux.default = import ./shell.nix { inherit pkgs; };
Expand Down
1 change: 1 addition & 0 deletions lib/mix/tasks/compile.tria.ex
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ defmodule Mix.Tasks.Compile.Tria do
|> File.mkdir_p!()

Debug.inspect(manifest, label: :manifest)
manifest = %Manifest{manifest | new: false}

File.write!(manifest_path, :erlang.term_to_binary(manifest))
end
Expand Down
19 changes: 16 additions & 3 deletions lib/mix/tasks/tria.warmup.ex
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,15 @@ defmodule Mix.Tasks.Tria.Warmup do
alias Tria.Language.Analyzer.Purity

def run(args) when is_list(args) do
run parse_args args
{functions, modules} = run parse_args args

IO.write [
IO.ANSI.clear_line(),
IO.ANSI.green(),
"\nWarmup completed",
IO.ANSI.reset(),
"\nChecked #{functions} functions in #{modules - 1} modules\n"
]
end

def run(%{from: :loaded}) do
Expand All @@ -64,7 +72,7 @@ defmodule Mix.Tasks.Tria.Warmup do
def check(modules) do
length = length modules

Enum.reduce(modules, 1, fn module, index ->
Enum.reduce(modules, {0, 1}, fn module, {all_functions, index} ->
with(
{:ok, object_code} <- Beam.object_code(module),
{:ok, abstract_code} <- Beam.abstract_code(object_code)
Expand All @@ -87,8 +95,13 @@ defmodule Mix.Tasks.Tria.Warmup do
{findex + 1, now}
end)
end
|> case do
{functions, _} ->
{all_functions + functions, index + 1}

index + 1
_ ->
{all_functions, index + 1}
end
end)
end

Expand Down
10 changes: 5 additions & 5 deletions lib/tria/compiler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,14 @@ defmodule Tria.Compiler do
_paths,
%{build_path: build_path, context: context, manifest: manifest} = opts
) do
caller = self()
ContextServer.restore!(context, present: not manifest.new, build_path: build_path)

added_and_changed =
for {status, file} when status in ~w[added changed]a <- files_diff do
file
end

caller = self()
result =
ElixirCompiler.parallel_compile(added_and_changed,
# Code options
Expand All @@ -117,10 +118,10 @@ defmodule Tria.Compiler do

# ParallelCompiler options
dest: build_path,
each_module: fn file, module, bytecode ->
each_module: fn file, module, beam ->
Debug.inspect(module, label: :each_module)
Beam.store_object_code(module, bytecode)
send(caller, {:last_cycle_compiled, {module, bytecode, file}})
Beam.store_object_code(module, beam)
send(caller, {:last_cycle_compiled, {module, beam, file}})
end,
each_cycle: fn graphs ->
modules =
Expand Down Expand Up @@ -172,7 +173,6 @@ defmodule Tria.Compiler do
|> Manifest.apply_diff(files_diff)
|> Manifest.update_file_to_modules(file_to_modules)

ContextServer.restore(opts.context)
ContextServer.emit_difference(opts.context, new_modules, removed_modules, changed_modules)

modules =
Expand Down
26 changes: 22 additions & 4 deletions lib/tria/compiler/context_server.ex
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ defmodule Tria.Compiler.ContextServer do
Mark `module` ready. Context module can only be generated
when all modules are ready
"""
@spec mark_ready(t(), module()) :: :ok
@spec mark_ready(t(), module()) :: :ok | :error
def mark_ready(context, module) do
call(context, {:ready, module})
end
Expand All @@ -74,11 +74,26 @@ defmodule Tria.Compiler.ContextServer do
@doc """
Restores state of the context server from already existing context module
"""
@spec restore(t(), Keyword.t()) :: :ok
@spec restore(t(), Keyword.t()) :: :ok | :error
def restore(context, opts \\ []) do
call(context, {:restore, opts})
end

@doc """
Restores state of the context server from already existing context module. Raises on error
"""
@spec restore!(t(), Keyword.t()) :: :ok | no_return()
def restore!(context, opts \\ []) do
{present, opts} = Keyword.pop!(opts, :present)
case restore(context, opts) do
:error when present ->
raise CompileError, description: "Failed to restore the #{inspect context}"

_ ->
:ok
end
end

@spec emit_difference(t(), Enumerable.t(module()), Enumerable.t(module()), Enumerable.t(module())) :: :ok
def emit_difference(context, new_modules, removed_modules, changed_modules) do
call(context, {:emit_difference, new_modules, removed_modules, changed_modules})
Expand Down Expand Up @@ -118,14 +133,15 @@ defmodule Tria.Compiler.ContextServer do
{:reply, :ok, %{state | definitions: definitions}}
end

def handle_call({:restore, _opts}, _from, state) do
def handle_call({:restore, opts}, _from, state) do
context = state.name
case Beam.object_code(context) do
case Beam.object_code_from_path(context, opts[:build_path]) do
{:ok, object_code} ->
definitions =
object_code
|> Beam.abstract_code!()
|> Beam.tria_functions()
|> Debug.inspect_ast(label: :restored_functions)
|> Enum.reduce(%{}, fn {{_module, kind, name, arity}, clauses}, acc ->
{module, name} = Compiler.unfname(name)
Tracer.tag_ast({:fn, [], clauses}, key: {module, name, arity}, label: :restored)
Expand Down Expand Up @@ -202,6 +218,8 @@ defmodule Tria.Compiler.ContextServer do
end
end

Debug.inspect_ast(module, label: :context_module)

if Debug.debugging?(:write_tria) do
File.write!("tria_global_context.ex", ast_to_string(module))
end
Expand Down
2 changes: 1 addition & 1 deletion lib/tria/compiler/manifest.ex
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
defmodule Tria.Compiler.Manifest do

@moduledoc """
Compiler manifest.
Expand All @@ -20,6 +19,7 @@ defmodule Tria.Compiler.Manifest do
@tria_version Tria.MixProject.project[:version]

defstruct [
new: true,
tria_version: @tria_version,
file_inputs: %{},
file_to_modules: %{},
Expand Down
47 changes: 40 additions & 7 deletions lib/tria/compiler/translator/abstract.ex
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,16 @@ defmodule Tria.Compiler.AbstractTranslator do
|> postwalk(&with_meta(&1, meta))

# List comprehension
{:lc, anno, body, [{:b_generate, banno, bin, input}]} ->
{:<<>>, _, bin} = traverse(bin)
{last, heading} = List.pop_at(bin, -1)
input = traverse(input)
{:for, meta(anno), [{:<<>>, meta(banno), heading ++ [{:"<-", [], [last, input]}]}, [do: traverse_block body]]}

{:lc, anno, body, loops} ->
{:for, meta(anno), traverse(loops) ++ [[do: traverse_block body]]}
{:for, meta(anno), traverse_loops(loops) ++ [[do: traverse_block body]]}

# Map comprehension
{:mc, anno, {:map_field_assoc, _anno, left, right}, loops} ->
meta = meta(anno)
left = traverse_block(left)
right = traverse_block(right)
traversed_loops = traverse_loops(loops)
{:for, meta, traversed_loops ++ [[into: {:%{}, meta, []}, do: {left, right}]]}

{:block, anno, block} ->
{:__block__, meta(anno), Enum.map(block, &traverse/1)}
Expand Down Expand Up @@ -175,6 +177,9 @@ defmodule Tria.Compiler.AbstractTranslator do
{:b_generate, anno, left, right} ->
{:"<-", meta(anno), [traverse(left), traverse(right)]}

{:m_generate, anno, left, right} ->
{:"<-", meta(anno), [traverse(left), traverse(right)]}

# Binary
{:bin, anno, elements} ->
# Why flatten?
Expand Down Expand Up @@ -339,6 +344,34 @@ defmodule Tria.Compiler.AbstractTranslator do

## Context-specific traversal

### Comprehension loops

defguardp is_generate(g) when g in ~w[generate m_generate]a

def traverse_loops([]), do: []
def traverse_loops([loop | loops]) do
loop =
case loop do
{:b_generate, anno, binary, iterable} ->
{:<<>>, _, traversed_binary} = traverse(binary)
{last, heading} = List.pop_at(traversed_binary, -1)
iterable = traverse(iterable)
meta = meta(anno)
{:<<>>, meta, heading ++ [{:"<-", anno, [last, iterable]}]}

{g, anno, {:map_field_exact, _mfe_anno, left, right}, iterable} when is_generate(g) ->
{:"<-", meta(anno), [{traverse(left), traverse(right)}, traverse(iterable)]}

{g, anno, item, iterable} when is_generate(g) ->
{:"<-", meta(anno), [traverse(item) , traverse(iterable)]}

other ->
traverse(other)
end

[loop | traverse_loops(loops)]
end

### Try

# try/rescue actually generates `catch` clauses.
Expand Down
45 changes: 23 additions & 22 deletions lib/tria/compiler/translator/elixir.ex
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,29 @@ defmodule Tria.Compiler.ElixirTranslator do
@doc """
Returns full module atom from an alias
"""
# Here I don't write `%Macro.Env{}` because sometime I use field-polymorphic structure
@spec unalias(Macro.t(), Macro.Env.t() | map()) :: module() | Macro.t()
def unalias(module, _env) when is_atom(module), do: module
def unalias({:__aliases__, _, [{:__MODULE__, _, _} | tail]}, %{module: module} = env) do
unalias({:__aliases__, [], [module | tail]}, env)
end
def unalias({:__aliases__, _, [module | tail]} = aliased, %{aliases: aliases} = env) do
case Keyword.fetch(aliases, Module.concat([module])) do
{:ok, found} ->
Module.concat([found | tail])

:error ->
case Macro.expand(aliased, env) do
module when is_atom(module) ->
module

other ->
unalias(other)
end
end
end
def unalias(other, _env), do: other

@spec unalias(Macro.t()) :: module() | Macro.t()
def unalias({:__aliases__, meta, names} = ast) when is_aliases(ast) do
if the_alias = meta[:alias], do: the_alias, else: Module.concat(names)
Expand Down Expand Up @@ -793,28 +816,6 @@ defmodule Tria.Compiler.ElixirTranslator do
%Macro.Env{env | versioned_vars: versioned_vars}
end

# Here I don't write Macro.Env because sometime I use field-polymorphic structure
defp unalias(module, _env) when is_atom(module), do: module
defp unalias({:__aliases__, _, [{:__MODULE__, _, _} | tail]}, %{module: module} = env) do
unalias({:__aliases__, [], [module | tail]}, env)
end
defp unalias({:__aliases__, _, [module | tail]} = aliased, %{aliases: aliases} = env) do
case Keyword.fetch(aliases, Module.concat([module])) do
{:ok, found} ->
Module.concat([found | tail])

:error ->
case Macro.expand(aliased, env) do
module when is_atom(module) ->
module

other ->
unalias(other)
end
end
end
defp unalias(other, _env), do: other

defp normalize_alias_to({:__aliases__, _, modules}), do: Module.concat(modules)
defp normalize_alias_to(module), do: Module.concat([module])

Expand Down
4 changes: 4 additions & 0 deletions lib/tria/language/analyzer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ defmodule Tria.Language.Analyzer do
:error ->
nil
end
rescue
error ->
IO.inspect mfarity, label: :failed
reraise error, __STACKTRACE__
end

end
20 changes: 20 additions & 0 deletions lib/tria/language/beam.ex
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,26 @@ defmodule Tria.Language.Beam do
end
end

@doc """
Fetches obeject_code from module name
"""
@spec object_code_from_path(module(), Path.t()) :: {:ok, object_code()} | :error
def object_code_from_path(module, nil) do
object_code(module)
end

def object_code_from_path(module, path) do
with {:error, _} <- File.read(Path.join(path, "#{module}.beam")) do
case :code.get_object_code(module) do
{^module, object_code, _filename} ->
{:ok, object_code}

_ ->
:error
end
end
end

@doc """
Fetches obeject_code from module name in raising manner
"""
Expand Down
Loading

0 comments on commit c146eef

Please sign in to comment.