1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <cmajor/rt/Classes.hpp>
  7 #include <cmajor/rt/Statics.hpp>
  8 #include <cmajor/rt/Error.hpp>
  9 #include <cmajor/rt/Io.hpp>
 10 #include <soulng/util/System.hpp>
 11 #include <soulng/util/BinaryReader.hpp>
 12 #include <soulng/util/Path.hpp>
 13 #include <soulng/util/Prime.hpp>
 14 #include <soulng/util/Uuid.hpp>
 15 #include <boost/filesystem.hpp>
 16 #include <boost/uuid/uuid_io.hpp>
 17 #include <boost/functional/hash.hpp>
 18 #include <unordered_map>
 19 #include <mutex>
 20 #include <sstream>
 21 
 22 namespace cmajor { namespace rt {
 23 
 24 using namespace soulng::util;
 25 
 26 class ClassIdMap 
 27 {
 28 public:
 29     static void Init();
 30     static void Done();
 31     static ClassIdMap& Instance() { return *instance; }
 32     void SetClassId(const boost::uuids::uuid& typeIdconst boost::multiprecision::uint128_t& classId);
 33     boost::multiprecision::uint128_t GetClassId(const boost::uuids::uuid& typeId) const;
 34 private:
 35     static std::unique_ptr<ClassIdMap> instance;
 36     std::unordered_map<boost::uuids::uuidboost::multiprecision::uint128_tboost::boost::hash<boost::uuids::uuid>>classIdMap;
 37 };
 38 
 39 std::unique_ptr<ClassIdMap> ClassIdMap::instance;
 40 
 41 void ClassIdMap::Init()
 42 {
 43     instance.reset(new ClassIdMap());
 44 }
 45 
 46 void ClassIdMap::Done()
 47 {
 48     instance.reset();
 49 }
 50 
 51 void ClassIdMap::SetClassId(const boost::uuids::uuid& typeIdconst boost::multiprecision::uint128_t& classId)
 52 {
 53     classIdMap[typeId] = classId;
 54 }
 55 
 56 boost::multiprecision::uint128_t ClassIdMap::GetClassId(const boost::uuids::uuid& typeId) const
 57 {
 58     auto it = classIdMap.find(typeId);
 59     if (it != classIdMap.cend())
 60     {
 61         return it->second;
 62     }
 63     else
 64     {
 65         std::stringstream s;
 66         s << "internal error : class id for type id " << typeId << " not found.\n";
 67         std::string str = s.str();
 68         int32_t errorStringHandle = -1;
 69         void* stdError = RtOpenStdFile(2errorStringHandle);
 70         RtWrite(stdErrorreinterpret_cast<const uint8_t*>(str.c_str())str.length()errorStringHandle);
 71         RtFlush(stdErrorerrorStringHandle);
 72         exit(exitCodeInternalError);
 73     }
 74 }
 75 
 76 boost::multiprecision::uint128_t GetClassId(const boost::uuids::uuid& typeId)
 77 {
 78     return ClassIdMap::Instance().GetClassId(typeId);
 79 }
 80 
 81 void InitClasses(int64_t numberOfPolymorphicClassIdsconst uint64_t* polymorphicClassIdArrayint64_t numberOfStaticClassIdsconst uint64_t* staticClassIdArray)
 82 {
 83     try
 84     {
 85         ClassIdMap::Init();
 86         boost::uuids::uuid dynamicTypeId;
 87         for (int64_t i = 0; i < numberOfPolymorphicClassIds; ++i)
 88         {
 89             uint64_t typeId1 = polymorphicClassIdArray[4 * i];
 90             uint64_t typeId2 = polymorphicClassIdArray[4 * i + 1];
 91             boost::multiprecision::uint128_t classId = boost::multiprecision::uint128_t(polymorphicClassIdArray[4 * i + 2]) << 64 | polymorphicClassIdArray[4 * i + 3];
 92             IntsToUuid(typeId1typeId2dynamicTypeId);
 93             ClassIdMap::Instance().SetClassId(dynamicTypeIdclassId);
 94         }
 95         boost::uuids::uuid staticTypeId;
 96         std::vector<boost::uuids::uuid> staticClassIds;
 97         for (int64_t i = 0; i < numberOfStaticClassIds; ++i)
 98         {
 99             uint64_t typeId1 = staticClassIdArray[2 * i];
100             uint64_t typeId2 = staticClassIdArray[2 * i + 1];
101             IntsToUuid(typeId1typeId2staticTypeId);
102             staticClassIds.push_back(staticTypeId);
103         }
104         AllocateMutexes(staticClassIds);
105     }
106     catch (const std::exception& ex;)
107     {
108         std::stringstream s;
109         s << "internal error in program initialization: " << ex.what() << "\n";
110         std::string str = s.str();
111         int32_t errorStringHandle = -1;
112         void* stdError = RtOpenStdFile(2errorStringHandle);
113         RtWrite(stdErrorreinterpret_cast<const uint8_t*>(str.c_str())str.length()errorStringHandle);
114         RtFlush(stdErrorerrorStringHandle);
115         exit(exitCodeInternalError);
116     }
117 }
118 
119 std::mutex dynamicInitVmtMutex;
120 
121 bool DynamicInitVmtsAndCompare(void* vmt1void* vmt2)
122 {
123     std::lock_guard<std::mutex> lock(dynamicInitVmtMutex);
124     uint64_t* vmt1Header = reinterpret_cast<uint64_t*>(vmt1);
125     boost::multiprecision::uint128_t classId1(boost::multiprecision::uint128_t(vmt1Header[0]) << 64 | vmt1Header[1]);
126     if (classId1 == 0)
127     {
128         uint64_t typeId1 = vmt1Header[2];
129         uint64_t typeId2 = vmt1Header[3];
130         boost::uuids::uuid typeId;
131         IntsToUuid(typeId1typeId2typeId);
132         classId1 = ClassIdMap::Instance().GetClassId(typeId);
133         vmt1Header[0] = static_cast<uint64_t>(classId1 >> 64);
134         vmt1Header[1] = static_cast<uint64_t>(classId1);
135     }
136     uint64_t* vmt2Header = reinterpret_cast<uint64_t*>(vmt2);
137     boost::multiprecision::uint128_t classId2(boost::multiprecision::uint128_t(vmt2Header[0]) << 64 | vmt2Header[1]);
138     if (classId2 == 0)
139     {
140         uint64_t typeId1 = vmt2Header[2];
141         uint64_t typeId2 = vmt2Header[3];
142         boost::uuids::uuid typeId;
143         IntsToUuid(typeId1typeId2typeId);
144         classId2 = ClassIdMap::Instance().GetClassId(typeId);
145         vmt2Header[0] = static_cast<uint64_t>(classId2 >> 64);
146         vmt2Header[1] = static_cast<uint64_t>(classId2);
147     }
148     return classId1 % classId2 == 0;
149 }
150 
151 void DoneClasses()
152 {
153     ClassIdMap::Done();
154 }
155 
156 } } // namespace cmajor::rt