1
%% ``The contents of this file are subject to the Erlang Public License,
2
%% Version 1.1, (the "License"); you may not use this file except in
3
%% compliance with the License. You should have received a copy of the
4
%% Erlang Public License along with this software. If not, it can be
5
%% retrieved via the world wide web at http://www.erlang.org/.
7
%% Software distributed under the License is distributed on an "AS IS"
8
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9
%% the License for the specific language governing rights and limitations
12
%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
13
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
14
%% AB. All Rights Reserved.''
16
%% $Id: beam_dict.erl,v 1.1 2008/12/17 09:53:41 mikpe Exp $
18
%% Purpose : Maintain atom, import, and export tables for assembler.
22
-export([new/0, opcode/2, highest_opcode/1,
23
atom/2, local/4, export/4, import/4, string/2, lambda/5,
24
atom_table/1, local_table/1, export_table/1, import_table/1,
25
string_table/1,lambda_table/1]).
28
{atoms = [], % [{Index, Atom}]
29
exports = [], % [{F, A, Label}]
30
locals = [], % [{F, A, Label}]
31
imports = [], % [{Index, {M, F, A}]
32
strings = [], % Deep list of characters
33
lambdas = [], % [{...}]
43
%% Remembers highest opcode.
45
opcode(Op, Dict) when Dict#asm_dict.highest_opcode > Op -> Dict;
46
opcode(Op, Dict) -> Dict#asm_dict{highest_opcode=Op}.
48
%% Returns the highest opcode encountered.
50
highest_opcode(#asm_dict{highest_opcode=Op}) -> Op.
52
%% Returns the index for an atom (adding it to the atom table if necessary).
53
%% atom(Atom, Dict) -> {Index, Dict'}
55
atom(Atom, Dict) when atom(Atom) ->
56
NextIndex = Dict#asm_dict.next_atom,
57
case lookup_store(Atom, Dict#asm_dict.atoms, NextIndex) of
58
{Index, _, NextIndex} ->
60
{Index, Atoms, NewIndex} ->
61
{Index, Dict#asm_dict{atoms=Atoms, next_atom=NewIndex}}
64
%% Remembers an exported function.
65
%% export(Func, Arity, Label, Dict) -> Dict'
67
export(Func, Arity, Label, Dict0) when atom(Func), integer(Arity), integer(Label) ->
68
{Index, Dict1} = atom(Func, Dict0),
69
Dict1#asm_dict{exports = [{Index, Arity, Label}| Dict1#asm_dict.exports]}.
71
%% Remembers a local function.
72
%% local(Func, Arity, Label, Dict) -> Dict'
74
local(Func, Arity, Label, Dict0) when atom(Func), integer(Arity), integer(Label) ->
75
{Index,Dict1} = atom(Func, Dict0),
76
Dict1#asm_dict{locals = [{Index,Arity,Label}| Dict1#asm_dict.locals]}.
78
%% Returns the index for an import entry (adding it to the import table if necessary).
79
%% import(Mod, Func, Arity, Dict) -> {Index, Dict'}
81
import(Mod, Func, Arity, Dict) when atom(Mod), atom(Func), integer(Arity) ->
82
NextIndex = Dict#asm_dict.next_import,
83
case lookup_store({Mod, Func, Arity}, Dict#asm_dict.imports, NextIndex) of
84
{Index, _, NextIndex} ->
86
{Index, Imports, NewIndex} ->
87
{_, D1} = atom(Mod, Dict#asm_dict{imports=Imports, next_import=NewIndex}),
88
{_, D2} = atom(Func, D1),
92
%% Returns the index for a string in the string table (adding the string to the
93
%% table if necessary).
94
%% string(String, Dict) -> {Offset, Dict'}
96
string(Str, Dict) when list(Str) ->
97
#asm_dict{strings = Strings, string_offset = NextOffset} = Dict,
98
case old_string(Str, Strings) of
102
NewDict = Dict#asm_dict{strings = Strings++Str,
103
string_offset = NextOffset+length(Str)},
104
{NextOffset, NewDict}
107
%% Returns the index for a funentry (adding it to the table if necessary).
108
%% lambda(Dict, Lbl, Index, Uniq, NumFree) -> {Index,Dict'}
110
lambda(Lbl, Index, OldUniq, NumFree, #asm_dict{lambdas=Lambdas0}=Dict) ->
111
OldIndex = length(Lambdas0),
112
Lambdas = [{Lbl,{OldIndex,Lbl,Index,NumFree,OldUniq}}|Lambdas0],
113
{OldIndex,Dict#asm_dict{lambdas=Lambdas}}.
115
%% Returns the atom table.
116
%% atom_table(Dict) -> [Length,AtomString...]
118
atom_table(#asm_dict{atoms=Atoms, next_atom=NumAtoms}) ->
119
Sorted = lists:sort(Atoms),
124
{NumAtoms-1, lists:map(Fun, Sorted)}.
126
%% Returns the table of local functions.
127
%% local_table(Dict) -> {NumLocals, [{Function, Arity, Label}...]}
129
local_table(#asm_dict{locals = Locals}) ->
130
{length(Locals),Locals}.
132
%% Returns the export table.
133
%% export_table(Dict) -> {NumExports, [{Function, Arity, Label}...]}
135
export_table(#asm_dict{exports = Exports}) ->
136
{length(Exports), Exports}.
138
%% Returns the import table.
139
%% import_table(Dict) -> {NumImports, [{Module, Function, Arity}...]}
141
import_table(Dict) ->
142
#asm_dict{imports = Imports, next_import = NumImports} = Dict,
143
Sorted = lists:sort(Imports),
144
Fun = fun({_, {Mod, Func, Arity}}) ->
145
{Atom0, _} = atom(Mod, Dict),
146
{Atom1, _} = atom(Func, Dict),
147
{Atom0, Atom1, Arity}
149
{NumImports, lists:map(Fun, Sorted)}.
151
string_table(#asm_dict{strings = Strings, string_offset = Size}) ->
154
lambda_table(#asm_dict{locals=Loc0,lambdas=Lambdas0}) ->
155
Lambdas1 = sofs:relation(Lambdas0),
156
Loc = sofs:relation([{Lbl,{F,A}} || {F,A,Lbl} <- Loc0]),
157
Lambdas2 = sofs:relative_product1(Lambdas1, Loc),
158
Lambdas = [<<F:32,A:32,Lbl:32,Index:32,NumFree:32,OldUniq:32>> ||
159
{{_,Lbl,Index,NumFree,OldUniq},{F,A}} <- sofs:to_external(Lambdas2)],
160
{length(Lambdas),Lambdas}.
162
%%% Local helper functions.
164
lookup_store(Key, Dict, NextIndex) ->
165
case catch lookup_store1(Key, Dict, NextIndex) of
166
Index when integer(Index) ->
167
{Index, Dict, NextIndex};
169
{Index, NewDict, NextIndex+1}
172
lookup_store1(Key, [Pair|Dict], NextIndex) when Key > element(2, Pair) ->
173
{Index, NewDict} = lookup_store1(Key, Dict, NextIndex),
174
{Index, [Pair|NewDict]};
175
lookup_store1(Key, [{Index, Key}|_Dict], _NextIndex) ->
177
lookup_store1(Key, Dict, NextIndex) ->
178
{NextIndex, [{NextIndex, Key}|Dict]}.
180
%% Search for string Str in the string pool Pool.
181
%% old_string(Str, Pool) -> false | {true, Offset}
183
old_string(Str, Pool) ->
184
old_string(Str, Pool, 0).
186
old_string([C|Str], [C|Pool], Index) ->
187
case lists:prefix(Str, Pool) of
191
old_string([C|Str], Pool, Index+1)
193
old_string(Str, [_|Pool], Index) ->
194
old_string(Str, Pool, Index+1);
195
old_string(_Str, [], _Index) ->