X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;f=src%2Floader%2FCompiler.cpp;h=96c0cc1425b643a8068a7b5ff6c8e2ff3697069e;hb=1970312e983541d32d4ff73c81b8d90156a7bb99;hp=5575838b83f9664bcb2c21ecbca6f47ec17d8465;hpb=553fb21593a9c95e37e3be98ad0e4b97bc4ff11b;p=l2e.git diff --git a/src/loader/Compiler.cpp b/src/loader/Compiler.cpp index 5575838..96c0cc1 100644 --- a/src/loader/Compiler.cpp +++ b/src/loader/Compiler.cpp @@ -1,199 +1,325 @@ -/* - * 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 { 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)); +: intp(intp) { + 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 = out.tellp(); Pad(out, 16); + fileHeader.arraysBegin = out.tellp(); + WriteArrays(out); + fileHeader.arraysEnd = out.tellp(); + out.seekp(0); + WriteHeader(out); WriteExports(out); - Pad(out, 16); WriteExternals(out); - Pad(out, 16); - WriteExportStrings(out); - Pad(out, 16); - WriteExternalStrings(out); - Pad(out, 16); + out.seekg(fileHeader.objectsBegin); + out.clear(); + Relocate(out); + fileHeader.imagesBegin = out.tellp(); WriteImages(out); - Pad(out, 16); - WriteObjects(out); + fileHeader.imagesEnd = out.tellp(); + out.seekp(0); + WriteHeader(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) { + Object object; + object.typeId = Interpreter::STRING_ID; + object.size = i->size() + 1; + Write(out, &object, sizeof(Object)); + addressMap.insert(make_pair(i->c_str(), out.tellp())); + Write(out, i->c_str(), object.size); + } + for(vector::const_iterator + i(intp.PostponedDefinitions().begin()), + end(intp.PostponedDefinitions().end()); + i != end; ++i) { + Object object; + object.typeId = Interpreter::STRING_ID; + object.size = i->identifier.size() + 1; + Write(out, &object, sizeof(Object)); + addressMap.insert(make_pair( + i->identifier.c_str(), out.tellp())); + Write(out, i->identifier.c_str(), object.size); + } + for (std::map::const_iterator + i(intp.Images().begin()), end(intp.Images().end()); + i != end; ++i) { + addressMap.insert(make_pair( + i->second, 0)); + Object object; + object.typeId = Interpreter::STRING_ID; + object.size = i->first.size() + 1; + Write(out, &object, sizeof(Object)); + addressMap.insert(make_pair( + i->first.c_str(), out.tellp())); + Write(out, i->first.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)); + addressMap.insert(make_pair(*j, out.tellp())); + 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.typeId = i->typeId; + array.size = i->size; + array.ref = i->ref; + Write(out, &array, sizeof(Array)); + addressMap.insert(make_pair(i->data, out.tellp())); + 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); + for (std::map::const_iterator + i(images.begin()), end(images.end()); + i != end; ++i) { + const string &path = intp.FindImage( + reinterpret_cast(i->second)); + Image img; + img.pathOffset = addressMap.at(path.c_str()); + img.destOffset = i->first; + Write(out, &img, sizeof(Image)); } } -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()); - } - Pad(out, 16); + +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) { + 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::Relocate(iostream &out) { + int bufferSize = TypeDescription::GetMaxSize(); + char *buffer = new char[bufferSize]; + for (;out && out.tellg() < fileHeader.objectsEnd;) { + Object object; + out.read(reinterpret_cast(&object), sizeof(Object)); + const TypeDescription &td = TypeDescription::Get(object.typeId); + unsigned int pos = out.tellg(); -void Compiler::Write(ostream &out, const char *data, int amount) { - out.write(data, amount); - cursor += amount; + out.read(buffer, object.size); + Relocate(pos, 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)); + buffer = new char[array.size]; + unsigned int pos = out.tellg(); + out.read(buffer, array.size); + if (array.ref) { + RelocateArray(buffer, array.size); + } else { + const TypeDescription &td = TypeDescription::Get(array.typeId); + for (char *i = buffer, *end = buffer + array.size; + i < end; i += td.Size()) { + Relocate(pos + (i - buffer), i, td); + } + } + out.seekp(pos); + out.write(buffer, array.size); + out.seekg(out.tellp()); + delete[] buffer; + } } -void Compiler::Pad(ostream &out, int to) { - for (int remaining(Remaining(cursor, to)); remaining > 0; --remaining) { - out.put(0); - ++cursor; +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); } } -int Compiler::Remaining(int value, int alignment) { - int have(value % alignment); - return (have > 0) ? (16 - have) : 0; +void Compiler::Relocate( + unsigned int pos, + 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()) { + char **dest = reinterpret_cast( + object + fd.Offset()); + if (!(*dest)) { + continue; + } + if (fd.TypeId() == Interpreter::IMAGE_ID) { + images.insert(make_pair( + pos + fd.Offset(), *dest)); + } + 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); + } else { + const TypeDescription &nestedType + = TypeDescription::Get(fd.TypeId()); + Relocate(pos + fd.Offset(), object + fd.Offset(), nestedType); + } + } } -int Compiler::ReferenceOffset(int typeId, int objectId, std::ptrdiff_t fieldOffset) const { - return ObjectOffset(typeId, objectId) + fieldOffset; +void Compiler::Write(ostream &out, const void *data, int amount) { + out.write(reinterpret_cast(data), amount); } -int Compiler::ObjectOffset(int typeId, int objectId) const { - const TypeDescription &td(TypeDescription::Get(typeId)); - return GetTypeOffset(typeId) + (td.Size() * objectId); +void Compiler::Pad(ostream &out, int to) { + Fill(out, Remaining(out.tellp(), to)); } -int Compiler::GetTypeOffset(int typeId) const { - return objectOffsets.at(typeId); +void Compiler::Fill(ostream &out, int count, char c) { + for (int remaining(count); remaining > 0; --remaining) { + out.put(c); + } +} + +int Compiler::Remaining(int value, int alignment) { + int have(value % alignment); + return (have > 0) ? (16 - have) : 0; } }