Skip to content

Commit 24f46be

Browse files
author
José Valim
committed
Use unamed tables for module compilation
* We have created a main named table that keeps all module information * We have reduced the amount of tables by storing internal, docs and attributes altogether and using table looks for retriving the relevant information * At this moment, creating a module in Elixir defines three tables, one for data, another for functions and another for clauses Signed-off-by: José Valim <[email protected]>
1 parent 0fe3da9 commit 24f46be

File tree

8 files changed

+165
-178
lines changed

8 files changed

+165
-178
lines changed

lib/elixir/lib/kernel/lexical_tracker.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ defmodule Kernel.LexicalTracker do
3333
defp to_pid(pid) when is_pid(pid), do: pid
3434
defp to_pid(mod) when is_atom(mod) do
3535
table = :elixir_module.data_table(mod)
36-
[{_, val}] = :ets.lookup(table, :__lexical_tracker)
36+
[{_, val}] = :ets.lookup(table, {:elixir, :lexical_tracker})
3737
val
3838
end
3939

lib/elixir/lib/module.ex

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -504,19 +504,19 @@ defmodule Module do
504504
def add_doc(module, line, kind, tuple, signature, doc) when
505505
kind in [:def, :defmacro, :type, :opaque] and (is_binary(doc) or is_boolean(doc) or doc == nil) do
506506
assert_not_compiled!(:add_doc, module)
507-
table = docs_table_for(module)
507+
table = data_table_for(module)
508508

509509
{signature, _} = :lists.mapfoldl fn(x, acc) ->
510510
{simplify_signature(x, acc), acc + 1}
511511
end, 1, signature
512512

