-/*
- * 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 {
Compiler::Compiler(const Interpreter &intp)
: intp(intp)
, cursor(0) {
- int headerSize(4 + (5 * sizeof(int)) + (intp.Values().size() * 2 * sizeof(int)));
-
- exportsOffset = headerSize + Remaining(headerSize, 16);
- int exportsSize(intp.ExportedIdentifiers().size() * sizeof(Export));
+ int headerSize(sizeof(ObjectFileHeader));
- externalsOffset = exportsOffset + exportsSize + Remaining(exportsSize, 16);
- int externalsSize(intp.PostponedDefinitions().size() * sizeof(External));
-
- exportStringsOffset = externalsOffset + externalsSize + Remaining(externalsSize, 16);
- int exportStringsSize(0);
- for (set<string>::const_iterator i(intp.ExportedIdentifiers().begin()), end(intp.ExportedIdentifiers().end()); i != end; ++i) {
- exportStringsSize += i->size() + 1;
- }
+ fileHeader.exportsBegin = headerSize;
+ fileHeader.exportsEnd = fileHeader.exportsBegin
+ + (intp.ExportedIdentifiers().size() * sizeof(Export));
- externalStringsOffset = exportStringsOffset + exportStringsSize + Remaining(exportStringsSize, 16);
- int externalStringsSize(0);
- for(vector<Interpreter::PostponedDefinition>::const_iterator i(intp.PostponedDefinitions().begin()), end(intp.PostponedDefinitions().end()); i != end; ++i) {
- externalStringsSize += std::strlen(i->identifier) + 1;
- }
-
- imagesOffset = externalStringsOffset + externalStringsSize + Remaining(externalStringsSize, 16);
- int imagesSize(intp.Images().size() * sizeof(ImageProperties));
- for (map<string, SDL_Surface *>::const_iterator i(intp.Images().begin()), end(intp.Images().end()); i != end; ++i) {
- imagesSize += i->second->w * i->second->h * i->second->format->BytesPerPixel;
- }
+ fileHeader.externalsBegin = fileHeader.exportsEnd;
+ fileHeader.externalsEnd = fileHeader.externalsBegin
+ + (intp.PostponedDefinitions().size() * sizeof(External));
- objectsOffset = imagesOffset + imagesSize + Remaining(imagesSize, 16);
- int objectsSize(0);
- 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] = objectsOffset + objectsSize;
- objectsSize += td.Size() * i->second.size();
- objectsSize += Remaining(objectsSize, 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, "L2O\n", 4);
- Write(out, reinterpret_cast<const char *>(&exportsOffset), sizeof(int));
- Write(out, reinterpret_cast<const char *>(&externalsOffset), sizeof(int));
- Write(out, reinterpret_cast<const char *>(&externalStringsOffset), sizeof(int));
- Write(out, reinterpret_cast<const char *>(&exportStringsOffset), sizeof(int));
- Write(out, reinterpret_cast<const char *>(&imagesOffset), sizeof(int));
- Write(out, reinterpret_cast<const char *>(&objectsOffset), sizeof(int));
- for(map<int, vector<void *> >::const_iterator i(intp.Values().begin()), end(intp.Values().end()); i != end; ++i) {
- Write(out, reinterpret_cast<const char *>(&i->first), sizeof(int));
- int typeOffset(TypeOffset(i->first));
- Write(out, reinterpret_cast<const char *>(&typeOffset), sizeof(int));
+ 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) {
+ Object object;
+ object.typeId = Interpreter::STRING_ID;
+ object.size = i->size() + 1;
+ Write(out, &object, sizeof(Object));
+ addressMap.insert(make_pair(i->c_str(), cursor));
+ 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);
}
}
void Compiler::WriteExports(ostream &out) {
- int nameOffset(externalStringsOffset);
- 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(exportStringsOffset);
- 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.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 * i->second->format->BytesPerPixel);
- // 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;
}
}
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 TypeOffset(typeId) + (td.Size() * objectId);
-}
-
-int Compiler::TypeOffset(int typeId) const {
- return objectOffsets.at(typeId);
-}
-
}