]> git.localhorst.tv Git - l2e.git/blob - src/loader/Compiler.cpp
b583aabb298a46017fb87d23d1772e1e79fed12e
[l2e.git] / src / loader / Compiler.cpp
1 #include "Compiler.h"
2
3 #include "Interpreter.h"
4 #include "TypeDescription.h"
5
6 #include <climits>
7 #include <cstring>
8 #include <iostream>
9 #include <map>
10 #include <ostream>
11 #include <set>
12 #include <stdexcept>
13 #include <string>
14 #include <utility>
15 #include <vector>
16
17 using std::iostream;
18 using std::make_pair;
19 using std::map;
20 using std::ostream;
21 using std::runtime_error;
22 using std::set;
23 using std::string;
24 using std::strlen;
25 using std::vector;
26
27 namespace loader {
28
29 Compiler::Compiler(const Interpreter &intp)
30 : intp(intp)
31 , cursor(0) {
32         int headerSize(sizeof(ObjectFileHeader));
33
34         fileHeader.exportsBegin = headerSize;
35         fileHeader.exportsEnd = fileHeader.exportsBegin
36                         + (intp.ExportedIdentifiers().size() * sizeof(Export));
37
38         fileHeader.externalsBegin = fileHeader.exportsEnd;
39         fileHeader.externalsEnd = fileHeader.externalsBegin
40                         + (intp.PostponedDefinitions().size() * sizeof(External));
41
42         fileHeader.objectsBegin = fileHeader.externalsEnd
43                         + Remaining(fileHeader.externalsEnd, 16);
44 }
45
46 void Compiler::Write(iostream &out) {
47         ReserveHeader(out);
48         WriteObjects(out);
49         WriteOwnStrings(out);
50         fileHeader.objectsEnd = cursor;
51         Pad(out, 16);
52         fileHeader.arraysBegin = cursor;
53         WriteArrays(out);
54         fileHeader.arraysEnd = cursor;
55         out.seekp(0);
56         cursor = 0;
57         WriteHeader(out);
58         WriteExports(out);
59         WriteExternals(out);
60         out.seekg(fileHeader.objectsBegin);
61         out.clear();
62         Relocate(out);
63 }
64
65 void Compiler::ReserveHeader(ostream &out) {
66         Fill(out, fileHeader.objectsBegin);
67 }
68
69 void Compiler::WriteHeader(ostream &out) {
70         Write(out, &fileHeader, sizeof(ObjectFileHeader));
71 }
72
73 void Compiler::WriteOwnStrings(ostream &out) {
74         for (set<string>::const_iterator
75                         i(intp.ExportedIdentifiers().begin()),
76                         end(intp.ExportedIdentifiers().end());
77                         i != end; ++i) {
78                 Object object;
79                 object.typeId = Interpreter::STRING_ID;
80                 object.size = i->size() + 1;
81                 Write(out, &object, sizeof(Object));
82                 addressMap.insert(make_pair(i->c_str(), cursor));
83                 Write(out, i->c_str(), object.size);
84         }
85         for(vector<Interpreter::PostponedDefinition>::const_iterator
86                         i(intp.PostponedDefinitions().begin()),
87                         end(intp.PostponedDefinitions().end());
88                         i != end; ++i) {
89                 addressMap.insert(make_pair(
90                                 i->identifier.c_str(), cursor));
91                 Object object;
92                 object.typeId = Interpreter::STRING_ID;
93                 object.size = i->identifier.size() + 1;
94                 Write(out, &object, sizeof(Object));
95                 Write(out, i->identifier.c_str(), object.size);
96         }
97 }
98
99 void Compiler::WriteExports(ostream &out) {
100         for (set<string>::const_iterator
101                         i(intp.ExportedIdentifiers().begin()),
102                         end(intp.ExportedIdentifiers().end());
103                         i != end; ++i) {
104                 Export exp;
105                 PrepareExport(exp, *i);
106                 Write(out, &exp, sizeof(Export));
107         }
108 }
109
110 void Compiler::WriteExternals(ostream &out) {
111         for(vector<Interpreter::PostponedDefinition>::const_iterator
112                         i(intp.PostponedDefinitions().begin()),
113                         end(intp.PostponedDefinitions().end());
114                         i != end; ++i) {
115                 External ext;
116                 PrepareExternal(ext, *i);
117                 Write(out, &ext, sizeof(External));
118         }
119 }
120
121 void Compiler::WriteObjects(ostream &out) {
122         Pad(out, 16);
123         for (map<int, vector<void *> >::const_iterator
124                         i(intp.Values().begin()), end(intp.Values().end());
125                         i != end; ++i) {
126                 const TypeDescription &td(TypeDescription::Get(i->first));
127                 for (vector<void *>::const_iterator
128                                 j(i->second.begin()), jend(i->second.end());
129                                 j != jend; ++j) {
130                         Object object;
131                         PrepareObject(object, td, *j);
132                         Write(out, &object, sizeof(Object));
133                         Write(out, *j, object.size);
134                 }
135         }
136 }
137
138 void Compiler::WriteArrays(ostream &out) {
139         Pad(out, 16);
140         for (vector<Interpreter::Array>::const_iterator
141                         i(intp.Arrays().begin()), end(intp.Arrays().end());
142                         i != end; ++i) {
143                 Array array;
144                 array.typeId = i->typeId;
145                 array.size = i->size;
146                 array.ref = i->ref;
147                 Write(out, &array, sizeof(Array));
148                 addressMap.insert(make_pair(i->data, cursor));
149                 Write(out, i->data, array.size);
150         }
151 }
152
153
154 void Compiler::PrepareExport(Export &exp, const string &str) {
155         const Interpreter::ParsedDefinition &dfn
156                         = intp.GetDefinition(str);
157         exp.nameOffset = addressMap[str.c_str()];
158         exp.typeId = dfn.type;
159         exp.dataOffset = addressMap[intp.GetObject(dfn.type, str)];
160 }
161
162 void Compiler::PrepareExternal(
163                 External &ext,
164                 const Interpreter::PostponedDefinition &def) {
165         ext.nameOffset = addressMap[def.identifier.c_str()];
166         ext.referenceOffset = addressMap[def.object] + (def.dest - def.object);
167         ext.inlined = 0;
168         if (def.inlined) ext.inlined |= 1;
169         if (def.aggregate) ext.inlined |= 2;
170 }
171
172 void Compiler::PrepareObject(
173                 Object &object,
174                 const TypeDescription &td,
175                 void *data) {
176         addressMap.insert(make_pair(data, cursor + sizeof(Object)));
177         object.typeId = td.TypeId();
178         switch (td.TypeId()) {
179                 case Interpreter::STRING_ID:
180                         object.size = strlen(
181                                         reinterpret_cast<char *>(data)) + 1;
182                         break;
183                 default:
184                         object.size = td.Size();
185                         break;
186         }
187 }
188
189 void Compiler::Relocate(iostream &out) {
190         int bufferSize = TypeDescription::GetMaxSize();
191         char *buffer = new char[bufferSize];
192         for (;out && out.tellg() < fileHeader.objectsEnd;) {
193                 // 20785
194                 Object object;
195                 out.read(reinterpret_cast<char *>(&object), sizeof(Object));
196                 const TypeDescription &td = TypeDescription::Get(object.typeId);
197                 if (!td.NeedsLinking()) {
198                         out.seekg(object.size, iostream::cur);
199                         continue;
200                 }
201                 unsigned int pos = out.tellg();
202                 out.seekg(pos);
203                 out.read(buffer, object.size);
204                 Relocate(buffer, td);
205                 out.seekp(pos);
206                 out.write(buffer, object.size);
207                 out.seekg(out.tellp());
208         }
209         delete[] buffer;
210         out.seekg(fileHeader.arraysBegin);
211         Array array;
212         for (; out && out.tellg() < fileHeader.arraysEnd;) {
213                 out.read(reinterpret_cast<char *>(&array), sizeof(Array));
214                 if (array.ref) {
215                         buffer = new char[array.size];
216                         unsigned int pos = out.tellg();
217                         out.seekg(pos);
218                         out.read(buffer, array.size);
219                         RelocateArray(buffer, array.size);
220                         out.seekp(pos);
221                         out.write(buffer, array.size);
222                         out.seekg(out.tellp());
223                         delete[] buffer;
224                 } else {
225                         const TypeDescription &td = TypeDescription::Get(array.typeId);
226                         for (char *i = array.Data(), *end = array.Data() + array.size;
227                                         i < end; i += td.Size()) {
228                                 Relocate(i, td);
229                         }
230                 }
231         }
232 }
233
234 void Compiler::RelocateArray(char *array, int size) {
235         for (char *i = array, *end = array + size;
236                         i < end; i += sizeof(void *)) {
237                 char **dest = reinterpret_cast<char **>(i);
238                 map<const void *, unsigned int>::const_iterator
239                                 entry(addressMap.find(*dest));
240                 if (entry == addressMap.end()) {
241                         throw runtime_error("unable to relocate array member");
242                 }
243                 unsigned int destOffset = entry->second;
244                 *dest = reinterpret_cast<char *>(destOffset);
245         }
246 }
247
248 void Compiler::Relocate(char *object, const TypeDescription &td) {
249         for (TypeDescription::FieldIterator
250                         i(td.FieldsBegin()), end(td.FieldsEnd());
251                         i != end; ++i) {
252                 const FieldDescription &fd = i->second;
253                 if (!fd.IsAggregate() && !fd.IsReferenced()) {
254                         continue;
255                 }
256                 char **dest = reinterpret_cast<char **>(
257                                 object + fd.Offset());
258                 if (!(*dest)) {
259                         continue;
260                 }
261                 map<const void *, unsigned int>::const_iterator
262                                 entry(addressMap.find(*dest));
263                 if (entry == addressMap.end()) {
264                         throw runtime_error(string("unable to relocate field ")
265                                         + i->first + " in object of type " + td.TypeName());
266                 }
267                 unsigned int destOffset = entry->second;
268                 *dest = reinterpret_cast<char *>(destOffset);
269         }
270 }
271
272
273 void Compiler::Write(ostream &out, const void *data, int amount) {
274         out.write(reinterpret_cast<const char *>(data), amount);
275         cursor += amount;
276 }
277
278 void Compiler::Pad(ostream &out, int to) {
279         Fill(out, Remaining(cursor, to));
280 }
281
282 void Compiler::Fill(ostream &out, int count, char c) {
283         for (int remaining(count); remaining > 0; --remaining) {
284                 out.put(c);
285                 ++cursor;
286         }
287 }
288
289 int Compiler::Remaining(int value, int alignment) {
290         int have(value % alignment);
291         return (have > 0) ? (16 - have) : 0;
292 }
293
294 }