]> git.localhorst.tv Git - l2e.git/blobdiff - src/loader/Compiler.cpp
new object file format in compiler
[l2e.git] / src / loader / Compiler.cpp
index 5575838b83f9664bcb2c21ecbca6f47ec17d8465..d122643fbedc7c29ddac0eef0ad6fb8d8fe53f3c 100644 (file)
@@ -1,26 +1,27 @@
-/*
- * Compiler.cpp
- *
- *  Created on: Sep 11, 2012
- *      Author: holy
- */
-
 #include "Compiler.h"
 
 #include "Interpreter.h"
+#include "TypeDescription.h"
 
 #include <climits>
 #include <cstring>
+#include <iostream>
 #include <map>
 #include <ostream>
 #include <set>
+#include <stdexcept>
 #include <string>
+#include <utility>
 #include <vector>
 
+using std::iostream;
+using std::make_pair;
 using std::map;
 using std::ostream;
+using std::runtime_error;
 using std::set;
 using std::string;
+using std::strlen;
 using std::vector;
 
 namespace loader {
@@ -28,151 +29,254 @@ namespace loader {
 Compiler::Compiler(const Interpreter &intp)
 : intp(intp)
 , cursor(0) {
-       int headerSize(sizeof(ObjectFileHeader) + (intp.Values().size() * sizeof(TypeOffset)));
-
-       fileHeader.exportsBegin = headerSize + Remaining(headerSize, 16);
-       fileHeader.exportsEnd = fileHeader.exportsBegin + (intp.ExportedIdentifiers().size() * sizeof(Export));
+       int headerSize(sizeof(ObjectFileHeader));
 
-       fileHeader.externalsBegin = fileHeader.exportsEnd + Remaining(fileHeader.exportsEnd, 16);
-       fileHeader.externalsEnd = fileHeader.externalsBegin + (intp.PostponedDefinitions().size() * sizeof(External));
-
-       fileHeader.exportStringsBegin = fileHeader.externalsEnd + Remaining(fileHeader.externalsEnd, 16);
-       fileHeader.exportStringsEnd = fileHeader.exportStringsBegin;
-       for (set<string>::const_iterator i(intp.ExportedIdentifiers().begin()), end(intp.ExportedIdentifiers().end()); i != end; ++i) {
-               fileHeader.exportStringsEnd += i->size() + 1;
-       }
+       fileHeader.exportsBegin = headerSize;
+       fileHeader.exportsEnd = fileHeader.exportsBegin
+                       + (intp.ExportedIdentifiers().size() * sizeof(Export));
 
-       fileHeader.externalStringsBegin = fileHeader.exportStringsEnd + Remaining(fileHeader.exportStringsEnd, 16);
-       fileHeader.externalStringsEnd = fileHeader.externalStringsBegin;
-       for(vector<Interpreter::PostponedDefinition>::const_iterator i(intp.PostponedDefinitions().begin()), end(intp.PostponedDefinitions().end()); i != end; ++i) {
-               fileHeader.externalStringsEnd += std::strlen(i->identifier) + 1;
-       }
-
-       fileHeader.imagesBegin = fileHeader.externalStringsEnd + Remaining(fileHeader.externalStringsEnd, 16);
-       fileHeader.imagesEnd = fileHeader.imagesBegin + (intp.Images().size() * sizeof(ImageProperties));
-       for (map<string, SDL_Surface *>::const_iterator i(intp.Images().begin()), end(intp.Images().end()); i != end; ++i) {
-               fileHeader.imagesEnd += i->second->w * i->second->h * i->second->format->BytesPerPixel;
-       }
+       fileHeader.externalsBegin = fileHeader.exportsEnd;
+       fileHeader.externalsEnd = fileHeader.externalsBegin
+                       + (intp.PostponedDefinitions().size() * sizeof(External));
 
-       fileHeader.objectsBegin = fileHeader.imagesEnd + Remaining(fileHeader.imagesEnd, 16);
-       fileHeader.objectsEnd = fileHeader.objectsBegin;
-       for (map<int, vector<void *> >::const_iterator i(intp.Values().begin()), end(intp.Values().end()); i != end; ++i) {
-               const TypeDescription &td(TypeDescription::Get(i->first));
-               objectOffsets[i->first] = fileHeader.objectsEnd;
-               fileHeader.objectsEnd += td.Size() * i->second.size();
-               fileHeader.objectsEnd += Remaining(fileHeader.objectsEnd, 16);
-       }
+       fileHeader.objectsBegin = fileHeader.externalsEnd
+                       + Remaining(fileHeader.externalsEnd, 16);
 }
 
-void Compiler::Write(ostream &out) {
-       WriteHeader(out);
+void Compiler::Write(iostream &out) {
+       ReserveHeader(out);
+       WriteObjects(out);
+       WriteOwnStrings(out);
+       fileHeader.objectsEnd = cursor;
        Pad(out, 16);
+       fileHeader.arraysBegin = cursor;
+       WriteArrays(out);
+       fileHeader.arraysEnd = cursor;
+       out.seekp(0);
+       cursor = 0;
+       WriteHeader(out);
        WriteExports(out);
-       Pad(out, 16);
        WriteExternals(out);
-       Pad(out, 16);
-       WriteExportStrings(out);
-       Pad(out, 16);
-       WriteExternalStrings(out);
-       Pad(out, 16);
-       WriteImages(out);
-       Pad(out, 16);
-       WriteObjects(out);
+       out.seekg(fileHeader.objectsBegin);
+       out.clear();
+       Relocate(out);
 }
 
+void Compiler::ReserveHeader(ostream &out) {
+       Fill(out, fileHeader.objectsBegin);
+}
 
 void Compiler::WriteHeader(ostream &out) {
-       Write(out, reinterpret_cast<const char *>(&fileHeader), sizeof(ObjectFileHeader));
-       for(map<int, vector<void *> >::const_iterator i(intp.Values().begin()), end(intp.Values().end()); i != end; ++i) {
-               TypeOffset to;
-               to.typeId = i->first;
-               to.begin = GetTypeOffset(i->first);
-               to.end = to.begin + (i->second.size() * TypeDescription::Get(i->first).Size());
-               Write(out, reinterpret_cast<const char *>(&to), sizeof(TypeOffset));
+       Write(out, &fileHeader, sizeof(ObjectFileHeader));
+}
+
+void Compiler::WriteOwnStrings(ostream &out) {
+       for (set<string>::const_iterator
+                       i(intp.ExportedIdentifiers().begin()),
+                       end(intp.ExportedIdentifiers().end());
+                       i != end; ++i) {
+               addressMap.insert(make_pair(i->c_str(), cursor));
+               Object object;
+               object.typeId = Interpreter::STRING_ID;
+               object.size = i->size() + 1;
+               Write(out, &object, sizeof(Object));
+               Write(out, i->c_str(), object.size);
+       }
+       for(vector<Interpreter::PostponedDefinition>::const_iterator
+                       i(intp.PostponedDefinitions().begin()),
+                       end(intp.PostponedDefinitions().end());
+                       i != end; ++i) {
+               addressMap.insert(make_pair(
+                               i->identifier.c_str(), cursor));
+               Object object;
+               object.typeId = Interpreter::STRING_ID;
+               object.size = i->identifier.size() + 1;
+               Write(out, &object, sizeof(Object));
+               Write(out, i->identifier.c_str(), object.size);
        }
-       TypeOffset to;
-       to.typeId = 0;
-       to.begin = 0;
-       to.end = 0;
-       Write(out, reinterpret_cast<const char *>(&to), sizeof(TypeOffset));
 }
 
 void Compiler::WriteExports(ostream &out) {
-       int nameOffset(fileHeader.externalStringsBegin);
-       for (set<string>::const_iterator i(intp.ExportedIdentifiers().begin()), end(intp.ExportedIdentifiers().end()); i != end; ++i) {
-               const Interpreter::ParsedDefinition &dfn(intp.GetDefinition(*i));
+       for (set<string>::const_iterator
+                       i(intp.ExportedIdentifiers().begin()),
+                       end(intp.ExportedIdentifiers().end());
+                       i != end; ++i) {
                Export exp;
-               exp.nameOffset = nameOffset;
-               exp.typeId = dfn.type;
-               exp.dataOffset = ObjectOffset(dfn.type, dfn.id);
-               Write(out, reinterpret_cast<char *>(&exp), sizeof(Export));
-               nameOffset += i->size() + 1;
+               PrepareExport(exp, *i);
+               Write(out, &exp, sizeof(Export));
        }
 }
 
 void Compiler::WriteExternals(ostream &out) {
-       int nameOffset(fileHeader.exportStringsBegin);
-       for(vector<Interpreter::PostponedDefinition>::const_iterator i(intp.PostponedDefinitions().begin()), end(intp.PostponedDefinitions().end()); i != end; ++i) {
+       for(vector<Interpreter::PostponedDefinition>::const_iterator
+                       i(intp.PostponedDefinitions().begin()),
+                       end(intp.PostponedDefinitions().end());
+                       i != end; ++i) {
                External ext;
-               ext.nameOffset = nameOffset;
-               ext.referenceOffset = ReferenceOffset(i->type, i->id, i->offset);
-               ext.inlined = i->inlined ? 1 : 0;
-               Write(out, reinterpret_cast<char *>(&ext), sizeof(External));
-               nameOffset += std::strlen(i->identifier) + 1;
+               PrepareExternal(ext, *i);
+               Write(out, &ext, sizeof(External));
        }
 }
 
-void Compiler::WriteExportStrings(ostream &out) {
-       for (set<string>::const_iterator i(intp.ExportedIdentifiers().begin()), end(intp.ExportedIdentifiers().end()); i != end; ++i) {
-               Write(out, i->c_str(), i->size() + 1);
+void Compiler::WriteObjects(ostream &out) {
+       Pad(out, 16);
+       for (map<int, vector<void *> >::const_iterator
+                       i(intp.Values().begin()), end(intp.Values().end());
+                       i != end; ++i) {
+               const TypeDescription &td(TypeDescription::Get(i->first));
+               for (vector<void *>::const_iterator
+                               j(i->second.begin()), jend(i->second.end());
+                               j != jend; ++j) {
+                       Object object;
+                       PrepareObject(object, td, *j);
+                       Write(out, &object, sizeof(Object));
+                       Write(out, *j, object.size);
+               }
        }
 }
 
-void Compiler::WriteExternalStrings(ostream &out) {
-       for(vector<Interpreter::PostponedDefinition>::const_iterator i(intp.PostponedDefinitions().begin()), end(intp.PostponedDefinitions().end()); i != end; ++i) {
-               Write(out, i->identifier, std::strlen(i->identifier) + 1);
+void Compiler::WriteArrays(ostream &out) {
+       Pad(out, 16);
+       for (vector<Interpreter::Array>::const_iterator
+                       i(intp.Arrays().begin()), end(intp.Arrays().end());
+                       i != end; ++i) {
+               Array array;
+               array.size = i->size;
+               array.ref = i->ref;
+               Write(out, &array, sizeof(Array));
+               addressMap.insert(make_pair(i->data, cursor));
+               Write(out, i->data, array.size);
        }
 }
 
-void Compiler::WriteImages(ostream &out) {
-       for (map<string, SDL_Surface *>::const_iterator i(intp.Images().begin()), end(intp.Images().end()); i != end; ++i) {
-               ImageProperties ip;
-               ip.flags = i->second->flags;
-               ip.width = i->second->w;
-               ip.height = i->second->h;
-               ip.depth = i->second->format->BitsPerPixel;
-               ip.pitch = i->second->pitch;
-               ip.rmask = i->second->format->Rmask;
-               ip.gmask = i->second->format->Gmask;
-               ip.bmask = i->second->format->Bmask;
-               ip.amask = i->second->format->Amask;
-               Write(out, reinterpret_cast<char *>(&ip), sizeof(ImageProperties));
-               SDL_LockSurface(i->second);
-               Write(out, reinterpret_cast<char *>(i->second->pixels), ip.width * ip.height * (ip.depth / CHAR_BIT + (ip.depth % CHAR_BIT ? 1 : 0)));
-               // TODO: store palette too?
-               SDL_UnlockSurface(i->second);
+
+void Compiler::PrepareExport(Export &exp, const string &str) {
+       const Interpreter::ParsedDefinition &dfn
+                       = intp.GetDefinition(str);
+       exp.nameOffset = addressMap[str.c_str()];
+       exp.typeId = dfn.type;
+       exp.dataOffset = addressMap[intp.GetObject(dfn.type, str)];
+}
+
+void Compiler::PrepareExternal(
+               External &ext,
+               const Interpreter::PostponedDefinition &def) {
+       ext.nameOffset = addressMap[def.identifier.c_str()];
+       ext.referenceOffset = addressMap[def.object] + (def.dest - def.object);
+       ext.inlined = 0;
+       if (def.inlined) ext.inlined |= 1;
+       if (def.aggregate) ext.inlined |= 2;
+}
+
+void Compiler::PrepareObject(
+               Object &object,
+               const TypeDescription &td,
+               void *data) {
+       addressMap.insert(make_pair(data, cursor + sizeof(Object)));
+       object.typeId = td.TypeId();
+       switch (td.TypeId()) {
+               case Interpreter::STRING_ID:
+                       object.size = strlen(
+                                       reinterpret_cast<char *>(data)) + 1;
+                       break;
+               default:
+                       object.size = td.Size();
+                       break;
        }
 }
 
-void Compiler::WriteObjects(ostream &out) {
-       for (map<int, vector<void *> >::const_iterator i(intp.Values().begin()), end(intp.Values().end()); i != end; ++i) {
-               const TypeDescription &td(TypeDescription::Get(i->first));
-               for (vector<void *>::const_iterator j(i->second.begin()), jend(i->second.end()); j != jend; ++j) {
-                       Write(out, reinterpret_cast<char *>(*j), td.Size());
+void Compiler::Relocate(iostream &out) {
+       int bufferSize = TypeDescription::GetMaxSize();
+       char *buffer = new char[bufferSize];
+       for (;out && out.tellg() < fileHeader.objectsEnd;) {
+               // 20785
+               Object object;
+               out.read(reinterpret_cast<char *>(&object), sizeof(Object));
+               const TypeDescription &td = TypeDescription::Get(object.typeId);
+               if (td.NeedsLinking()) {
+                       out.seekg(object.size, iostream::cur);
+                       continue;
+               }
+               unsigned int pos = out.tellg();
+               out.seekg(pos);
+               out.read(buffer, object.size);
+               Relocate(buffer, td);
+               out.seekp(pos);
+               out.write(buffer, object.size);
+               out.seekg(out.tellp());
+       }
+       delete[] buffer;
+       out.seekg(fileHeader.arraysBegin);
+       Array array;
+       for (; out && out.tellg() < fileHeader.arraysEnd;) {
+               out.read(reinterpret_cast<char *>(&array), sizeof(Array));
+               if (!array.ref) {
+                       out.seekg(array.size);
+                       continue;
                }
-               Pad(out, 16);
+               buffer = new char[array.size];
+               unsigned int pos = out.tellg();
+               out.seekg(pos);
+               out.read(buffer, array.size);
+               RelocateArray(buffer, array.size);
+               out.seekp(pos);
+               out.write(buffer, array.size);
+               out.seekg(out.tellp());
+               delete[] buffer;
        }
 }
 
+void Compiler::RelocateArray(char *array, int size) {
+       for (char *i = array, *end = array + size;
+                       i < end; i += sizeof(void *)) {
+               char **dest = reinterpret_cast<char **>(i);
+               map<const void *, unsigned int>::const_iterator
+                               entry(addressMap.find(*dest));
+               if (entry == addressMap.end()) {
+                       throw runtime_error("unable to relocate array member");
+               }
+               unsigned int destOffset = entry->second;
+               *dest = reinterpret_cast<char *>(destOffset);
+       }
+}
 
-void Compiler::Write(ostream &out, const char *data, int amount) {
-       out.write(data, amount);
+void Compiler::Relocate(char *object, const TypeDescription &td) {
+       for (TypeDescription::FieldIterator
+                       i(td.FieldsBegin()), end(td.FieldsEnd());
+                       i != end; ++i) {
+               const FieldDescription &fd = i->second;
+               if (!fd.IsAggregate() && !fd.IsReferenced()) {
+                       continue;
+               }
+               char **dest = reinterpret_cast<char **>(
+                               object + fd.Offset());
+               if (!(*dest)) {
+                       continue;
+               }
+               map<const void *, unsigned int>::const_iterator
+                               entry(addressMap.find(*dest));
+               if (entry == addressMap.end()) {
+                       throw runtime_error(string("unable to relocate field ")
+                                       + i->first + " in object of type " + td.TypeName());
+               }
+               unsigned int destOffset = entry->second;
+               *dest = reinterpret_cast<char *>(destOffset);
+       }
+}
+
+
+void Compiler::Write(ostream &out, const void *data, int amount) {
+       out.write(reinterpret_cast<const char *>(data), amount);
        cursor += amount;
 }
 
 void Compiler::Pad(ostream &out, int to) {
-       for (int remaining(Remaining(cursor, to)); remaining > 0; --remaining) {
-               out.put(0);
+       Fill(out, Remaining(cursor, to));
+}
+
+void Compiler::Fill(ostream &out, int count, char c) {
+       for (int remaining(count); remaining > 0; --remaining) {
+               out.put(c);
                ++cursor;
        }
 }
@@ -182,18 +286,4 @@ int Compiler::Remaining(int value, int alignment) {
        return (have > 0) ? (16 - have) : 0;
 }
 
-
-int Compiler::ReferenceOffset(int typeId, int objectId, std::ptrdiff_t fieldOffset) const {
-       return ObjectOffset(typeId, objectId) + fieldOffset;
-}
-
-int Compiler::ObjectOffset(int typeId, int objectId) const {
-       const TypeDescription &td(TypeDescription::Get(typeId));
-       return GetTypeOffset(typeId) + (td.Size() * objectId);
-}
-
-int Compiler::GetTypeOffset(int typeId) const {
-       return objectOffsets.at(typeId);
-}
-
 }