513-
case :ets.lookup(table, tuple) do
513+
case :ets.lookup(table, {:doc, tuple}) do
514514
[] ->
515-
:ets.insert(table, {tuple, line, kind, signature, doc})
515+
:ets.insert(table, {{:doc, tuple}, line, kind, signature, doc})
516516
:ok
517-
[{tuple, line, _old_kind, old_sign, old_doc}] ->
517+
[{doc_tuple, line, _old_kind, old_sign, old_doc}] ->
518518
:ets.insert(table, {
519-
tuple,
519+
doc_tuple,
520520
line,
521521
kind,
522522
merge_signatures(old_sign, signature, 1),
@@ -612,7 +612,7 @@ defmodule Module do
612612
"""
613613
def defines?(module, tuple) when is_tuple(tuple) do
614614
assert_not_compiled!(:defines?, module)
615-
table = function_table_for(module)
615+
table = defs_table_for(module)
616616
:ets.lookup(table, tuple) != []
617617
end
618618

@@ -632,7 +632,7 @@ defmodule Module do
632632
"""
633633
def defines?(module, tuple, kind) do
634634
assert_not_compiled!(:defines?, module)
635-
table = function_table_for(module)
635+
table = defs_table_for(module)
636636
case :ets.lookup(table, tuple) do
637637
[{_, ^kind, _, _, _, _, _}] -> true
638638
_ -> false
@@ -652,8 +652,8 @@ defmodule Module do
652652
"""
653653
def definitions_in(module) do
654654
assert_not_compiled!(:definitions_in, module)
655-
table = function_table_for(module)
656-
for {tuple, _, _, _, _, _, _} <- :ets.tab2list(table), do: tuple
655+
table = defs_table_for(module)
656+
:lists.concat :ets.match(table, {:'$1', :_, :_, :_, :_, :_, :_})
657657
end
658658

659659
@doc """
@@ -671,8 +671,8 @@ defmodule Module do
671671
"""
672672
def definitions_in(module, kind) do
673673
assert_not_compiled!(:definitions_in, module)
674-
table = function_table_for(module)
675-
for {tuple, stored_kind, _, _, _, _, _} <- :ets.tab2list(table), stored_kind == kind, do: tuple
674+
table = defs_table_for(module)
675+
:lists.concat :ets.match(table, {:'$1', kind, :_, :_, :_, :_, :_})
676676
end
677677

678678
@doc """
@@ -698,12 +698,11 @@ defmodule Module do
698698
[]
699699
end
700700

701-
old = get_attribute(module, :__overridable)
701+
old = :elixir_def_overridable.overridable(module)
702702
merged = :orddict.update(tuple, fn({count, _, _, _}) ->
703703
{count + 1, clause, neighbours, false}
704704
end, {1, clause, neighbours, false}, old)
705-
706-
put_attribute(module, :__overridable, merged)
705+
:elixir_def_overridable.overridable(module, merged)
707706
end
708707
end
709708
end
@@ -712,7 +711,7 @@ defmodule Module do
712711
Returns `true` if `tuple` in `module` is marked as overridable.
713712
"""
714713
def overridable?(module, tuple) do
715-
!!List.keyfind(get_attribute(module, :__overridable), tuple, 0)
714+
!!List.keyfind(:elixir_def_overridable.overridable(module), tuple, 0)
716715
end
717716

718717
@doc """
@@ -731,7 +730,7 @@ defmodule Module do
731730
assert_not_compiled!(:put_attribute, module)
732731
table = data_table_for(module)
733732
value = normalize_attribute(key, value)
734-
acc = :ets.lookup_element(table, :__acc_attributes, 2)
733+
acc = :ets.lookup_element(table, {:elixir, :acc_attributes}, 2)
735734

736735
new =
737736
if :lists.member(key, acc) do
@@ -832,13 +831,13 @@ defmodule Module do
832831
table = data_table_for(module)
833832

834833
if Keyword.get(opts, :persist) do
835-
old = :ets.lookup_element(table, :__persisted_attributes, 2)
836-
:ets.insert(table, {:__persisted_attributes, [new|old]})
834+
old = :ets.lookup_element(table, {:elixir, :persisted_attributes}, 2)
835+
:ets.insert(table, {{:elixir, :persisted_attributes}, [new|old]})
837836
end
838837

839838
if Keyword.get(opts, :accumulate) do
840-
old = :ets.lookup_element(table, :__acc_attributes, 2)
841-
:ets.insert(table, {:__acc_attributes, [new|old]})
839+
old = :ets.lookup_element(table, {:elixir, :acc_attributes}, 2)
840+
:ets.insert(table, {{:elixir, :acc_attributes}, [new|old]})
842841
end
843842
end
844843

@@ -901,7 +900,7 @@ defmodule Module do
901900
case :ets.lookup(table, key) do
902901
[{^key, val}] -> val
903902
[] ->
904-
acc = :ets.lookup_element(table, :__acc_attributes, 2)
903+
acc = :ets.lookup_element(table, {:elixir, :acc_attributes}, 2)
905904

906905
cond do
907906
:lists.member(key, acc) ->
@@ -956,15 +955,11 @@ defmodule Module do
956955
end
957956

958957
defp data_table_for(module) do
959-
module
960-
end
961-
962-
defp function_table_for(module) do
963-
:elixir_def.table(module)
958+
:elixir_module.data_table(module)
964959
end
965960

966-
defp docs_table_for(module) do
967-
:elixir_module.docs_table(module)
961+
defp defs_table_for(module) do
962+
:elixir_module.defs_table(module)
968963
end
969964

970965
defp assert_not_compiled!(fun, module) do

lib/elixir/lib/module/locals_tracker.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ defmodule Module.LocalsTracker do
8383
defp to_pid(pid) when is_pid(pid), do: pid
8484
defp to_pid(mod) when is_atom(mod) do
8585
table = :elixir_module.data_table(mod)
86-
[{_, val}] = :ets.lookup(table, :__locals_tracker)
86+
[{_, val}] = :ets.lookup(table, {:elixir, :locals_tracker})
8787
val
8888
end
8989

lib/elixir/src/elixir_def.erl

Lines changed: 36 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,35 @@
11
% Holds the logic responsible for function definitions (def(p) and defmacro(p)).
22
-module(elixir_def).
3-
-export([table/1, clauses_table/1, setup/1,
4-
cleanup/1, reset_last/1, lookup_definition/2,
3+
-export([setup/1, reset_last/1, lookup_definition/2,
54
delete_definition/2, store_definition/6, unwrap_definitions/2,
6-
store_each/8, format_error/1]).
5+
store_each/7, format_error/1]).
76
-include("elixir.hrl").
87

9-
-define(attr, '__def_table').
10-
-define(clauses_attr, '__clauses_table').
8+
-define(last_def, {elixir, last_def}).
9+
-define(attr, {elixir, def_table}).
10+
-define(clauses_attr, {elixir, clauses_table}).
1111

1212
%% Table management functions. Called internally.
1313

14-
table(Module) ->
15-
ets:lookup_element(Module, ?attr, 2).
16-
17-
clauses_table(Module) ->
18-
ets:lookup_element(Module, ?clauses_attr, 2).
19-
2014
setup(Module) ->
21-
ets:insert(Module, {?attr, ets:new(Module, [set, public])}),
22-
ets:insert(Module, {?clauses_attr, ets:new(Module, [bag, public])}),
2315
reset_last(Module),
2416
ok.
2517

26-
cleanup(Module) ->
27-
ets:delete(table(Module)),
28-
ets:delete(clauses_table(Module)).
29-
30-
%% Reset the last item. Useful when evaling code.
3118
reset_last(Module) ->
32-
ets:insert(table(Module), {last, []}).
19+
ets:insert(elixir_module:data_table(Module), {?last_def, []}).
3320

34-
%% Looks up a definition from the database.
3521
lookup_definition(Module, Tuple) ->
36-
case ets:lookup(table(Module), Tuple) of
22+
case ets:lookup(elixir_module:defs_table(Module), Tuple) of
3723
[Result] ->
38-
CTable = clauses_table(Module),
24+
CTable = elixir_module:clas_table(Module),
3925
{Result, [Clause || {_, Clause} <- ets:lookup(CTable, Tuple)]};
4026
_ ->
4127
false
4228
end.
4329

4430
delete_definition(Module, Tuple) ->
45-
ets:delete(table(Module), Tuple),
46-
ets:delete(clauses_table(Module), Tuple).
31+
ets:delete(elixir_module:defs_table(Module), Tuple),
32+
ets:delete(elixir_module:clas_table(Module), Tuple).
4733

4834
% Invoked by the wrap definition with the function abstract tree.
4935
% Each function is then added to the function table.
@@ -98,16 +84,12 @@ store_definition(Line, Kind, CheckClauses, Name, Args, Guards, Body, KeepLocatio
9884
DefaultsLength = length(Defaults),
9985
elixir_locals:record_defaults(Tuple, Kind, Module, DefaultsLength),
10086

101-
File = ?m(E, file),
102-
Table = table(Module),
103-
CTable = clauses_table(Module),
104-
87+
File = ?m(E, file),
10588
compile_super(Module, Super, E),
106-
check_previous_defaults(Table, Line, Name, Arity, Kind, DefaultsLength, E),
89+
check_previous_defaults(Line, Module, Name, Arity, Kind, DefaultsLength, E),
10790

108-
store_each(CheckClauses, Kind, File, Location,
109-
Table, CTable, DefaultsLength, Function),
110-
[store_each(false, Kind, File, Location, Table, CTable, 0,
91+
store_each(CheckClauses, Kind, File, Location, Module, DefaultsLength, Function),
92+
[store_each(false, Kind, File, Location, Module, 0,
11193
default_function_for(Kind, Name, Default)) || Default <- Defaults],
11294

11395
make_struct_available(Kind, Module, Name, Args),
@@ -166,7 +148,7 @@ normalize_location(File) ->
166148
%% Compile super
167149

168150
compile_super(Module, true, #{function := Function}) ->
169-
elixir_def_overridable:store(Module, Function, true);
151+
elixir_def_overridable:super(Module, Function);
170152
compile_super(_Module, _, _E) -> ok.
171153

172154
%% Translate the given call and expression given
@@ -229,9 +211,8 @@ is_macro(_) -> false.
229211
% It returns a list of all functions to be exported, plus the macros,
230212
% and the body of all functions.
231213
unwrap_definitions(File, Module) ->
232-
Table = table(Module),
233-
CTable = clauses_table(Module),
234-
ets:delete(Table, last),
214+
Table = elixir_module:defs_table(Module),
215+
CTable = elixir_module:clas_table(Module),
235216

236217
{All, Private} = unwrap_definition(ets:tab2list(Table), File, Module, CTable, [], []),
237218
Unreachable = elixir_locals:warn_unused_local(File, Module, Private),
@@ -327,26 +308,33 @@ warn_bodyless_function(Line, File, _Module, Kind, Tuple) ->
327308
%% This function also checks and emit warnings in case
328309
%% the kind, of the visibility of the function changes.
329310

330-
store_each(Check, Kind, File, Location, Table, CTable, Defaults, {function, Line, Name, Arity, Clauses}) ->
331-
Tuple = {Name, Arity},
311+
store_each(Check, Kind, File, Location, Module, Defaults, {function, Line, Name, Arity, Clauses}) ->
312+
Data = elixir_module:data_table(Module),
313+
Defs = elixir_module:defs_table(Module),
314+
Clas = elixir_module:clas_table(Module),
315+
316+
Tuple = {Name, Arity},
332317
HasBody = Clauses =/= [],
333-
case ets:lookup(Table, Tuple) of
334-
[{Tuple, StoredKind, StoredLine, StoredFile, StoredCheck, StoredLocation, {StoredDefaults, LastHasBody, LastDefaults}}] ->
318+
319+
case ets:lookup(Defs, Tuple) of
320+
[{Tuple, StoredKind, StoredLine, StoredFile, StoredCheck,
321+
StoredLocation, {StoredDefaults, LastHasBody, LastDefaults}}] ->
335322
FinalLine = StoredLine,
336323
FinalLocation = StoredLocation,
337324
FinalDefaults = {max(Defaults, StoredDefaults), HasBody, Defaults},
338325
check_valid_kind(Line, File, Name, Arity, Kind, StoredKind),
339326
(Check and StoredCheck) andalso
340-
check_valid_clause(Line, File, Name, Arity, Kind, Table, StoredLine, StoredFile),
327+
check_valid_clause(Line, File, Name, Arity, Kind, Data, StoredLine, StoredFile),
341328
check_valid_defaults(Line, File, Name, Arity, Kind, Defaults, LastDefaults, LastHasBody);
342329
[] ->
343330
FinalLine = Line,
344331
FinalLocation = Location,
345332
FinalDefaults = {Defaults, HasBody, Defaults}
346333
end,
347-
Check andalso ets:insert(Table, {last, {Name, Arity}}),
348-
ets:insert(CTable, [{Tuple, Clause} || Clause <- Clauses ]),
349-
ets:insert(Table, {Tuple, Kind, FinalLine, File, Check, FinalLocation, FinalDefaults}).
334+
335+
Check andalso ets:insert(Data, {?last_def, {Name, Arity}}),
336+
ets:insert(Clas, [{Tuple, Clause} || Clause <- Clauses]),
337+
ets:insert(Defs, {Tuple, Kind, FinalLine, File, Check, FinalLocation, FinalDefaults}).
350338

351339
%% Validations
352340

@@ -355,8 +343,8 @@ check_valid_kind(Line, File, Name, Arity, Kind, StoredKind) ->
355343
elixir_errors:form_error([{line, Line}], File, ?MODULE,
356344
{changed_kind, {Name, Arity, StoredKind, Kind}}).
357345

358-
check_valid_clause(Line, File, Name, Arity, Kind, Table, StoredLine, StoredFile) ->
359-
case ets:lookup_element(Table, last, 2) of
346+
check_valid_clause(Line, File, Name, Arity, Kind, Data, StoredLine, StoredFile) ->
347+
case ets:lookup_element(Data, ?last_def, 2) of
360348
{Name,Arity} -> [];
361349
[] -> [];
362350
_ ->
@@ -379,8 +367,8 @@ check_valid_defaults(Line, File, Name, Arity, Kind, _, _, _) ->
379367
elixir_errors:form_error([{line, Line}], File, ?MODULE,
380368
{clauses_with_defaults, {Kind, Name, Arity}}).
381369

382-
check_previous_defaults(Table, Line, Name, Arity, Kind, Defaults, E) ->
383-
Matches = ets:match(Table, {{Name, '$2'}, '$1', '_', '_', '_', '_', {'$3', '_', '_'}}),
370+
check_previous_defaults(Line, Module, Name, Arity, Kind, Defaults, E) ->
371+
Matches = ets:match(elixir_module:defs_table(Module), {{Name, '$2'}, '$1', '_', '_', '_', '_', {'$3', '_', '_'}}),
384372
[ begin
385373
elixir_errors:form_error([{line, Line}], ?m(E, file), ?MODULE,
386374
{defs_with_defaults, Name, {Kind, Arity}, {K, A}})

lib/elixir/src/elixir_def_overridable.erl

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
% Holds the logic responsible for defining overridable functions and handling super.
22
-module(elixir_def_overridable).
3-
-export([store_pending/1, ensure_defined/4,
4-
name/2, store/3, format_error/1]).
3+
-export([setup/1, overridable/1, overridable/2, name/2, super/2, store_pending/1,
4+
ensure_defined/4, format_error/1]).
55
-include("elixir.hrl").
6+
-define(attr, {elixir, overridable}).
7+
8+
setup(Module) ->
9+
overridable(Module, []).
610

711
overridable(Module) ->
8-
ets:lookup_element(elixir_module:data_table(Module), '__overridable', 2).
12+
ets:lookup_element(elixir_module:data_table(Module), ?attr, 2).
913

1014
overridable(Module, Value) ->
11-
ets:insert(elixir_module:data_table(Module), {'__overridable', Value}).
15+
ets:insert(elixir_module:data_table(Module), {?attr, Value}).
1216

1317
%% Check if an overridable function is defined.
1418

@@ -51,11 +55,11 @@ store(Module, Function, GenerateName) ->
5155
end,
5256

5357
Def = {function, Line, FinalName, Arity, Clauses},
54-
elixir_def:store_each(false, FinalKind, File, Location,
55-
elixir_def:table(Module), elixir_def:clauses_table(Module), Defaults, Def)
58+
elixir_def:store_each(false, FinalKind, File, Location, Module, Defaults, Def)
5659
end.
5760

58-
%% Store pending declarations that were not manually made concrete.
61+
super(Module, Function) ->
62+
store(Module, Function, true).
5963

6064
store_pending(Module) ->
6165
_ = [store(Module, X, false) || {X, {_, _, _, false}} <- overridable(Module),
@@ -73,4 +77,4 @@ format_error({no_super, Module, {Name, Arity}}) ->
7377
format_fa({Name, Arity}) ->
7478
A = atom_to_binary(Name, utf8),
7579
B = integer_to_binary(Arity),
76-
<< A/binary, $/, B/binary >>.
80+
<<A/binary, $/, B/binary>>.

0 commit comments

Comments
 (0)