X-Git-Url: https://git.localhorst.tv/?a=blobdiff_plain;ds=sidebyside;f=src%2Floader%2FCompiler.cpp;h=bb96b28728ecf82e1abb03fbb195722eb02dec83;hb=45bb35881a10720ae26701ddf075f756419cd627;hp=59bebfbcdf5633a8a2b08bd485d7409cb9a1373b;hpb=587a9fc38235475f1c25424bee3e3aeb892a25e2;p=l2e.git diff --git a/src/loader/Compiler.cpp b/src/loader/Compiler.cpp index 59bebfb..bb96b28 100644 --- a/src/loader/Compiler.cpp +++ b/src/loader/Compiler.cpp @@ -1,25 +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 { @@ -27,149 +29,254 @@ 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::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::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::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 >::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(&exportsOffset), sizeof(int)); - Write(out, reinterpret_cast(&externalsOffset), sizeof(int)); - Write(out, reinterpret_cast(&externalStringsOffset), sizeof(int)); - Write(out, reinterpret_cast(&exportStringsOffset), sizeof(int)); - Write(out, reinterpret_cast(&imagesOffset), sizeof(int)); - Write(out, reinterpret_cast(&objectsOffset), sizeof(int)); - for(map >::const_iterator i(intp.Values().begin()), end(intp.Values().end()); i != end; ++i) { - Write(out, reinterpret_cast(&i->first), sizeof(int)); - int typeOffset(TypeOffset(i->first)); - Write(out, reinterpret_cast(&typeOffset), sizeof(int)); + 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(), cursor)); + 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); } } void Compiler::WriteExports(ostream &out) { - int nameOffset(externalStringsOffset); - 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(exportStringsOffset); - 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.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 * 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(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; } } @@ -179,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 TypeOffset(typeId) + (td.Size() * objectId); -} - -int Compiler::TypeOffset(int typeId) const { - return objectOffsets.at(typeId); -} - }