]> git.localhorst.tv Git - l2e.git/blob - src/loader/Compiler.cpp
d122643fbedc7c29ddac0eef0ad6fb8d8fe53f3c
[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                 addressMap.insert(make_pair(i->c_str(), cursor));
79                 Object object;
80                 object.typeId = Interpreter::STRING_ID;
81                 object.size = i->size() + 1;
82                 Write(out, &object, sizeof(Object));
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.size = i->size;
145                 array.ref = i->ref;
146                 Write(out, &array, sizeof(Array));
147                 addressMap.insert(make_pair(i->data, cursor));
148                 Write(out, i->data, array.size);
149         }
150 }
151
152
153 void Compiler::PrepareExport(Export &exp, const string &str) {
154         const Interpreter::ParsedDefinition &dfn
155                         = intp.GetDefinition(str);
156         exp.nameOffset = addressMap[str.c_str()];
157         exp.typeId = dfn.type;
158         exp.dataOffset = addressMap[intp.GetObject(dfn.type, str)];
159 }
160
161 void Compiler::PrepareExternal(
162                 External &ext,
163                 const Interpreter::PostponedDefinition &def) {
164         ext.nameOffset = addressMap[def.identifier.c_str()];
165         ext.referenceOffset = addressMap[def.object] + (def.dest - def.object);
166         ext.inlined = 0;
167         if (def.inlined) ext.inlined |= 1;
168         if (def.aggregate) ext.inlined |= 2;
169 }
170
171 void Compiler::PrepareObject(
172                 Object &object,
173                 const TypeDescription &td,
174                 void *data) {
175         addressMap.insert(make_pair(data, cursor + sizeof(Object)));
176         object.typeId = td.TypeId();
177         switch (td.TypeId()) {
178                 case Interpreter::STRING_ID:
179                         object.size = strlen(
180                                         reinterpret_cast<char *>(data)) + 1;
181                         break;
182                 default:
183                         object.size = td.Size();
184                         break;
185         }
186 }
187
188 void Compiler::Relocate(iostream &out) {
189         int bufferSize = TypeDescription::GetMaxSize();
190         char *buffer = new char[bufferSize];
191         for (;out && out.tellg() < fileHeader.objectsEnd;) {
192                 // 20785
193                 Object object;
194                 out.read(reinterpret_cast<char *>(&object), sizeof(Object));
195                 const TypeDescription &td = TypeDescription::Get(object.typeId);
196                 if (td.NeedsLinking()) {
197                         out.seekg(object.size, iostream::cur);
198                         continue;
199                 }
200                 unsigned int pos = out.tellg();
201                 out.seekg(pos);
202                 out.read(buffer, object.size);
203                 Relocate(buffer, td);
204                 out.seekp(pos);
205                 out.write(buffer, object.size);
206                 out.seekg(out.tellp());
207         }
208         delete[] buffer;
209         out.seekg(fileHeader.arraysBegin);
210         Array array;
211         for (; out && out.tellg() < fileHeader.arraysEnd;) {
212                 out.read(reinterpret_cast<char *>(&array), sizeof(Array));
213                 if (!array.ref) {
214                         out.seekg(array.size);
215                         continue;
216                 }
217                 buffer = new char[array.size];
218                 unsigned int pos = out.tellg();
219                 out.seekg(pos);
220                 out.read(buffer, array.size);
221                 RelocateArray(buffer, array.size);
222                 out.seekp(pos);
223                 out.write(buffer, array.size);
224                 out.seekg(out.tellp());
225                 delete[] buffer;
226         }
227 }
228
229 void Compiler::RelocateArray(char *array, int size) {
230         for (char *i = array, *end = array + size;
231                         i < end; i += sizeof(void *)) {
232                 char **dest = reinterpret_cast<char **>(i);
233                 map<const void *, unsigned int>::const_iterator
234                                 entry(addressMap.find(*dest));
235                 if (entry == addressMap.end()) {
236                         throw runtime_error("unable to relocate array member");
237                 }
238                 unsigned int destOffset = entry->second;
239                 *dest = reinterpret_cast<char *>(destOffset);
240         }
241 }
242
243 void Compiler::Relocate(char *object, const TypeDescription &td) {
244         for (TypeDescription::FieldIterator
245                         i(td.FieldsBegin()), end(td.FieldsEnd());
246                         i != end; ++i) {
247                 const FieldDescription &fd = i->second;
248                 if (!fd.IsAggregate() && !fd.IsReferenced()) {
249                         continue;
250                 }
251                 char **dest = reinterpret_cast<char **>(
252                                 object + fd.Offset());
253                 if (!(*dest)) {
254                         continue;
255                 }
256                 map<const void *, unsigned int>::const_iterator
257                                 entry(addressMap.find(*dest));
258                 if (entry == addressMap.end()) {
259                         throw runtime_error(string("unable to relocate field ")
260                                         + i->first + " in object of type " + td.TypeName());
261                 }
262                 unsigned int destOffset = entry->second;
263                 *dest = reinterpret_cast<char *>(destOffset);
264         }
265 }
266
267
268 void Compiler::Write(ostream &out, const void *data, int amount) {
269         out.write(reinterpret_cast<const char *>(data), amount);
270         cursor += amount;
271 }
272
273 void Compiler::Pad(ostream &out, int to) {
274         Fill(out, Remaining(cursor, to));
275 }
276
277 void Compiler::Fill(ostream &out, int count, char c) {
278         for (int remaining(count); remaining > 0; --remaining) {
279                 out.put(c);
280                 ++cursor;
281         }
282 }
283
284 int Compiler::Remaining(int value, int alignment) {
285         int have(value % alignment);
286         return (have > 0) ? (16 - have) : 0;
287 }
288
289 }