X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;f=src%2Floader%2FCompiler.cpp;fp=src%2Floader%2FCompiler.cpp;h=d122643fbedc7c29ddac0eef0ad6fb8d8fe53f3c;hb=8c8061a4f8b88410d6d93c039afe6affc4b69cf2;hp=5575838b83f9664bcb2c21ecbca6f47ec17d8465;hpb=0f30d8254ff8b9e63795960ec031577cf68fbf95;p=l2e.git diff --git a/src/loader/Compiler.cpp b/src/loader/Compiler.cpp index 5575838..d122643 100644 --- a/src/loader/Compiler.cpp +++ b/src/loader/Compiler.cpp @@ -1,26 +1,27 @@ -/* - * Compiler.cpp - * - * Created on: Sep 11, 2012 - * Author: holy - */ - #include "Compiler.h" #include "Interpreter.h" +#include "TypeDescription.h" #include #include +#include #include #include #include +#include #include +#include #include +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::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::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::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 >::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(&fileHeader), sizeof(ObjectFileHeader)); - for(map >::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(&to), sizeof(TypeOffset)); + Write(out, &fileHeader, sizeof(ObjectFileHeader)); +} + +void Compiler::WriteOwnStrings(ostream &out) { + for (set::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::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(&to), sizeof(TypeOffset)); } void Compiler::WriteExports(ostream &out) { - int nameOffset(fileHeader.externalStringsBegin); - for (set::const_iterator i(intp.ExportedIdentifiers().begin()), end(intp.ExportedIdentifiers().end()); i != end; ++i) { - const Interpreter::ParsedDefinition &dfn(intp.GetDefinition(*i)); + for (set::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(&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::const_iterator i(intp.PostponedDefinitions().begin()), end(intp.PostponedDefinitions().end()); i != end; ++i) { + for(vector::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(&ext), sizeof(External)); - nameOffset += std::strlen(i->identifier) + 1; + PrepareExternal(ext, *i); + Write(out, &ext, sizeof(External)); } } -void Compiler::WriteExportStrings(ostream &out) { - for (set::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 >::const_iterator + i(intp.Values().begin()), end(intp.Values().end()); + i != end; ++i) { + const TypeDescription &td(TypeDescription::Get(i->first)); + for (vector::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::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::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::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(&ip), sizeof(ImageProperties)); - SDL_LockSurface(i->second); - Write(out, reinterpret_cast(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(data)) + 1; + break; + default: + object.size = td.Size(); + break; } } -void Compiler::WriteObjects(ostream &out) { - for (map >::const_iterator i(intp.Values().begin()), end(intp.Values().end()); i != end; ++i) { - const TypeDescription &td(TypeDescription::Get(i->first)); - for (vector::const_iterator j(i->second.begin()), jend(i->second.end()); j != jend; ++j) { - Write(out, reinterpret_cast(*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(&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(&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(i); + map::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(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( + object + fd.Offset()); + if (!(*dest)) { + continue; + } + map::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(destOffset); + } +} + + +void Compiler::Write(ostream &out, const void *data, int amount) { + out.write(reinterpret_cast(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); -} - }