]> git.localhorst.tv Git - l2e.git/blob - src/loader/Compiler.cpp
96c0cc1425b643a8068a7b5ff6c8e2ff3697069e
[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.inlined = 0;
198         if (def.inlined) ext.inlined |= 1;
199         if (def.aggregate) ext.inlined |= 2;
200 }
201
202 void Compiler::PrepareObject(
203                 Object &object,
204                 const TypeDescription &td,
205                 void *data) {
206         object.typeId = td.TypeId();
207         switch (td.TypeId()) {
208                 case Interpreter::STRING_ID:
209                         object.size = strlen(
210                                         reinterpret_cast<char *>(data)) + 1;
211                         break;
212                 default:
213                         object.size = td.Size();
214                         break;
215         }
216 }
217
218 void Compiler::Relocate(iostream &out) {
219         int bufferSize = TypeDescription::GetMaxSize();
220         char *buffer = new char[bufferSize];
221         for (;out && out.tellg() < fileHeader.objectsEnd;) {
222                 Object object;
223                 out.read(reinterpret_cast<char *>(&object), sizeof(Object));
224                 const TypeDescription &td = TypeDescription::Get(object.typeId);
225                 unsigned int pos = out.tellg();
226
227                 out.read(buffer, object.size);
228                 Relocate(pos, buffer, td);
229                 out.seekp(pos);
230                 out.write(buffer, object.size);
231                 out.seekg(out.tellp());
232         }
233         delete[] buffer;
234         out.seekg(fileHeader.arraysBegin);
235         Array array;
236         for (; out && out.tellg() < fileHeader.arraysEnd;) {
237                 out.read(reinterpret_cast<char *>(&array), sizeof(Array));
238                 buffer = new char[array.size];
239                 unsigned int pos = out.tellg();
240                 out.read(buffer, array.size);
241                 if (array.ref) {
242                         RelocateArray(buffer, array.size);
243                 } else {
244                         const TypeDescription &td = TypeDescription::Get(array.typeId);
245                         for (char *i = buffer, *end = buffer + array.size;
246                                         i < end; i += td.Size()) {
247                                 Relocate(pos + (i - buffer), i, td);
248                         }
249                 }
250                 out.seekp(pos);
251                 out.write(buffer, array.size);
252                 out.seekg(out.tellp());
253                 delete[] buffer;
254         }
255 }
256
257 void Compiler::RelocateArray(char *array, int size) {
258         for (char *i = array, *end = array + size;
259                         i < end; i += sizeof(void *)) {
260                 char **dest = reinterpret_cast<char **>(i);
261                 map<const void *, unsigned int>::const_iterator
262                                 entry(addressMap.find(*dest));
263                 if (entry == addressMap.end()) {
264                         throw runtime_error("unable to relocate array member");
265                 }
266                 unsigned int destOffset = entry->second;
267                 *dest = reinterpret_cast<char *>(destOffset);
268         }
269 }
270
271 void Compiler::Relocate(
272                 unsigned int pos,
273                 char *object,
274                 const TypeDescription &td) {
275         for (TypeDescription::FieldIterator
276                         i(td.FieldsBegin()), end(td.FieldsEnd());
277                         i != end; ++i) {
278                 const FieldDescription &fd = i->second;
279                 if (fd.IsAggregate() || fd.IsReferenced()) {
280                         char **dest = reinterpret_cast<char **>(
281                                         object + fd.Offset());
282                         if (!(*dest)) {
283                                 continue;
284                         }
285                         if (fd.TypeId() == Interpreter::IMAGE_ID) {
286                                 images.insert(make_pair(
287                                                 pos + fd.Offset(), *dest));
288                         }
289                         map<const void *, unsigned int>::const_iterator
290                                         entry(addressMap.find(*dest));
291                         if (entry == addressMap.end()) {
292                                 throw runtime_error(string("unable to relocate field ")
293                                                 + i->first + " in object of type " + td.TypeName());
294                         }
295                         unsigned int destOffset = entry->second;
296                         *dest = reinterpret_cast<char *>(destOffset);
297                 } else {
298                         const TypeDescription &nestedType
299                                         = TypeDescription::Get(fd.TypeId());
300                         Relocate(pos + fd.Offset(), object + fd.Offset(), nestedType);
301                 }
302         }
303 }
304
305
306 void Compiler::Write(ostream &out, const void *data, int amount) {
307         out.write(reinterpret_cast<const char *>(data), amount);
308 }
309
310 void Compiler::Pad(ostream &out, int to) {
311         Fill(out, Remaining(out.tellp(), to));
312 }
313
314 void Compiler::Fill(ostream &out, int count, char c) {
315         for (int remaining(count); remaining > 0; --remaining) {
316                 out.put(c);
317         }
318 }
319
320 int Compiler::Remaining(int value, int alignment) {
321         int have(value % alignment);
322         return (have > 0) ? (16 - have) : 0;
323 }
324
325 }