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