From 4bab09349da598984d69269d05ba06a73371aff8 Mon Sep 17 00:00:00 2001 From: Gleb Balykov Date: Fri, 22 Apr 2022 13:28:32 +0300 Subject: [PATCH] [Tizen] Add mcj-edit.py tool that can modify MultiCoreJit profiles. Available commands: - split (splits mcj profile in app-dependent and app-independent based on modules) - merge (merges mcj profiles in one profile) - verify (verifies correctness of mcj profile) - find (finds method or module in mcj profile) - compare (compares mcj profiles) - clean-stats (cleans mcj profile usage stats) - print (prints mcj profile) - help (shows short summary on some aspects of mcj profile) - self-test (performs some testing) See README for more details on usage, see examples/ for examples of mcj profiles. --- src/coreclr/tools/mcj-edit/README.md | 95 + .../tools/mcj-edit/examples/helloworld/README.md | 3 + .../tools/mcj-edit/examples/helloworld/profile.dat | Bin 0 -> 6828 bytes .../examples/helloworld/system_modules.txt | 6 + .../examples/tizen-csharp-samples/README.md | 9 + .../org.tizen.example.Alarm.dat | Bin 0 -> 30296 bytes .../org.tizen.example.Calculator.dat | Bin 0 -> 29748 bytes .../org.tizen.example.HeartRateMonitor.dat | Bin 0 -> 30372 bytes ....tizen.example.Net.VoiceMemo.Tizen.Wearable.dat | Bin 0 -> 34908 bytes .../org.tizen.example.Weather.dat | Bin 0 -> 39864 bytes .../org.tizen.example.XStopWatch.dat | Bin 0 -> 29544 bytes .../tizen-csharp-samples/system_modules.txt | 265 ++ src/coreclr/tools/mcj-edit/mcj-edit.py | 4467 ++++++++++++++++++++ 13 files changed, 4845 insertions(+) create mode 100644 src/coreclr/tools/mcj-edit/README.md create mode 100644 src/coreclr/tools/mcj-edit/examples/helloworld/README.md create mode 100644 src/coreclr/tools/mcj-edit/examples/helloworld/profile.dat create mode 100644 src/coreclr/tools/mcj-edit/examples/helloworld/system_modules.txt create mode 100644 src/coreclr/tools/mcj-edit/examples/tizen-csharp-samples/README.md create mode 100644 src/coreclr/tools/mcj-edit/examples/tizen-csharp-samples/org.tizen.example.Alarm.dat create mode 100644 src/coreclr/tools/mcj-edit/examples/tizen-csharp-samples/org.tizen.example.Calculator.dat create mode 100644 src/coreclr/tools/mcj-edit/examples/tizen-csharp-samples/org.tizen.example.HeartRateMonitor.dat create mode 100644 src/coreclr/tools/mcj-edit/examples/tizen-csharp-samples/org.tizen.example.Net.VoiceMemo.Tizen.Wearable.dat create mode 100644 src/coreclr/tools/mcj-edit/examples/tizen-csharp-samples/org.tizen.example.Weather.dat create mode 100644 src/coreclr/tools/mcj-edit/examples/tizen-csharp-samples/org.tizen.example.XStopWatch.dat create mode 100644 src/coreclr/tools/mcj-edit/examples/tizen-csharp-samples/system_modules.txt create mode 100644 src/coreclr/tools/mcj-edit/mcj-edit.py diff --git a/src/coreclr/tools/mcj-edit/README.md b/src/coreclr/tools/mcj-edit/README.md new file mode 100644 index 0000000..15b05b5 --- /dev/null +++ b/src/coreclr/tools/mcj-edit/README.md @@ -0,0 +1,95 @@ +# MCJ profile editor + +`mcj-edit.py` is MCJ profile editor, see `--help` for all available options, see `help` for mcj profile short summary and for binary signature short summary. + +See `examples/` for examples of mcj profiles. + +## Examples of usage + +### To show mcj profile format summary: + +```sh +python3 mcj-edit.py help --mcj-format +``` + +### To show binary signature format summary: + +```sh +python3 mcj-edit.py help --binary-signature-format +``` + +### To show help: + +```sh +python3 mcj-edit.py --help +``` + +### To verify profile correctness: + +```sh +python3 mcj-edit.py verify -i `pwd`/profile.dat +``` + +### To print profile: + +```sh +python3 mcj-edit.py print -i `pwd`/profile.dat +``` + +Add `--raw` option to print raw profile, i.e. the way it is saved in file. + +Add `--header`, `--modules`, `--module-deps-and-methods` options to print only parts of profile. + +### To find method or module in profile: + +```sh +python3 mcj-edit.py find -i `pwd`/profile.dat --module System.Private.CoreLib --method-token 100663502 +``` + +Use `--module` option to find module by name, `--method-token` to find generic/non-generic method by token. + +### To compare profiles: + +Using load and compare: +```sh +python3 mcj-edit.py compare -i `pwd`/profile.dat -i /tmp/profile2.dat +``` + +To use sha256sum on files add `--sha256` option. + +### To split profile in app-dependent and app-independent: + +```sh +python3 mcj-edit.py split -i `pwd`/profile.dat --system-modules-list `pwd`/system_modules.txt +``` + +After this command two new files will be created: `pwd`/profile.dat.app for app-dependent profile and `pwd`/profile.dat.sys for app-independent profile. + +### To merge profiles: + +```sh +python3 mcj-edit.py merge -i `pwd`/profile.dat -i /tmp/profile2.dat -o `pwd`/profile.merged.dat +``` + +After this command new file wil be created: `pwd`/profile.merged.dat. + +**Note: merge can't be performed on two arbitrary mcj profiles! Next profiles can't be merged:** +- if one profile contains module with name `AAA` and version `X` and another profile contains module with same name `AAA` and version `Y` +- if one profile contains module with name `AAA` and assembly name `BBB` and another profile contains module with same name `AAA` and assembly name `CCC` +- if one profile contains module with name `AAA` with flags `X` and another profile contains module with same name `AAA` with flags `Y` (this situation should not happen now, flags are always 0) +- if one profile contains method with token/signature `XXX` with flags `X` and another profile contains method with same token/signature `XXX` with flags `Y` (this situation can happen now only if one profile was rewritten during use, i.e. JIT_BY_APP_THREAD_TAG was not set for some methods, i.e. COMPlus_MultiCoreJitNoProfileGather=1 was not set) + +### To run some tests: + +```sh +python3 mcj-edit.py self-test --rw-sha256 -i `pwd`/profile.dat +python3 mcj-edit.py self-test --rw -i `pwd`/profile.dat +python3 mcj-edit.py self-test --sm -i `pwd`/profile.dat --system-modules-list `pwd`/system_modules.txt +``` + +## pylint + +To run pylint: +```sh +pylint -d superfluous-parens,missing-function-docstring,missing-class-docstring,missing-module-docstring,too-many-boolean-expressions,too-many-arguments,too-many-public-methods,too-many-lines --max-line-length=120 --method-naming-style=camelCase --argument-naming-style=camelCase --attr-naming-style=camelCase --variable-naming-style=camelCase mcj-edit.py +``` diff --git a/src/coreclr/tools/mcj-edit/examples/helloworld/README.md b/src/coreclr/tools/mcj-edit/examples/helloworld/README.md new file mode 100644 index 0000000..09c8513 --- /dev/null +++ b/src/coreclr/tools/mcj-edit/examples/helloworld/README.md @@ -0,0 +1,3 @@ +# HelloWorld + +`profile.dat` is mcj profile for console helloworld launched without ni.dll, `system_modules.txt` is related number of system modules. diff --git a/src/coreclr/tools/mcj-edit/examples/helloworld/profile.dat b/src/coreclr/tools/mcj-edit/examples/helloworld/profile.dat new file mode 100644 index 0000000000000000000000000000000000000000..9c3c6d981fa5cda2e9fb14d87dae1da10e221c52 GIT binary patch literal 6828 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 M`|rW);7Q{D08&TQ1poj5 literal 0 HcmV?d00001 diff --git a/src/coreclr/tools/mcj-edit/examples/helloworld/system_modules.txt b/src/coreclr/tools/mcj-edit/examples/helloworld/system_modules.txt new file mode 100644 index 0000000..ca9d15b --- /dev/null +++ b/src/coreclr/tools/mcj-edit/examples/helloworld/system_modules.txt @@ -0,0 +1,6 @@ +System.Private.CoreLib +System.Console +System.Threading +Microsoft.Win32.Primitives +System.Collections +System.Memory diff --git a/src/coreclr/tools/mcj-edit/examples/tizen-csharp-samples/README.md b/src/coreclr/tools/mcj-edit/examples/tizen-csharp-samples/README.md new file mode 100644 index 0000000..65e01a7 --- /dev/null +++ b/src/coreclr/tools/mcj-edit/examples/tizen-csharp-samples/README.md @@ -0,0 +1,9 @@ +# Tizen CSharp Samples + +Built apps from https://github.com/Samsung/Tizen-CSharp-Samples + +With this setup all dlls have corresponding ni.dll: +- netcoreapp is in bubble with itself +- framework is in bubble with netcoreapp and itself +- frameworkref is in bubble with netcoreapp, framework and itself +- app is in bubble with all above diff --git a/src/coreclr/tools/mcj-edit/examples/tizen-csharp-samples/org.tizen.example.Alarm.dat b/src/coreclr/tools/mcj-edit/examples/tizen-csharp-samples/org.tizen.example.Alarm.dat new file mode 100644 index 0000000000000000000000000000000000000000..a3187012c03771c8ea0c838730b14be2cf1e1040 GIT binary patch literal 30296 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 MB4qa0yBH_`2cA^E3IG5A literal 0 HcmV?d00001 diff --git a/src/coreclr/tools/mcj-edit/examples/tizen-csharp-samples/org.tizen.example.Net.VoiceMemo.Tizen.Wearable.dat b/src/coreclr/tools/mcj-edit/examples/tizen-csharp-samples/org.tizen.example.Net.VoiceMemo.Tizen.Wearable.dat new file mode 100644 index 0000000000000000000000000000000000000000..dba9408cc04faf8c051d6dbf22b32279d72f13b2 GIT binary patch literal 34908 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 literal 0 HcmV?d00001 diff --git a/src/coreclr/tools/mcj-edit/examples/tizen-csharp-samples/org.tizen.example.Weather.dat b/src/coreclr/tools/mcj-edit/examples/tizen-csharp-samples/org.tizen.example.Weather.dat new file mode 100644 index 0000000000000000000000000000000000000000..81761cd4856ffa4996f5492cb58fb09d74bbd241 GIT binary patch literal 39864 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 HV~zNKCX4c% literal 0 HcmV?d00001 diff --git a/src/coreclr/tools/mcj-edit/examples/tizen-csharp-samples/org.tizen.example.XStopWatch.dat b/src/coreclr/tools/mcj-edit/examples/tizen-csharp-samples/org.tizen.example.XStopWatch.dat new file mode 100644 index 0000000000000000000000000000000000000000..23845b594e2d24750c533498a890e77b8c185fc8 GIT binary patch literal 29544 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 Utility.getMaxForNBytes(1)): + raise InternalError() + + if (isLittleEndian): + value = value | (byte << index * 8) + else: + value = (value << 8) | byte + + return value + + # Split bytes of value + @staticmethod + def splitNBytes(value, numbytes, isLittleEndian=True): + if (value is None or numbytes is None or isLittleEndian is None): + raise InternalError() + if (not issubclass(type(value), int) or not issubclass(type(numbytes), int) + or not issubclass(type(isLittleEndian), bool)): + raise InternalError() + if (value < 0 or numbytes < 0): + raise InternalError() + + bytesArr = [] + + for index in range(numbytes): # pylint: disable=unused-variable + if (isLittleEndian): + bytesArr.append(value & 0xff) + else: + bytesArr.insert(0, value & 0xff) + value = value >> 8 + + if (value > 0): + raise InternalError() + + return bytesArr + + # Pack bits: 8 high bits for value1, 24 low bits for value2 + @staticmethod + def pack8_24(value1, value2): # pylint: disable=invalid-name + if (value1 is None or value2 is None): + raise InternalError() + if (not issubclass(type(value1), int) or not issubclass(type(value2), int)): + raise InternalError() + if (value1 < 0 or value1 > Utility.getMaxForNBytes(1) + or value2 < 0 or value2 > Utility.getMaxForNBytes(3)): + raise InternalError() + return (value1 << 24) | value2 + + # Get max allowed value for unsigned N bits + @staticmethod + def getMaxForNBits(numBits): + if (numBits is None): + raise InternalError() + if (not issubclass(type(numBits), int)): + raise InternalError() + if (numBits < 0): + raise InternalError() + return (1 << numBits) - 1 + + # Get max allowed value for unsigned N bytes + @staticmethod + def getMaxForNBytes(numBytes): + if (numBytes is None): + raise InternalError() + if (not issubclass(type(numBytes), int)): + raise InternalError() + if (numBytes < 0): + raise InternalError() + return Utility.getMaxForNBits(numBytes * 8) + +# ---------------------------------------------------------------------------------------------------------------------- +# These are some constants from runtime, which should be checked before usage! +# See: +# - src/coreclr/vm/multicorejitimpl.h +# - ... +# +# TODO: add function that checks/sets these by parsing file from runtime +class RuntimeConstants: # pylint: disable=too-few-public-methods + METHOD_FLAGS_MASK = 0xff0000 + JIT_BY_APP_THREAD_TAG = 0x10000 + RECORD_TYPE_OFFSET = 24 + MAX_MODULES = 0x1000 + MODULE_MASK = 0xffff + MODULE_LEVEL_OFFSET = 16 + MAX_MODULE_LEVELS = 0x100 + MAX_METHODS = 0x4000 + #SIGNATURE_LENGTH_MASK = 0xffff + HEADER_W_COUNTER = 14 + HEADER_D_COUNTER = 3 + #MULTICOREJITLIFE = 60 * 1000 + #MAX_WALKBACK = 128 + + MULTICOREJIT_PROFILE_VERSION = 102 + MULTICOREJIT_HEADER_RECORD_ID = 1 + MULTICOREJIT_MODULE_RECORD_ID = 2 + MULTICOREJIT_MODULEDEPENDENCY_RECORD_ID = 3 + MULTICOREJIT_METHOD_RECORD_ID = 4 + MULTICOREJIT_GENERICMETHOD_RECORD_ID = 5 + + # Next constant are used directly and have no named variables in runtime + X_MODULE_RECORD_LEN_MASK = 0xffffff + +# ---------------------------------------------------------------------------------------------------------------------- +# These are sizes of types in bytes +class RuntimeTypeSizes: # pylint: disable=too-few-public-methods + int = 4 + short = 2 + char = 1 + +# ---------------------------------------------------------------------------------------------------------------------- +# Header of MCJ profile. +# +# Corresponds to "struct HeaderRecord" from multicorejitimpl.h +# +# To create from bytes: HeaderRecord.createFromBytes(bytes) +# To create from data structures using references: HeaderRecord.createByRef(...) +# To create from data structures using copy: HeaderRecord.createByCopy(...) +# +class HeaderRecord: # pylint: disable=too-many-instance-attributes + Alignment = RuntimeTypeSizes.int + + Size = 6 * RuntimeTypeSizes.int \ + + Utility.alignUp(RuntimeConstants.HEADER_W_COUNTER * RuntimeTypeSizes.short, Alignment) \ + + RuntimeConstants.HEADER_D_COUNTER * RuntimeTypeSizes.int + + # Empty constructor, do not use it directly + # Create new objects by createByCopy or createByRef + def __init__(self): + self._recordId = None + self._version = None + self._timeStamp = None + self._moduleCount = None + self._methodCount = None + self._moduleDepCount = None + self._shortCounters = None + self._longCounters = None + + # Equality comparison operator + def __eq__(self, rhs): + if (rhs is None): + return False + if (not issubclass(type(rhs), HeaderRecord)): + return False + return self._recordId == rhs._recordId and self._version == rhs._version \ + and self._timeStamp == rhs._timeStamp and self._moduleCount == rhs._moduleCount \ + and self._methodCount == rhs._methodCount and self._moduleDepCount == rhs._moduleDepCount \ + and self._shortCounters == rhs._shortCounters and self._longCounters == rhs._longCounters + + # Get moduleCount + def getModuleCount(self): + return self._moduleCount + + # Get methodCount + def getMethodCount(self): + return self._methodCount + + # Get moduleDepCount + def getModuleDepCount(self): + return self._moduleDepCount + + # Set moduleCount + def setModuleCount(self, moduleCount): + self._moduleCount = moduleCount + self.verify() + + # Set methodCount + def setMethodCount(self, methodCount): + self._methodCount = methodCount + self.verify() + + # Set moduleDepCount + def setModuleDepCount(self, moduleDepCount): + self._moduleDepCount = moduleDepCount + self.verify() + + # 0-init usage stats + def dropGlobalUsageStats(self): + self._shortCounters = [0] * RuntimeConstants.HEADER_W_COUNTER + self._longCounters = [0] * RuntimeConstants.HEADER_D_COUNTER + self.verify() + + # Verify consistency + def verify(self): + if (self._recordId is None or self._version is None + or self._timeStamp is None or self._moduleCount is None + or self._methodCount is None or self._moduleDepCount is None + or self._shortCounters is None or self._longCounters is None): + raise InternalError() + + if (not issubclass(type(self._recordId), int) or not issubclass(type(self._version), int) + or not issubclass(type(self._timeStamp), int) or not issubclass(type(self._moduleCount), int) + or not issubclass(type(self._methodCount), int) or not issubclass(type(self._moduleDepCount), int) + or not issubclass(type(self._shortCounters), list) or not issubclass(type(self._longCounters), list)): + raise InternalError() + + if (self._recordId < 0 or self._recordId > Utility.getMaxForNBytes(RuntimeTypeSizes.int) + or self._version < 0 or self._version > Utility.getMaxForNBytes(RuntimeTypeSizes.int) + or self._timeStamp < 0 or self._timeStamp > Utility.getMaxForNBytes(RuntimeTypeSizes.int) + or self._moduleCount < 0 or self._moduleCount > Utility.getMaxForNBytes(RuntimeTypeSizes.int) + or self._methodCount < 0 or self._methodCount > Utility.getMaxForNBytes(RuntimeTypeSizes.int) + or self._moduleDepCount < 0 or self._moduleDepCount > Utility.getMaxForNBytes(RuntimeTypeSizes.int) + or len(self._shortCounters) != RuntimeConstants.HEADER_W_COUNTER + or len(self._longCounters) != RuntimeConstants.HEADER_D_COUNTER): + raise InternalError() + + for i in self._shortCounters: + if (i < 0 or i > Utility.getMaxForNBytes(RuntimeTypeSizes.short)): + raise InternalError() + + for i in self._longCounters: + if (i < 0 or i > Utility.getMaxForNBytes(RuntimeTypeSizes.short)): + raise InternalError() + + if (self._version != RuntimeConstants.MULTICOREJIT_PROFILE_VERSION): + raise ProfileInconsistencyError() + + if (self._moduleCount > RuntimeConstants.MAX_MODULES): + raise ProfileInconsistencyError() + + if (self._methodCount > RuntimeConstants.MAX_METHODS): + raise ProfileInconsistencyError() + + if (self._recordId != Utility.pack8_24(RuntimeConstants.MULTICOREJIT_HEADER_RECORD_ID, HeaderRecord.Size)): + raise ProfileInconsistencyError() + + # Print raw + def printRaw(self, offsetStr=""): + if (offsetStr is None or not issubclass(type(offsetStr), str)): + raise InternalError() + + print(offsetStr + ">>> Raw HeaderRecord:") + print(offsetStr + "recordId = " + str(self._recordId)) + print(offsetStr + "version = " + str(self._version)) + print(offsetStr + "timeStamp = " + str(self._timeStamp)) + print(offsetStr + "moduleCount = " + str(self._moduleCount)) + print(offsetStr + "methodCount = " + str(self._methodCount)) + print(offsetStr + "moduleDepCount = " + str(self._moduleDepCount)) + print(offsetStr + "shortCounters = " + str(self._shortCounters)) + print(offsetStr + "longCounters = " + str(self._longCounters)) + + # Print pretty + def print(self, offsetStr=""): + if (offsetStr is None or not issubclass(type(offsetStr), str)): + raise InternalError() + + print(offsetStr + ">>> MultiCoreJit profile (version: " + str(self._version) + + ", time stamp: " + str(self._timeStamp) + ")") + print("") + print(offsetStr + "Number of used modules: " + str(self._moduleCount)) + print(offsetStr + "Number of method dependencies: " + str(self._methodCount)) + print(offsetStr + "Number of module dependencies: " + str(self._moduleDepCount)) + print("") + print(offsetStr + ">>> Stats for played profile (these are 0 if profile was not played):") + print("") + print(offsetStr + "Total number of methods: " + + str(self._shortCounters[0])) + print(offsetStr + "Number of methods, which had native code (i.e. no jit in mcj thread for them): " + + str(self._shortCounters[1])) + print(offsetStr + "Number of methods, which were tried to be jitted in mcj thread: " + + str(self._shortCounters[2])) + print(offsetStr + "Number of methods, which were successfully jitted in mcj thread: " + + str(self._shortCounters[3])) + print(offsetStr + "Number of methods, jit code for which was used after jit in mcj thread: " + + str(self._shortCounters[4])) + print(offsetStr + "Number of methods, which were skipped for some reason: " + + str(self._shortCounters[5])) + print(offsetStr + "Number of methods, which were skipped because of missing module: " + + str(self._shortCounters[6])) + print(offsetStr + "Number of methods, which were traversed backwards: " + + str(self._shortCounters[9])) + print("") + + # Create from bytes + @staticmethod + def createFromBytes(bytesArr): + if (bytesArr is None or not issubclass(type(bytesArr), list)): + raise InternalError() + + if (len(bytesArr) != HeaderRecord.Size): + raise ProfileInconsistencyError() + + index = 0 + + recordId = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int]) + index += RuntimeTypeSizes.int + + version = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int]) + index += RuntimeTypeSizes.int + + timeStamp = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int]) + index += RuntimeTypeSizes.int + + moduleCount = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int]) + index += RuntimeTypeSizes.int + + methodCount = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int]) + index += RuntimeTypeSizes.int + + moduleDepCount = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int]) + index += RuntimeTypeSizes.int + + shortCounters = [] + for i in range(0, RuntimeConstants.HEADER_W_COUNTER): # pylint: disable=unused-variable + shortCounters.append(Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short])) + index += RuntimeTypeSizes.short + + index = Utility.alignUp(index, HeaderRecord.Alignment) + + longCounters = [] + for i in range(0, RuntimeConstants.HEADER_D_COUNTER): # pylint: disable=unused-variable + longCounters.append(Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int])) + index += RuntimeTypeSizes.int + + return HeaderRecord.createByRef(recordId, version, timeStamp, moduleCount, methodCount, + moduleDepCount, shortCounters, longCounters) + + # Create from objects taking them by reference + @staticmethod + def createByRef(recordId, version, timeStamp, moduleCount, methodCount, + moduleDepCount, shortCounters, longCounters): + header = HeaderRecord() + + header._recordId = recordId # pylint: disable=protected-access + header._version = version # pylint: disable=protected-access + header._timeStamp = timeStamp # pylint: disable=protected-access + header._moduleCount = moduleCount # pylint: disable=protected-access + header._methodCount = methodCount # pylint: disable=protected-access + header._moduleDepCount = moduleDepCount # pylint: disable=protected-access + header._shortCounters = shortCounters # pylint: disable=protected-access + header._longCounters = longCounters # pylint: disable=protected-access + + header.verify() + return header + + # Create from objects taking them by copy + @staticmethod + def createByCopy(recordId, version, timeStamp, moduleCount, methodCount, + moduleDepCount, shortCounters, longCounters): + return HeaderRecord.createByRef(recordId, version, timeStamp, moduleCount, methodCount, + moduleDepCount, shortCounters.copy(), longCounters.copy()) + + # Copy object + def copy(self): + return HeaderRecord.createByCopy(self._recordId, self._version, self._timeStamp, + self._moduleCount, self._methodCount, self._moduleDepCount, + self._shortCounters, self._longCounters) + + # Convert object to list of bytes + def convertToBytes(self): + index = 0 + + bytesArr = [] + + bytesArr += Utility.splitNBytes(self._recordId, RuntimeTypeSizes.int) + index += RuntimeTypeSizes.int + + bytesArr += Utility.splitNBytes(self._version, RuntimeTypeSizes.int) + index += RuntimeTypeSizes.int + + bytesArr += Utility.splitNBytes(self._timeStamp, RuntimeTypeSizes.int) + index += RuntimeTypeSizes.int + + bytesArr += Utility.splitNBytes(self._moduleCount, RuntimeTypeSizes.int) + index += RuntimeTypeSizes.int + + bytesArr += Utility.splitNBytes(self._methodCount, RuntimeTypeSizes.int) + index += RuntimeTypeSizes.int + + bytesArr += Utility.splitNBytes(self._moduleDepCount, RuntimeTypeSizes.int) + index += RuntimeTypeSizes.int + + for i in self._shortCounters: + bytesArr += Utility.splitNBytes(i, RuntimeTypeSizes.short) + index += RuntimeTypeSizes.short + + padding = Utility.alignUp(index, HeaderRecord.Alignment) - index + bytesArr += [0] * padding + index += padding + + for i in self._longCounters: + bytesArr += Utility.splitNBytes(i, RuntimeTypeSizes.int) + index += RuntimeTypeSizes.int + + if (index != HeaderRecord.Size): + raise InternalError() + + return bytesArr + +# ---------------------------------------------------------------------------------------------------------------------- +# GUID. +# +# Corresponds to "GUID" from pal_mstypes.h +# +# To create from bytes: GUID.createFromBytes(bytes) +# To create from data structures using references: GUID.createByRef(...) +# To create from data structures using copy: GUID.createByCopy(...) +# +class GUID: + Alignment = RuntimeTypeSizes.int + + Size = RuntimeTypeSizes.int + 2 * RuntimeTypeSizes.short + 8 * RuntimeTypeSizes.char + + # Empty constructor, do not use it directly + # Create new objects by createByCopy or createByRef + def __init__(self): + self._data1 = None + self._data2 = None + self._data3 = None + self._data4 = None + + # Equality comparison operator + def __eq__(self, rhs): + if (rhs is None): + return False + if (not issubclass(type(rhs), GUID)): + return False + return self._data1 == rhs._data1 and self._data2 == rhs._data2 \ + and self._data3 == rhs._data3 and self._data4 == rhs._data4 + + # Verify consistency + def verify(self): + if (self._data1 is None or self._data2 is None or self._data3 is None or self._data4 is None): + raise InternalError() + + if (not issubclass(type(self._data1), int) or not issubclass(type(self._data2), int) + or not issubclass(type(self._data3), int) or not issubclass(type(self._data4), list)): + raise InternalError() + + if (self._data1 < 0 or self._data1 > Utility.getMaxForNBytes(RuntimeTypeSizes.int) + or self._data2 < 0 or self._data2 > Utility.getMaxForNBytes(RuntimeTypeSizes.short) + or self._data3 < 0 or self._data3 > Utility.getMaxForNBytes(RuntimeTypeSizes.short) + or len(self._data4) != 8): + raise InternalError() + + for i in self._data4: + if (i < 0 or i > Utility.getMaxForNBytes(RuntimeTypeSizes.char)): + raise InternalError() + + # Print raw + def printRaw(self, offsetStr=""): + if (offsetStr is None or not issubclass(type(offsetStr), str)): + raise InternalError() + + print(offsetStr + ">>> Raw GUID:") + print(offsetStr + "data1 = " + str(self._data1)) + print(offsetStr + "data2 = " + str(self._data2)) + print(offsetStr + "data3 = " + str(self._data3)) + print(offsetStr + "data4 = " + str(self._data4)) + + # Print pretty + def print(self, offsetStr=""): + if (offsetStr is None or not issubclass(type(offsetStr), str)): + raise InternalError() + + print(offsetStr + "GUID: " + str(self._data1) + + "," + str(self._data2) + + "," + str(self._data3) + + "," + str(self._data4)) + print(offsetStr + "") + + # Create from bytes + @staticmethod + def createFromBytes(bytesArr): + if (bytesArr is None or not issubclass(type(bytesArr), list)): + raise InternalError() + + if (len(bytesArr) != GUID.Size): + raise ProfileInconsistencyError() + + index = 0 + + data1 = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int]) + index += RuntimeTypeSizes.int + + data2 = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short]) + index += RuntimeTypeSizes.short + + data3 = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short]) + index += RuntimeTypeSizes.short + + data4 = [0] * 8 + for i in range(0, 8): + data4[i] = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.char]) + index += RuntimeTypeSizes.char + + return GUID.createByRef(data1, data2, data3, data4) + + # Create from objects taking them by reference + @staticmethod + def createByRef(data1, data2, data3, data4): + guid = GUID() + + guid._data1 = data1 # pylint: disable=protected-access + guid._data2 = data2 # pylint: disable=protected-access + guid._data3 = data3 # pylint: disable=protected-access + guid._data4 = data4 # pylint: disable=protected-access + + guid.verify() + return guid + + # Create from objects taking them by copy + @staticmethod + def createByCopy(data1, data2, data3, data4): + return GUID.createByRef(data1, data2, data3, data4.copy()) + + # Copy object + def copy(self): + return GUID.createByCopy(self._data1, self._data2, self._data3, self._data4) + + # Convert object to list of bytes + def convertToBytes(self): + index = 0 + + bytesArr = [] + + bytesArr += Utility.splitNBytes(self._data1, RuntimeTypeSizes.int) + index += RuntimeTypeSizes.int + + bytesArr += Utility.splitNBytes(self._data2, RuntimeTypeSizes.short) + index += RuntimeTypeSizes.short + + bytesArr += Utility.splitNBytes(self._data3, RuntimeTypeSizes.short) + index += RuntimeTypeSizes.short + + for i in self._data4: + bytesArr += Utility.splitNBytes(i, RuntimeTypeSizes.char) + index += RuntimeTypeSizes.char + + if (index != GUID.Size): + raise InternalError() + + return bytesArr + +# ---------------------------------------------------------------------------------------------------------------------- +# Module version. +# +# Corresponds to "class ModuleVersion" from multicorejitimpl.h +# +# To create from bytes: ModuleVersion.createFromBytes(bytes) +# To create from data structures using references: ModuleVersion.createByRef(...) +# To create from data structures using copy: ModuleVersion.createByCopy(...) +# +class ModuleVersion: + Alignment = RuntimeTypeSizes.int + + Size = 4 * RuntimeTypeSizes.short + RuntimeTypeSizes.int + GUID.Size + + # Empty constructor, do not use it directly + # Create new objects by createByCopy or createByRef + def __init__(self): + self._major = None + self._minor = None + self._build = None + self._revision = None + self._versionFlags = None + self._hasNativeImage = None + self._mvid = None + + # Equality comparison operator + def __eq__(self, rhs): + if (rhs is None): + return False + if (not issubclass(type(rhs), ModuleVersion)): + return False + return self._major == rhs._major and self._minor == rhs._minor and self._build == rhs._build \ + and self._revision == rhs._revision and self._versionFlags == rhs._versionFlags \ + and self._hasNativeImage == rhs._hasNativeImage and self._mvid == rhs._mvid + + # Verify consistency + def verify(self): + if (self._major is None or self._minor is None or self._build is None or self._revision is None + or self._versionFlags is None or self._hasNativeImage is None or self._mvid is None): + raise InternalError() + + if (not issubclass(type(self._major), int) or not issubclass(type(self._minor), int) + or not issubclass(type(self._build), int) or not issubclass(type(self._revision), int) + or not issubclass(type(self._versionFlags), int) or not issubclass(type(self._hasNativeImage), int) + or not issubclass(type(self._mvid), GUID)): + raise InternalError() + + if (self._major < 0 or self._major > Utility.getMaxForNBytes(RuntimeTypeSizes.short) + or self._minor < 0 or self._minor > Utility.getMaxForNBytes(RuntimeTypeSizes.short) + or self._build < 0 or self._build > Utility.getMaxForNBytes(RuntimeTypeSizes.short) + or self._revision < 0 or self._revision > Utility.getMaxForNBytes(RuntimeTypeSizes.short) + or self._versionFlags < 0 or self._versionFlags > Utility.getMaxForNBits(RuntimeTypeSizes.int * 8 - 1) + or self._hasNativeImage < 0 or self._hasNativeImage > Utility.getMaxForNBits(1)): + raise InternalError() + + # Print raw + def printRaw(self, offsetStr=""): + if (offsetStr is None or not issubclass(type(offsetStr), str)): + raise InternalError() + + print(offsetStr + ">>> Raw ModuleVersion:") + print(offsetStr + "major = " + str(self._major)) + print(offsetStr + "minor = " + str(self._minor)) + print(offsetStr + "build = " + str(self._build)) + print(offsetStr + "revision = " + str(self._revision)) + print(offsetStr + "versionFlags = " + str(self._versionFlags)) + print(offsetStr + "hasNativeImage = " + str(self._hasNativeImage)) + print(offsetStr + "mvid = {") + self._mvid.printRaw(offsetStr + " ") + print(offsetStr + "}") + + # Print pretty + def print(self, offsetStr=""): + if (offsetStr is None or not issubclass(type(offsetStr), str)): + raise InternalError() + + print(offsetStr + "ModuleVersion: " + str(self._major) + + "." + str(self._minor) + + "." + str(self._build) + + "." + str(self._revision) + + ", " + str(self._versionFlags) + + ", " + str(self._hasNativeImage)) + self._mvid.print(offsetStr) + + # Create from bytes + @staticmethod + def createFromBytes(bytesArr): + if (bytesArr is None or not issubclass(type(bytesArr), list)): + raise InternalError() + + if (len(bytesArr) != ModuleVersion.Size): + raise ProfileInconsistencyError() + + index = 0 + + major = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short]) + index += RuntimeTypeSizes.short + + minor = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short]) + index += RuntimeTypeSizes.short + + build = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short]) + index += RuntimeTypeSizes.short + + revision = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short]) + index += RuntimeTypeSizes.short + + versionFlags = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int]) + hasNativeImage = versionFlags & 0x01 + versionFlags = versionFlags & 0xfffffffe + index += RuntimeTypeSizes.int + + mvid = GUID.createFromBytes(bytesArr[index:index+GUID.Size]) + index += GUID.Size + + return ModuleVersion.createByRef(major, minor, build, revision, versionFlags, hasNativeImage, mvid) + + # Create from objects taking them by reference + @staticmethod + def createByRef(major, minor, build, revision, versionFlags, hasNativeImage, mvid): + moduleVersion = ModuleVersion() + + moduleVersion._major = major # pylint: disable=protected-access + moduleVersion._minor = minor # pylint: disable=protected-access + moduleVersion._build = build # pylint: disable=protected-access + moduleVersion._revision = revision # pylint: disable=protected-access + moduleVersion._versionFlags = versionFlags # pylint: disable=protected-access + moduleVersion._hasNativeImage = hasNativeImage # pylint: disable=protected-access + moduleVersion._mvid = mvid # pylint: disable=protected-access + + moduleVersion.verify() + return moduleVersion + + # Create from objects taking them by copy + @staticmethod + def createByCopy(major, minor, build, revision, versionFlags, hasNativeImage, mvid): + return ModuleVersion.createByRef(major, minor, build, revision, versionFlags, hasNativeImage, mvid.copy()) + + # Copy object + def copy(self): + return ModuleVersion.createByCopy(self._major, self._minor, self._build, self._revision, + self._versionFlags, self._hasNativeImage, self._mvid) + + # Convert object to list of bytes + def convertToBytes(self): + index = 0 + + bytesArr = [] + + bytesArr += Utility.splitNBytes(self._major, RuntimeTypeSizes.short) + index += RuntimeTypeSizes.short + + bytesArr += Utility.splitNBytes(self._minor, RuntimeTypeSizes.short) + index += RuntimeTypeSizes.short + + bytesArr += Utility.splitNBytes(self._build, RuntimeTypeSizes.short) + index += RuntimeTypeSizes.short + + bytesArr += Utility.splitNBytes(self._revision, RuntimeTypeSizes.short) + index += RuntimeTypeSizes.short + + versionFlags = self._versionFlags | self._hasNativeImage + bytesArr += Utility.splitNBytes(versionFlags, RuntimeTypeSizes.int) + index += RuntimeTypeSizes.int + + bytesArr += self._mvid.convertToBytes() + index += GUID.Size + + if (index != ModuleVersion.Size): + raise InternalError() + + return bytesArr + +# ---------------------------------------------------------------------------------------------------------------------- +# Record with information about used module. +# +# Corresponds to "struct ModuleRecord" from multicorejitimpl.h +# ModuleRecord in runtime implicitly "contains" module name and assembly name strings after itself, +# here they are a part of ModuleRecordExtended. +# +# To create from bytes: ModuleRecord.createFromBytes(bytes) +# To create from data structures using references: ModuleRecord.createByRef(...) +# To create from data structures using copy: ModuleRecord.createByCopy(...) +# +class ModuleRecord: # pylint: disable=too-many-public-methods + Alignment = RuntimeTypeSizes.int + + Size = RuntimeTypeSizes.int + ModuleVersion.Size + Utility.alignUp(5 * RuntimeTypeSizes.short, Alignment) + + # Empty constructor, do not use it directly + # Create new objects by createByCopy or createByRef + def __init__(self): + self._recordId = None + self._version = None + self._jitMethodCount = None + self._flags = None + self._wLoadLevel = None + self._lenModuleName = None + self._lenAssemblyName = None + + # Equality comparison operator + def __eq__(self, rhs): + if (rhs is None): + return False + if (not issubclass(type(rhs), ModuleRecord)): + return False + return self._recordId == rhs._recordId and self._version == rhs._version \ + and self._jitMethodCount == rhs._jitMethodCount and self._flags == rhs._flags \ + and self._wLoadLevel == rhs._wLoadLevel and self._lenModuleName == rhs._lenModuleName \ + and self._lenAssemblyName == rhs._lenAssemblyName + + # Get recordId + def getRecordId(self): + return self._recordId + + # Get version + def getVersion(self): + return self._version + + # Get jitMethodCount + def getJitMethodCount(self): + return self._jitMethodCount + + # Get flags + def getFlags(self): + return self._flags + + # Get wLoadLevel + def getLoadLevel(self): + return self._wLoadLevel + + # Get lenModuleName + def getLenModuleName(self): + return self._lenModuleName + + # Get lenAssemblyName + def getLenAssemblyName(self): + return self._lenAssemblyName + + # Set jitMethodCount + def setJitMethodCount(self, count): + self._jitMethodCount = count + self.verify() + + # Set wLoadLevel + def setLoadLevel(self, level): + self._wLoadLevel = level + self.verify() + + # Verify consistency + def verify(self): + if (self._recordId is None or self._version is None or self._jitMethodCount is None or self._flags is None + or self._wLoadLevel is None or self._lenModuleName is None or self._lenAssemblyName is None): + raise InternalError() + + if (not issubclass(type(self._recordId), int) or not issubclass(type(self._version), ModuleVersion) + or not issubclass(type(self._jitMethodCount), int) or not issubclass(type(self._flags), int) + or not issubclass(type(self._wLoadLevel), int) or not issubclass(type(self._lenModuleName), int) + or not issubclass(type(self._lenAssemblyName), int)): + raise InternalError() + + if (self._recordId < 0 or self._recordId > Utility.getMaxForNBytes(RuntimeTypeSizes.int) + or self._jitMethodCount < 0 or self._jitMethodCount > Utility.getMaxForNBytes(RuntimeTypeSizes.short) + or self._flags < 0 or self._flags > Utility.getMaxForNBytes(RuntimeTypeSizes.short) + or self._wLoadLevel < 0 or self._wLoadLevel > Utility.getMaxForNBytes(RuntimeTypeSizes.short) + or self._lenModuleName < 0 or self._lenModuleName > Utility.getMaxForNBytes(RuntimeTypeSizes.short) + or self._lenAssemblyName < 0 or self._lenAssemblyName > Utility.getMaxForNBytes(RuntimeTypeSizes.short)): + raise InternalError() + + # Print raw + def printRaw(self, offsetStr=""): + if (offsetStr is None or not issubclass(type(offsetStr), str)): + raise InternalError() + + print(offsetStr + ">>> Raw ModuleRecord:") + print(offsetStr + "recordId = " + str(self._recordId)) + print(offsetStr + "version = {") + self._version.printRaw(offsetStr + " ") + print(offsetStr + "}") + print(offsetStr + "jitMethodCount = " + str(self._jitMethodCount)) + print(offsetStr + "flags = " + str(self._flags)) + print(offsetStr + "wLoadLevel = " + str(self._wLoadLevel)) + print(offsetStr + "lenModuleName = " + str(self._lenModuleName)) + print(offsetStr + "lenAssemblyName = " + str(self._lenAssemblyName)) + + # Print pretty + def print(self, offsetStr=""): + if (offsetStr is None or not issubclass(type(offsetStr), str)): + raise InternalError() + + self._version.print(offsetStr) + print(offsetStr + "Number of used methods from module: " + str(self._jitMethodCount)) + print(offsetStr + "Final load level for module: " + str(self._wLoadLevel)) + + # Create from bytes + @staticmethod + def createFromBytes(bytesArr): + if (bytesArr is None or not issubclass(type(bytesArr), list)): + raise InternalError() + + if (len(bytesArr) != ModuleRecord.Size): + raise ProfileInconsistencyError() + + index = 0 + + recordId = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int]) + index += RuntimeTypeSizes.int + + version = ModuleVersion.createFromBytes(bytesArr[index:index+ModuleVersion.Size]) + index += ModuleVersion.Size + + jitMethodCount = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short]) + index += RuntimeTypeSizes.short + + flags = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short]) + index += RuntimeTypeSizes.short + + wLoadLevel = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short]) + index += RuntimeTypeSizes.short + + lenModuleName = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short]) + index += RuntimeTypeSizes.short + + lenAssemblyName = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short]) + index += RuntimeTypeSizes.short + + return ModuleRecord.createByRef(recordId, version, jitMethodCount, flags, wLoadLevel, + lenModuleName, lenAssemblyName) + + # Create from objects taking them by reference + @staticmethod + def createByRef(recordId, version, jitMethodCount, flags, wLoadLevel, lenModuleName, lenAssemblyName): + moduleRecord = ModuleRecord() + + moduleRecord._recordId = recordId # pylint: disable=protected-access + moduleRecord._version = version # pylint: disable=protected-access + moduleRecord._jitMethodCount = jitMethodCount # pylint: disable=protected-access + moduleRecord._flags = flags # pylint: disable=protected-access + moduleRecord._wLoadLevel = wLoadLevel # pylint: disable=protected-access + moduleRecord._lenModuleName = lenModuleName # pylint: disable=protected-access + moduleRecord._lenAssemblyName = lenAssemblyName # pylint: disable=protected-access + + moduleRecord.verify() + return moduleRecord + + # Create from objects taking them by copy + @staticmethod + def createByCopy(recordId, version, jitMethodCount, flags, wLoadLevel, lenModuleName, lenAssemblyName): + return ModuleRecord.createByRef(recordId, version.copy(), jitMethodCount, flags, wLoadLevel, + lenModuleName, lenAssemblyName) + + # Copy object + def copy(self): + return ModuleRecord.createByCopy(self._recordId, self._version, self._jitMethodCount, + self._flags, self._wLoadLevel, + self._lenModuleName, self._lenAssemblyName) + + # Convert object to list of bytes + def convertToBytes(self): + index = 0 + + bytesArr = [] + + bytesArr += Utility.splitNBytes(self._recordId, RuntimeTypeSizes.int) + index += RuntimeTypeSizes.int + + bytesArr += self._version.convertToBytes() + index += ModuleVersion.Size + + bytesArr += Utility.splitNBytes(self._jitMethodCount, RuntimeTypeSizes.short) + index += RuntimeTypeSizes.short + + bytesArr += Utility.splitNBytes(self._flags, RuntimeTypeSizes.short) + index += RuntimeTypeSizes.short + + bytesArr += Utility.splitNBytes(self._wLoadLevel, RuntimeTypeSizes.short) + index += RuntimeTypeSizes.short + + bytesArr += Utility.splitNBytes(self._lenModuleName, RuntimeTypeSizes.short) + index += RuntimeTypeSizes.short + + bytesArr += Utility.splitNBytes(self._lenAssemblyName, RuntimeTypeSizes.short) + index += RuntimeTypeSizes.short + + padding = Utility.alignUp(index, HeaderRecord.Alignment) - index + bytesArr += [0] * padding + index += padding + + if (index != ModuleRecord.Size): + raise InternalError() + + return bytesArr + +# ---------------------------------------------------------------------------------------------------------------------- +# Record with information about used module. +# +# This is ModuleRecord combined with actual module/assembly name strings. +# +# To create from bytes: ModuleRecordExtended.createFromBytes(bytes) +# To create from data structures using references: ModuleRecordExtended.createByRef(...) +# To create from data structures using copy: ModuleRecordExtended.createByCopy(...) +# +class ModuleRecordExtended: + + # Empty constructor, do not use it directly + # Create new objects by createByCopy or createByRef + def __init__(self): + self._moduleRecord = None + self._moduleName = None + self._assemblyName = None + + # Equality comparison operator + def __eq__(self, rhs): + if (rhs is None): + return False + if (not issubclass(type(rhs), ModuleRecordExtended)): + return False + + return self._moduleRecord == rhs._moduleRecord and \ + self._moduleName == rhs._moduleName and self._assemblyName == rhs._assemblyName + + # Get moduleRecord + def getModuleRecord(self): + return self._moduleRecord + + # Get moduleName + def getModuleName(self): + return self._moduleName + + # Get assemblyName + def getAssemblyName(self): + return self._assemblyName + + # Verify consistency + def verify(self): + if (self._moduleRecord is None or self._moduleName is None or self._assemblyName is None): + raise InternalError() + + if (not issubclass(type(self._moduleRecord), ModuleRecord) + or not issubclass(type(self._moduleName), str) + or not issubclass(type(self._assemblyName), str)): + raise InternalError() + + if (len(self._moduleName) != self._moduleRecord.getLenModuleName() + or len(self._assemblyName) != self._moduleRecord.getLenAssemblyName()): + raise InternalError() + + # Print raw + def printRaw(self, offsetStr=""): + if (offsetStr is None or not issubclass(type(offsetStr), str)): + raise InternalError() + + print(offsetStr + "moduleRecord = {") + self._moduleRecord.printRaw(offsetStr + " ") + print(offsetStr + "}") + print(offsetStr + "moduleName = " + self._moduleName) + print(offsetStr + "assemblyName = " + self._assemblyName) + + # Print pretty + def print(self, offsetStr=""): + if (offsetStr is None or not issubclass(type(offsetStr), str)): + raise InternalError() + + print(offsetStr + ">>> Module: " + self._moduleName + "; Assembly: " + self._assemblyName) + print(offsetStr + "") + self._moduleRecord.print(offsetStr) + print(offsetStr + "") + + # Create from bytes + @staticmethod + def createFromBytes(bytesArr): + if (bytesArr is None or not issubclass(type(bytesArr), list)): + raise InternalError() + + if (len(bytesArr) < ModuleRecord.Size): + raise ProfileInconsistencyError() + + index = 0 + + moduleRecord = ModuleRecord.createFromBytes(bytesArr[index:index+ModuleRecord.Size]) + index += ModuleRecord.Size + + lenModuleName = moduleRecord.getLenModuleName() + lenModuleNameAligned = Utility.alignUp(lenModuleName, RuntimeTypeSizes.int) + + lenAssemblyName = moduleRecord.getLenAssemblyName() + lenAssemblyNameAligned = Utility.alignUp(lenAssemblyName, RuntimeTypeSizes.int) + + if (len(bytesArr) != (ModuleRecord.Size + lenModuleNameAligned + lenAssemblyNameAligned)): + raise ProfileInconsistencyError() + + moduleName = "" + for i in bytesArr[index:index+lenModuleName]: + moduleName += chr(i) + index += lenModuleNameAligned + + assemblyName = "" + for i in bytesArr[index:index+lenAssemblyName]: + assemblyName += chr(i) + index += lenAssemblyNameAligned + + if (index != (ModuleRecord.Size + lenModuleNameAligned + lenAssemblyNameAligned)): + raise InternalError() + + return ModuleRecordExtended.createByRef(moduleRecord, moduleName, assemblyName) + + # Create from objects taking them by reference + @staticmethod + def createByRef(moduleRecord, moduleName, assemblyName): + moduleRecordExtended = ModuleRecordExtended() + + moduleRecordExtended._moduleRecord = moduleRecord # pylint: disable=protected-access + moduleRecordExtended._moduleName = moduleName # pylint: disable=protected-access + moduleRecordExtended._assemblyName = assemblyName # pylint: disable=protected-access + + moduleRecordExtended.verify() + return moduleRecordExtended + + # Create from objects taking them by copy + @staticmethod + def createByCopy(moduleRecord, moduleName, assemblyName): + return ModuleRecordExtended.createByRef(moduleRecord.copy(), moduleName, assemblyName) + + # Copy object + def copy(self): + return ModuleRecordExtended.createByCopy(self._moduleRecord, self._moduleName, self._assemblyName) + + # Convert object to list of bytes + def convertToBytes(self): + index = 0 + + bytesArr = [] + + bytesArr += self._moduleRecord.convertToBytes() + index += ModuleRecord.Size + + lenModuleName = self._moduleRecord.getLenModuleName() + lenModuleNameAligned = Utility.alignUp(lenModuleName, RuntimeTypeSizes.int) + bytesArr += list(bytearray(self._moduleName, "ascii")) + index += lenModuleName + + padding = lenModuleNameAligned - lenModuleName + bytesArr += [0] * padding + index += padding + + lenAssemblyName = self._moduleRecord.getLenAssemblyName() + lenAssemblyNameAligned = Utility.alignUp(lenAssemblyName, RuntimeTypeSizes.int) + bytesArr += list(bytearray(self._assemblyName, "ascii")) + index += lenAssemblyName + + padding = lenAssemblyNameAligned - lenAssemblyName + bytesArr += [0] * padding + index += padding + + if (index != (ModuleRecord.Size + lenModuleNameAligned + lenAssemblyNameAligned)): + raise InternalError() + + return bytesArr + +# ---------------------------------------------------------------------------------------------------------------------- +# Detailed info on types +# +# Semantically corresponds to CorTypeInfo +# +class CorTypeInfo: + + # Kinds of types + # + # Semantically corresponds to CorElementType + # TODO: verify these constants somehow, see above + class CorElementType: # pylint: disable=too-few-public-methods + + ELEMENT_TYPE_END = 0x00 + ELEMENT_TYPE_VOID = 0x01 + ELEMENT_TYPE_BOOLEAN = 0x02 + ELEMENT_TYPE_CHAR = 0x03 + ELEMENT_TYPE_I1 = 0x04 + ELEMENT_TYPE_U1 = 0x05 + ELEMENT_TYPE_I2 = 0x06 + ELEMENT_TYPE_U2 = 0x07 + ELEMENT_TYPE_I4 = 0x08 + ELEMENT_TYPE_U4 = 0x09 + ELEMENT_TYPE_I8 = 0x0a + ELEMENT_TYPE_U8 = 0x0b + ELEMENT_TYPE_R4 = 0x0c + ELEMENT_TYPE_R8 = 0x0d + ELEMENT_TYPE_STRING = 0x0e + + ELEMENT_TYPE_PTR = 0x0f + ELEMENT_TYPE_BYREF = 0x10 + + ELEMENT_TYPE_VALUETYPE = 0x11 + ELEMENT_TYPE_CLASS = 0x12 + ELEMENT_TYPE_VAR = 0x13 + ELEMENT_TYPE_ARRAY = 0x14 + ELEMENT_TYPE_GENERICINST = 0x15 + ELEMENT_TYPE_TYPEDBYREF = 0x16 + ELEMENT_TYPE_VALUEARRAY_UNSUPPORTED = 0x17 + ELEMENT_TYPE_I = 0x18 + ELEMENT_TYPE_U = 0x19 + ELEMENT_TYPE_R_UNSUPPORTED = 0x1a + ELEMENT_TYPE_FNPTR = 0x1b + ELEMENT_TYPE_OBJECT = 0x1c + ELEMENT_TYPE_SZARRAY = 0x1d + ELEMENT_TYPE_MVAR = 0x1e + + ELEMENT_TYPE_CMOD_REQD = 0x1f + ELEMENT_TYPE_CMOD_OPT = 0x20 + + ELEMENT_TYPE_INTERNAL = 0x21 + + ELEMENT_TYPE_MAX = 0x22 + + ELEMENT_TYPE_VAR_ZAPSIG = 0x3b + ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG = 0x3d + ELEMENT_TYPE_CANON_ZAPSIG = 0x3e + ELEMENT_TYPE_MODULE_ZAPSIG = 0x3f + + ELEMENT_TYPE_MODIFIER = 0x40 + ELEMENT_TYPE_SENTINEL = 0x01 | ELEMENT_TYPE_MODIFIER + ELEMENT_TYPE_PINNED = 0x05 | ELEMENT_TYPE_MODIFIER + + # This constant is not defined in runtime + X_ELEMENT_TYPE_LAST = ELEMENT_TYPE_PINNED + 1 + + # Entry in map of types info + class Entry: + + # Default constructor + def __init__(self, elementKind, name, isPrim): + self._elementKind = elementKind + self._name = name + self._isPrim = isPrim + + # Get kind of record + def getKind(self): + return self._elementKind + + # Get name of record + def getName(self): + return self._name + + # Get flag whether type is primitive + def getIsPrim(self): + return self._isPrim + + # Fill map with types info + @staticmethod + def fillMap(): + tmpmap = [None] * CorTypeInfo.CorElementType.X_ELEMENT_TYPE_LAST + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_END] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_END, "ELEMENT_TYPE_END", False) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_VOID] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_VOID, "void", True) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_BOOLEAN] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_BOOLEAN, "bool", True) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_CHAR] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_CHAR, "char", True) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_I1] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_I1, "i1", True) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_U1] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_U1, "u1", True) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_I2] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_I2, "i2", True) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_U2] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_U2, "u2", True) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_I4] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_I4, "i4", True) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_U4] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_U4, "u4", True) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_I8] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_I8, "i8", True) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_U8] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_U8, "u8", True) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_R4] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_R4, "r4", True) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_R8] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_R8, "r8", True) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_STRING] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_STRING, "string", False) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_PTR] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_PTR, "ptr", False) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_BYREF] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_BYREF, "byref", False) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_VALUETYPE] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_VALUETYPE, "valuetype", False) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_CLASS] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_CLASS, "class", False) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_VAR] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_VAR, "var", False) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_ARRAY] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_ARRAY, "array", False) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_GENERICINST] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_GENERICINST, "generic", False) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_TYPEDBYREF] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_TYPEDBYREF, "typedbyref", False) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_VALUEARRAY_UNSUPPORTED] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_VALUEARRAY_UNSUPPORTED, + "valuearray_unsupported", False) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_I] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_I, "i", True) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_U] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_U, "u", True) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_R_UNSUPPORTED] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_R_UNSUPPORTED, "r_unsupported", False) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_FNPTR] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_FNPTR, "fnptr", False) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_OBJECT] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_OBJECT, "object", False) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_SZARRAY] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_SZARRAY, "szarray", False) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_MVAR] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_MVAR, "mvar", False) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_CMOD_REQD] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_CMOD_REQD, "cmod_reqd", False) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_CMOD_OPT] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_CMOD_OPT, "cmod_opt", False) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_INTERNAL] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_INTERNAL, "internal", False) + #tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_MAX] = \ + # CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_MAX, "ELEMENT_TYPE_MAX", False) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_VAR_ZAPSIG] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_VAR_ZAPSIG, "vap_zapsig", False) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG, + "native_valuetype_zapsig", False) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_CANON_ZAPSIG] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_CANON_ZAPSIG, "canon_zapsig", False) + tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_MODULE_ZAPSIG] = \ + CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_MODULE_ZAPSIG, "module_zapsig", False) + #tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_MODIFIER] = \ + # CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_MODIFIER, "ELEMENT_TYPE_MODIFIER", False) + #tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_SENTINEL] = \ + # CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_SENTINEL, "ELEMENT_TYPE_SENTINEL", False) + #tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_PINNED] = \ + # CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_PINNED, "ELEMENT_TYPE_PINNED", False) + + # verify generated map + for index, record in enumerate(tmpmap): + if (not record is None and record.getKind() != index): + raise InternalError() + + return tmpmap + + # Map with types info, is filled explicitly below. + # Records that are absent from CorTypeInfo.CorElementType are None. + # Use getTypeMapEntry to access typemap. + typemap = None + + # Get info for type + @staticmethod + def getTypeMapEntry(elementKind): + if (elementKind is None or not issubclass(type(elementKind), int)): + raise InternalError() + record = CorTypeInfo.typemap[elementKind] # pylint: disable=unsubscriptable-object + if (record is None): + raise InternalError() + if (record.getKind() != elementKind): + raise InternalError() + return record + +# Fill map of types info +CorTypeInfo.typemap = CorTypeInfo.fillMap() + +# ---------------------------------------------------------------------------------------------------------------------- +# These are different kinds of types corresponding to CorTypeInfo.CorElementType + +# Base class for all types +class IType(ABC): + + # Get element kind + @abstractmethod + def getElementKind(self): + pass + + # Get string representation of type + @abstractmethod + def getStr(self, modules=None): + pass + + # Update all module indexes according to map old_index->new_index + @abstractmethod + def updateModuleIndex(self, moduleIndexMap): + pass + + # Get all module indexes used in related types + @abstractmethod + def getAllModuleIndexes(self): + pass + + # Copy type + @abstractmethod + def copy(self): + pass + + +# Corresponding to simple types that are fully described by their CorElementType +# +# To create from data structures using references: TypeSimple.createByRef(...) +# To create from data structures using copy: TypeSimple.createByCopy(...) +# +class TypeSimple(IType): + + # Empty constructor, do not use it directly + # Create new objects by createByCopy or createByRef + def __init__(self): + self._elementKind = None + + # Equality comparison operator + def __eq__(self, rhs): + if (rhs is None): + return False + if (not issubclass(type(rhs), TypeSimple)): + return False + return self._elementKind == rhs._elementKind + + # Convert to string + def getStr(self, modules=None): + if (not modules is None): + if (not issubclass(type(modules), list)): + raise InternalError() + for i in modules: + if (i is None or not issubclass(type(i), ModuleRecordExtended)): + raise InternalError() + + return CorTypeInfo.getTypeMapEntry(self._elementKind).getName() + + # Get elementKind + def getElementKind(self): + return self._elementKind + + # Get all module indexes used in related types + def getAllModuleIndexes(self): + return [] + + # Update all module indexes according to map old_index->new_index + def updateModuleIndex(self, moduleIndexMap): + if (moduleIndexMap is None or not issubclass(type(moduleIndexMap), list)): + raise InternalError() + self.verify() + + # Verify consistency + def verify(self): + if (self._elementKind is None): + raise InternalError() + + if (not issubclass(type(self._elementKind), int)): + raise InternalError() + + if (self._elementKind < 0 or self._elementKind >= CorTypeInfo.CorElementType.X_ELEMENT_TYPE_LAST): + raise InternalError() + + # Create from objects taking them by reference + @staticmethod + def createByRef(elementKind): + handle = TypeSimple() + + handle._elementKind = elementKind # pylint: disable=protected-access + + handle.verify() + return handle + + # Create from objects taking them by copy + @staticmethod + def createByCopy(elementKind): + return TypeSimple.createByRef(elementKind) + + # Copy object + def copy(self): + return TypeSimple.createByCopy(self._elementKind) + + +# Corresponding to types that are fully described by their CorElementType, module index and type token +# +# To create from data structures using references: TypeToken.createByRef(...) +# To create from data structures using copy: TypeToken.createByCopy(...) +# +class TypeToken(IType): + + # Empty constructor, do not use it directly + # Create new objects by createByCopy or createByRef + def __init__(self): + self._elementKind = None + self._moduleIndex = None + self._typeToken = None + + # Equality comparison operator + def __eq__(self, rhs): + if (rhs is None): + return False + if (not issubclass(type(rhs), TypeToken)): + return False + return self._elementKind == rhs._elementKind and self._moduleIndex == rhs._moduleIndex \ + and self._typeToken == rhs._typeToken + + # Convert to string + def getStr(self, modules=None): + if (not modules is None): + if (not issubclass(type(modules), list)): + raise InternalError() + for i in modules: + if (i is None or not issubclass(type(i), ModuleRecordExtended)): + raise InternalError() + + moduleStr = str(self._moduleIndex) + if (not modules is None): + moduleStr = modules[self._moduleIndex].getModuleName() + + return CorTypeInfo.getTypeMapEntry(self._elementKind).getName() + "{" + str(self._typeToken) \ + + ":" + moduleStr + "}" + + # Get elementKind + def getElementKind(self): + return self._elementKind + + # Get moduleIndex + def getModuleIndex(self): + return self._moduleIndex + + # Get typeToken + def getTypeToken(self): + return self._typeToken + + # Get all module indexes used in related types + def getAllModuleIndexes(self): + return [self._moduleIndex] + + # Update all module indexes according to map old_index->new_index + def updateModuleIndex(self, moduleIndexMap): + if (moduleIndexMap is None or not issubclass(type(moduleIndexMap), list)): + raise InternalError() + self._moduleIndex = moduleIndexMap[self._moduleIndex] + self.verify() + + # Verify consistency + def verify(self): + if (self._elementKind is None or self._moduleIndex is None or self._typeToken is None): + raise InternalError() + + if (not issubclass(type(self._elementKind), int) or not issubclass(type(self._moduleIndex), int) + or not issubclass(type(self._typeToken), int)): + raise InternalError() + + if (self._elementKind < 0 or self._elementKind >= CorTypeInfo.CorElementType.X_ELEMENT_TYPE_LAST): + raise InternalError() + + if (self._moduleIndex < 0 or self._moduleIndex >= RuntimeConstants.MAX_MODULES): + raise InternalError() + + if (self._typeToken < 0 or self._typeToken > Utility.getMaxForNBytes(RuntimeTypeSizes.int)): + raise InternalError() + + # Create from objects taking them by reference + @staticmethod + def createByRef(elementKind, moduleIndex, typeToken): + handle = TypeToken() + + handle._elementKind = elementKind # pylint: disable=protected-access + handle._moduleIndex = moduleIndex # pylint: disable=protected-access + handle._typeToken = typeToken # pylint: disable=protected-access + + handle.verify() + return handle + + # Create from objects taking them by copy + @staticmethod + def createByCopy(elementKind, moduleIndex, typeToken): + return TypeToken.createByRef(elementKind, moduleIndex, typeToken) + + # Copy object + def copy(self): + return TypeToken.createByCopy(self._elementKind, self._moduleIndex, self._typeToken) + + +# Corresponding to simple types with param type +# +# To create from data structures using references: TypeParamType.createByRef(...) +# To create from data structures using copy: TypeParamType.createByCopy(...) +# +class TypeParamType(IType): + + # Empty constructor, do not use it directly + # Create new objects by createByCopy or createByRef + def __init__(self): + self._elementKind = None + self._paramType = None + + # Equality comparison operator + def __eq__(self, rhs): + if (rhs is None): + return False + if (not issubclass(type(rhs), TypeParamType)): + return False + return self._elementKind == rhs._elementKind and self._paramType == rhs._paramType + + # Convert to string + def getStr(self, modules=None): + if (not modules is None): + if (not issubclass(type(modules), list)): + raise InternalError() + for i in modules: + if (i is None or not issubclass(type(i), ModuleRecordExtended)): + raise InternalError() + + return CorTypeInfo.getTypeMapEntry(self._elementKind).getName() + "{" + self._paramType.getStr(modules) + "}" + + # Get elementKind + def getElementKind(self): + return self._elementKind + + # Get paramType + def getParamType(self): + return self._paramType + + # Get all module indexes used in related types + def getAllModuleIndexes(self): + return self._paramType.getAllModuleIndexes() + + # Update all module indexes according to map old_index->new_index + def updateModuleIndex(self, moduleIndexMap): + if (moduleIndexMap is None or not issubclass(type(moduleIndexMap), list)): + raise InternalError() + self._paramType.updateModuleIndex(moduleIndexMap) + self.verify() + + # Verify consistency + def verify(self): + if (self._elementKind is None or self._paramType is None): + raise InternalError() + + if (not issubclass(type(self._elementKind), int) or not issubclass(type(self._paramType), IType)): + raise InternalError() + + if (self._elementKind < 0 or self._elementKind >= CorTypeInfo.CorElementType.X_ELEMENT_TYPE_LAST): + raise InternalError() + + # Create from objects taking them by reference + @staticmethod + def createByRef(elementKind, paramType): + handle = TypeParamType() + + handle._elementKind = elementKind # pylint: disable=protected-access + handle._paramType = paramType # pylint: disable=protected-access + + handle.verify() + return handle + + # Create from objects taking them by copy + @staticmethod + def createByCopy(elementKind, paramType): + return TypeParamType.createByRef(elementKind, paramType.copy()) + + # Copy object + def copy(self): + return TypeParamType.createByCopy(self._elementKind, self._paramType) + + +# Corresponding to array type +# +# To create from data structures using references: TypeArray.createByRef(...) +# To create from data structures using copy: TypeArray.createByCopy(...) +# +class TypeArray(IType): + + # Empty constructor, do not use it directly + # Create new objects by createByCopy or createByRef + def __init__(self): + self._elementKind = None + self._arrayElementType = None + self._rank = None + + # Equality comparison operator + def __eq__(self, rhs): + if (rhs is None): + return False + if (not issubclass(type(rhs), TypeArray)): + return False + return self._elementKind == rhs._elementKind and self._arrayElementType == rhs._arrayElementType \ + and self._rank == rhs._rank + + # Convert to string + def getStr(self, modules=None): + if (not modules is None): + if (not issubclass(type(modules), list)): + raise InternalError() + for i in modules: + if (i is None or not issubclass(type(i), ModuleRecordExtended)): + raise InternalError() + + return CorTypeInfo.getTypeMapEntry(self._elementKind).getName() + "{[" \ + + self._arrayElementType.getStr(modules) + " ]" + str(self._rank) + "}" + + # Get elementKind + def getElementKind(self): + return self._elementKind + + # Get arrayElementType + def getArrayElementType(self): + return self._arrayElementType + + # Get rank + def getRank(self): + return self._rank + + # Get all module indexes used in related types + def getAllModuleIndexes(self): + return self._arrayElementType.getAllModuleIndexes() + + # Update all module indexes according to map old_index->new_index + def updateModuleIndex(self, moduleIndexMap): + if (moduleIndexMap is None or not issubclass(type(moduleIndexMap), list)): + raise InternalError() + self._arrayElementType.updateModuleIndex(moduleIndexMap) + self.verify() + + # Verify consistency + def verify(self): + if (self._elementKind is None or self._arrayElementType is None or self._rank is None): + raise InternalError() + + if (not issubclass(type(self._elementKind), int) or not issubclass(type(self._arrayElementType), IType) + or not issubclass(type(self._rank), int)): + raise InternalError() + + if (self._elementKind < 0 or self._elementKind >= CorTypeInfo.CorElementType.X_ELEMENT_TYPE_LAST): + raise InternalError() + + if (self._rank < 0 or self._rank > Utility.getMaxForNBytes(RuntimeTypeSizes.char)): + raise InternalError() + + # Create from objects taking them by reference + @staticmethod + def createByRef(elementKind, arrayElementType, rank): + handle = TypeArray() + + handle._elementKind = elementKind # pylint: disable=protected-access + handle._arrayElementType = arrayElementType # pylint: disable=protected-access + handle._rank = rank # pylint: disable=protected-access + + handle.verify() + return handle + + # Create from objects taking them by copy + @staticmethod + def createByCopy(elementKind, arrayElementType, rank): + return TypeArray.createByRef(elementKind, arrayElementType.copy(), rank) + + # Copy object + def copy(self): + return TypeArray.createByCopy(self._elementKind, self._arrayElementType, self._rank) + + +# Corresponding to szarray type +# +# To create from data structures using references: TypeSZArray.createByRef(...) +# To create from data structures using copy: TypeSZArray.createByCopy(...) +# +class TypeSZArray(IType): + + # Empty constructor, do not use it directly + # Create new objects by createByCopy or createByRef + def __init__(self): + self._elementKind = None + self._arrayElementType = None + + # Equality comparison operator + def __eq__(self, rhs): + if (rhs is None): + return False + if (not issubclass(type(rhs), TypeSZArray)): + return False + return self._elementKind == rhs._elementKind and self._arrayElementType == rhs._arrayElementType + + # Convert to string + def getStr(self, modules=None): + if (not modules is None): + if (not issubclass(type(modules), list)): + raise InternalError() + for i in modules: + if (i is None or not issubclass(type(i), ModuleRecordExtended)): + raise InternalError() + + return CorTypeInfo.getTypeMapEntry(self._elementKind).getName() + "{[" \ + + self._arrayElementType.getStr(modules) + "]}" + + # Get elementKind + def getElementKind(self): + return self._elementKind + + # Get arrayElementType + def getArrayElementType(self): + return self._arrayElementType + + # Get all module indexes used in related types + def getAllModuleIndexes(self): + return self._arrayElementType.getAllModuleIndexes() + + # Update all module indexes according to map old_index->new_index + def updateModuleIndex(self, moduleIndexMap): + if (moduleIndexMap is None or not issubclass(type(moduleIndexMap), list)): + raise InternalError() + self._arrayElementType.updateModuleIndex(moduleIndexMap) + self.verify() + + # Verify consistency + def verify(self): + if (self._elementKind is None or self._arrayElementType is None): + raise InternalError() + + if (not issubclass(type(self._elementKind), int) or not issubclass(type(self._arrayElementType), IType)): + raise InternalError() + + if (self._elementKind < 0 or self._elementKind >= CorTypeInfo.CorElementType.X_ELEMENT_TYPE_LAST): + raise InternalError() + + # Create from objects taking them by reference + @staticmethod + def createByRef(elementKind, arrayElementType): + handle = TypeSZArray() + + handle._elementKind = elementKind # pylint: disable=protected-access + handle._arrayElementType = arrayElementType # pylint: disable=protected-access + + handle.verify() + return handle + + # Create from objects taking them by copy + @staticmethod + def createByCopy(elementKind, arrayElementType): + return TypeSZArray.createByRef(elementKind, arrayElementType.copy()) + + # Copy object + def copy(self): + return TypeSZArray.createByCopy(self._elementKind, self._arrayElementType) + + +# Corresponding to generic type +# +# To create from data structures using references: TypeGeneric.createByRef(...) +# To create from data structures using copy: TypeGeneric.createByCopy(...) +# +class TypeGeneric(IType): + + # Empty constructor, do not use it directly + # Create new objects by createByCopy or createByRef + def __init__(self): + self._elementKind = None + self._genericBaseType = None + self._instArgs = None + + # Equality comparison operator + def __eq__(self, rhs): + if (rhs is None): + return False + if (not issubclass(type(rhs), TypeGeneric)): + return False + return self._elementKind == rhs._elementKind and self._genericBaseType == rhs._genericBaseType \ + and self._instArgs == rhs._instArgs + + # Convert to string + def getStr(self, modules=None): + if (not modules is None): + if (not issubclass(type(modules), list)): + raise InternalError() + for i in modules: + if (i is None or not issubclass(type(i), ModuleRecordExtended)): + raise InternalError() + + output = CorTypeInfo.getTypeMapEntry(self._elementKind).getName() + "{" \ + + self._genericBaseType.getStr(modules) + "<" + + for index in range(len(self._instArgs)): + output += self._instArgs[index].getStr(modules) + if (index != (len(self._instArgs) - 1)): + output += "," + + output += ">}" + return output + + # Get elementKind + def getElementKind(self): + return self._elementKind + + # Get genericBaseType + def getGenericBaseType(self): + return self._genericBaseType + + # Get args + def getInstArgs(self): + return self._instArgs + + # Get all module indexes used in related types + def getAllModuleIndexes(self): + indexes = self._genericBaseType.getAllModuleIndexes() + for i in self._instArgs: + indexes += i.getAllModuleIndexes() + return sorted(set(indexes)) + + # Update all module indexes according to map old_index->new_index + def updateModuleIndex(self, moduleIndexMap): + if (moduleIndexMap is None or not issubclass(type(moduleIndexMap), list)): + raise InternalError() + self._genericBaseType.updateModuleIndex(moduleIndexMap) + for i in self._instArgs: + i.updateModuleIndex(moduleIndexMap) + self.verify() + + # Verify consistency + def verify(self): + if (self._elementKind is None or self._genericBaseType is None or self._instArgs is None): + raise InternalError() + + if (not issubclass(type(self._elementKind), int) or not issubclass(type(self._genericBaseType), TypeToken) + or not issubclass(type(self._instArgs), list)): + raise InternalError() + + if (self._elementKind < 0 or self._elementKind >= CorTypeInfo.CorElementType.X_ELEMENT_TYPE_LAST): + raise InternalError() + + for i in self._instArgs: + if (not issubclass(type(i), IType)): + raise InternalError() + + # Create from objects taking them by reference + @staticmethod + def createByRef(elementKind, genericBaseType, instArgs): + handle = TypeGeneric() + + handle._elementKind = elementKind # pylint: disable=protected-access + handle._genericBaseType = genericBaseType # pylint: disable=protected-access + handle._instArgs = instArgs # pylint: disable=protected-access + + handle.verify() + return handle + + # Create from objects taking them by copy + @staticmethod + def createByCopy(elementKind, genericBaseType, instArgs): + copiedArgs = [] + for i in instArgs: + copiedArgs.append(i.copy()) + + return TypeGeneric.createByRef(elementKind, genericBaseType.copy(), copiedArgs) + + # Copy object + def copy(self): + return TypeGeneric.createByCopy(self._elementKind, self._genericBaseType, self._instArgs) + + +# Corresponding to fnptr type +# +# To create from data structures using references: TypeFNPtr.createByRef(...) +# To create from data structures using copy: TypeFNPtr.createByCopy(...) +# +class TypeFNPtr(IType): + + # Empty constructor, do not use it directly + # Create new objects by createByCopy or createByRef + def __init__(self): + self._elementKind = None + self._callConv = None + self._retAndArgs = None + + # Equality comparison operator + def __eq__(self, rhs): + if (rhs is None): + return False + if (not issubclass(type(rhs), TypeFNPtr)): + return False + return self._elementKind == rhs._elementKind and self._callConv == rhs._callConv \ + and self._retAndArgs == rhs._retAndArgs + + # Convert to string + def getStr(self, modules=None): + if (not modules is None): + if (not issubclass(type(modules), list)): + raise InternalError() + for i in modules: + if (i is None or not issubclass(type(i), ModuleRecordExtended)): + raise InternalError() + + output = CorTypeInfo.getTypeMapEntry(self._elementKind).getName() + "{" + str(self._callConv) + "(" + + for index in range(len(self._retAndArgs)): + output += self._retAndArgs[index].getStr(modules) + if (index != (len(self._retAndArgs) - 1)): + output += "," + + output += ")}" + return output + + # Get elementKind + def getElementKind(self): + return self._elementKind + + # Get callConv + def getCallConv(self): + return self._callConv + + # Get retAndArgs + def getRetAndArgs(self): + return self._retAndArgs + + # Get all module indexes used in related types + def getAllModuleIndexes(self): + indexes = [] + for i in self._retAndArgs: + indexes += i.getAllModuleIndexes() + return sorted(set(indexes)) + + # Update all module indexes according to map old_index->new_index + def updateModuleIndex(self, moduleIndexMap): + if (moduleIndexMap is None or not issubclass(type(moduleIndexMap), list)): + raise InternalError() + for i in self._retAndArgs: + i.updateModuleIndex(moduleIndexMap) + self.verify() + + # Verify consistency + def verify(self): + if (self._elementKind is None or self._callConv is None or self._retAndArgs is None): + raise InternalError() + + if (not issubclass(type(self._elementKind), int) or not issubclass(type(self._callConv), int) + or not issubclass(type(self._retAndArgs), list)): + raise InternalError() + + if (self._elementKind < 0 or self._elementKind >= CorTypeInfo.CorElementType.X_ELEMENT_TYPE_LAST): + raise InternalError() + + if (self._callConv < 0 or self._callConv > Utility.getMaxForNBytes(RuntimeTypeSizes.char)): + raise InternalError() + + for i in self._retAndArgs: + if (not issubclass(type(i), IType)): + raise InternalError() + + # Create from objects taking them by reference + @staticmethod + def createByRef(elementKind, callConv, retAndArgs): + handle = TypeFNPtr() + + handle._elementKind = elementKind # pylint: disable=protected-access + handle._callConv = callConv # pylint: disable=protected-access + handle._retAndArgs = retAndArgs # pylint: disable=protected-access + + handle.verify() + return handle + + # Create from objects taking them by copy + @staticmethod + def createByCopy(elementKind, callConv, retAndArgs): + copiedRetAndArgs = [] + for i in retAndArgs: + copiedRetAndArgs.append(i.copy()) + + return TypeFNPtr.createByRef(elementKind, callConv, copiedRetAndArgs) + + # Copy object + def copy(self): + return TypeFNPtr.createByCopy(self._elementKind, self._callConv, self._retAndArgs) + + +# Corresponding to generic method +# +# To create from data structures using references: GenericMethod.createByRef(...) +# To create from data structures using copy: GenericMethod.createByCopy(...) +# +class GenericMethod: + + # Empty constructor, do not use it directly + # Create new objects by createByCopy or createByRef + def __init__(self): + self._methodFlags = None + self._moduleIndex = None + self._typeHandle = None + self._methodToken = None + self._methodInstArgs = None + + # Equality comparison operator + def __eq__(self, rhs): + if (rhs is None): + return False + if (not issubclass(type(rhs), GenericMethod)): + return False + return self._methodFlags == rhs._methodFlags and self._moduleIndex == rhs._moduleIndex \ + and self._typeHandle == rhs._typeHandle and self._methodToken == rhs._methodToken \ + and self._methodInstArgs == rhs._methodInstArgs + + # Convert to string + def getStr(self, modules=None): + if (not modules is None): + if (not issubclass(type(modules), list)): + raise InternalError() + for i in modules: + if (i is None or not issubclass(type(i), ModuleRecordExtended)): + raise InternalError() + + moduleStr = str(self._moduleIndex) + if (not modules is None): + moduleStr = modules[self._moduleIndex].getModuleName() + + output = "method{token{" + str(self._methodToken) + ":" + moduleStr + "}" + + if (not self._methodInstArgs is None): + output += "<" + for index in range(len(self._methodInstArgs)): + output += self._methodInstArgs[index].getStr(modules) + if (index != (len(self._methodInstArgs) - 1)): + output += "," + output += ">" + + output += "@type{" + self._typeHandle.getStr(modules) + "}}" + return output + + # Get methodFlags + def getMethodFlags(self): + return self._methodFlags + + # Get moduleIndex + def getModuleIndex(self): + return self._moduleIndex + + # Get typeHandle + def getTypeHandle(self): + return self._typeHandle + + # Get methodToken + def getMethodToken(self): + return self._methodToken + + # Get methodInstArgs + def getMethodInstArgs(self): + return self._methodInstArgs + + # Get all module indexes used in related types + def getAllModuleIndexes(self): + indexes = [self._moduleIndex] + indexes += self._typeHandle.getAllModuleIndexes() + if (not self._methodInstArgs is None): + for i in self._methodInstArgs: + indexes += i.getAllModuleIndexes() + return sorted(set(indexes)) + + # Update all module indexes according to map old_index->new_index + def updateModuleIndex(self, moduleIndexMap): + if (moduleIndexMap is None or not issubclass(type(moduleIndexMap), list)): + raise InternalError() + + self._moduleIndex = moduleIndexMap[self._moduleIndex] + self._typeHandle.updateModuleIndex(moduleIndexMap) + + if (not self._methodInstArgs is None): + for i in self._methodInstArgs: + i.updateModuleIndex(moduleIndexMap) + + self.verify() + + # Verify consistency + def verify(self): + if (self._methodFlags is None or self._moduleIndex is None or self._typeHandle is None + or self._methodToken is None): + raise InternalError() + + if (not issubclass(type(self._methodFlags), int) or not issubclass(type(self._moduleIndex), int) + or not issubclass(type(self._typeHandle), IType) or not issubclass(type(self._methodToken), int)): + raise InternalError() + + if (self._methodFlags < 0 or self._methodFlags > Utility.getMaxForNBytes(RuntimeTypeSizes.int)): + raise InternalError() + + if (self._moduleIndex < 0 or self._moduleIndex >= RuntimeConstants.MAX_MODULES): + raise InternalError() + + if (self._methodToken < 0 or self._methodToken > Utility.getMaxForNBytes(RuntimeTypeSizes.int)): + raise InternalError() + + if (not self._methodInstArgs is None): + if (not issubclass(type(self._methodInstArgs), list)): + raise InternalError() + + for i in self._methodInstArgs: + if (not issubclass(type(i), IType)): + raise InternalError() + + # Create from objects taking them by reference + @staticmethod + def createByRef(methodFlags, moduleIndex, typeHandle, methodToken, methodInstArgs): + method = GenericMethod() + + method._methodFlags = methodFlags # pylint: disable=protected-access + method._moduleIndex = moduleIndex # pylint: disable=protected-access + method._typeHandle = typeHandle # pylint: disable=protected-access + method._methodToken = methodToken # pylint: disable=protected-access + method._methodInstArgs = methodInstArgs # pylint: disable=protected-access + + method.verify() + return method + + # Create from objects taking them by copy + @staticmethod + def createByCopy(methodFlags, moduleIndex, typeHandle, methodToken, methodInstArgs): + copiedInstArgs = None + if (not methodInstArgs is None): + copiedInstArgs = [] + for i in methodInstArgs: + copiedInstArgs.append(i.copy()) + + return GenericMethod.createByRef(methodFlags, moduleIndex, typeHandle.copy(), methodToken, copiedInstArgs) + + # Copy object + def copy(self): + return GenericMethod.createByCopy(self._methodFlags, self._moduleIndex, self._typeHandle, + self._methodToken, self._methodInstArgs) + +#---------------------------------------------------------------------------------------------------------------------- +# Utilities for binary signature encoding/decoding +class SignatureDecoderUtil: + + # Corresponds to EncodeMethodSigFlags + # TODO: verify these constants somehow, see above + class EncodeMethodSigFlags: # pylint: disable=too-few-public-methods + ENCODE_METHOD_SIG_UnboxingStub = 0x01 + ENCODE_METHOD_SIG_InstantiatingStub = 0x02 + ENCODE_METHOD_SIG_MethodInstantiation = 0x04 + ENCODE_METHOD_SIG_SlotInsteadOfToken = 0x08 + ENCODE_METHOD_SIG_MemberRefToken = 0x10 + ENCODE_METHOD_SIG_Constrained = 0x20 + ENCODE_METHOD_SIG_OwnerType = 0x40 + ENCODE_METHOD_SIG_UpdateContext = 0x80 + + # Corresponds to CorTokenType + # TODO: verify these constants somehow, see above + class CorTokenType: # pylint: disable=too-few-public-methods + mdtModule = 0x00000000 + mdtTypeRef = 0x01000000 + mdtTypeDef = 0x02000000 + mdtFieldDef = 0x04000000 + mdtMethodDef = 0x06000000 + mdtParamDef = 0x08000000 + mdtInterfaceImpl = 0x09000000 + mdtMemberRef = 0x0a000000 + mdtCustomAttribute = 0x0c000000 + mdtPermission = 0x0e000000 + mdtSignature = 0x11000000 + mdtEvent = 0x14000000 + mdtProperty = 0x17000000 + mdtMethodImpl = 0x19000000 + mdtModuleRef = 0x1a000000 + mdtTypeSpec = 0x1b000000 + mdtAssembly = 0x20000000 + mdtAssemblyRef = 0x23000000 + mdtFile = 0x26000000 + mdtExportedType = 0x27000000 + mdtManifestResource = 0x28000000 + mdtNestedClass = 0x29000000 + mdtGenericParam = 0x2a000000 + mdtMethodSpec = 0x2b000000 + mdtGenericParamConstraint = 0x2c000000 + mdtString = 0x70000000 + mdtName = 0x71000000 + mdtBaseType = 0x72000000 + + # Get token from rid and type + @staticmethod + def getTokenFromRid(rid, typ): + return rid | typ + + # Get rid from token + @staticmethod + def getRidFromToken(token): + return token & 0x00ffffff + + # Get type from token + @staticmethod + def getTypeFromToken(token): + return token & 0xff000000 + +#---------------------------------------------------------------------------------------------------------------------- +# Decoder for binary signature of method that is created by MCJ +# +# Conceptually corresponds to ZapSig::DecodeMethod +# +class MethodBinarySignatureDecoder: # pylint: disable=too-few-public-methods + + # Constructor with module index for binary signature and binary signature itself + def __init__(self, moduleIndex, bytesArr): + if (moduleIndex is None or bytesArr is None): + raise InternalError() + if (not issubclass(type(moduleIndex), int) or not issubclass(type(bytesArr), list)): + raise InternalError() + + for i in bytesArr: + if (i < 0 or i > Utility.getMaxForNBytes(RuntimeTypeSizes.char)): + raise InternalError() + + self._moduleIndex = moduleIndex + self._bytesArr = bytesArr + self._index = 0 + + # Decode one byte from binary signature + # + # See SigBuilder::AppendByte + def _decodeByte(self): + value = self._bytesArr[self._index] + self._index += 1 + return value + + # Decode value (1, 2 or 4 bytes) from binary signature + # + # See SigBuilder::AppendData + def _decodeValue(self): + value = 0 + + if ((self._bytesArr[self._index] & 0x80) == 0): + # 1 byte case + length = 1 + if (self._index + length > len(self._bytesArr)): + raise ProfileInconsistencyError() + value = self._bytesArr[self._index] + if (value > 0x7f): + raise InternalError() + elif ((self._bytesArr[self._index] & 0xc0) == 0x80): + # 2 byte case + length = 2 + if (self._index + length > len(self._bytesArr)): + raise ProfileInconsistencyError() + value = ((self._bytesArr[self._index] & 0x3f) << 8) | self._bytesArr[self._index + 1] + if (value > 0x3fff): + raise InternalError() + elif ((self._bytesArr[self._index] & 0xe0) == 0xc0): + # 4 byte case + length = 4 + if (self._index + length > len(self._bytesArr)): + raise ProfileInconsistencyError() + value = ((self._bytesArr[self._index] & 0x1f) << 24) | (self._bytesArr[self._index + 1] << 16) + value = value | (self._bytesArr[self._index + 2] << 8) | self._bytesArr[self._index + 3] + if (value > 0x1fffffff): + raise InternalError() + else: + raise ProfileInconsistencyError() + + self._index += length + + return value + + # Decode token from binary signature + # + # See SigBuilder::AppendToken + def _decodeToken(self): + value = self._decodeValue() + + # get encode type and rid + encodedType = value & 0x3 + rid = value >> 2 + typ = None + + if (encodedType == 0x0): + typ = SignatureDecoderUtil.CorTokenType.mdtTypeDef + elif (encodedType == 0x1): + typ = SignatureDecoderUtil.CorTokenType.mdtTypeRef + elif (encodedType == 0x2): + typ = SignatureDecoderUtil.CorTokenType.mdtTypeSpec + elif (encodedType == 0x3): + typ = SignatureDecoderUtil.CorTokenType.mdtBaseType + else: + raise ProfileInconsistencyError() + + return SignatureDecoderUtil.getTokenFromRid(rid, typ) + + # Decode type from binary signature + # + # See ZapSig::GetSignatureForTypeHandle + def _decodeSignatureForTypeHandle(self, moduleIndex): # pylint: disable=too-many-locals, too-many-return-statements, too-many-statements + if (moduleIndex is None or not issubclass(type(moduleIndex), int)): + raise InternalError() + + # I. Decode type + typ = self._decodeByte() + + # II. Decode primitive type + if (typ < CorTypeInfo.CorElementType.ELEMENT_TYPE_MAX + and (CorTypeInfo.getTypeMapEntry(typ).getIsPrim() + or typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_STRING + or typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_OBJECT)): + return TypeSimple.createByRef(typ) + + # III. Decode non-primitive type + if (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_TYPEDBYREF): # pylint: disable=no-else-raise + # TODO: support this? + raise UnsupportedError() + elif (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG): + paramType = self._decodeSignatureForTypeHandle(moduleIndex) + return TypeParamType.createByRef(typ, paramType) + elif (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_CANON_ZAPSIG): + return TypeSimple.createByRef(typ) + elif (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_MODULE_ZAPSIG): + nextModuleIndex = self._decodeValue() + return self._decodeSignatureForTypeHandle(nextModuleIndex) + elif (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_VAR_ZAPSIG): + rid = self._decodeValue() + typeToken = SignatureDecoderUtil.getTokenFromRid(rid, SignatureDecoderUtil.CorTokenType.mdtGenericParam) + return TypeToken.createByRef(typ, moduleIndex, typeToken) + elif (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_VAR): # pylint: disable=no-else-raise + # TODO: support this? + raise UnsupportedError() + elif (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_MVAR): # pylint: disable=no-else-raise + # TODO: support this? + raise UnsupportedError() + elif (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_GENERICINST): + nextTyp = self._decodeByte() + + if (nextTyp == CorTypeInfo.CorElementType.ELEMENT_TYPE_INTERNAL): # pylint: disable=no-else-raise + # TODO: support this? + raise UnsupportedError() + else: + typeToken = self._decodeToken() + tid = SignatureDecoderUtil.getTypeFromToken(typeToken) + + if (not tid in (SignatureDecoderUtil.CorTokenType.mdtTypeRef, + SignatureDecoderUtil.CorTokenType.mdtTypeDef)): + raise ProfileInconsistencyError() + + numArgs = self._decodeValue() + args = [] + for i in range(numArgs): # pylint: disable=unused-variable + args.append(self._decodeSignatureForTypeHandle(moduleIndex)) + + return TypeGeneric.createByRef(typ, TypeToken.createByRef(nextTyp, moduleIndex, typeToken), args) + elif (typ in (CorTypeInfo.CorElementType.ELEMENT_TYPE_CLASS, + CorTypeInfo.CorElementType.ELEMENT_TYPE_VALUETYPE)): + typeToken = self._decodeToken() + tid = SignatureDecoderUtil.getTypeFromToken(typeToken) + + if (not tid in (SignatureDecoderUtil.CorTokenType.mdtTypeRef, + SignatureDecoderUtil.CorTokenType.mdtTypeDef)): + raise ProfileInconsistencyError() + + return TypeToken.createByRef(typ, moduleIndex, typeToken) + elif (typ in (CorTypeInfo.CorElementType.ELEMENT_TYPE_ARRAY, CorTypeInfo.CorElementType.ELEMENT_TYPE_SZARRAY)): + elemType = self._decodeSignatureForTypeHandle(moduleIndex) + + if (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_ARRAY): # pylint: disable=no-else-return + rank = self._decodeValue() + # Next two values are always written as 0 (see ZapSig::GetSignatureForTypeHandle) + nsizes = self._decodeValue() + nlbounds = self._decodeValue() + + if (nsizes != 0 or nlbounds != 0): + raise UnsupportedError() + + return TypeArray.createByRef(typ, elemType, rank) + else: + return TypeSZArray.createByRef(typ, elemType) + elif (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_PINNED): + nextType = self._decodeSignatureForTypeHandle(moduleIndex) + return TypeParamType.createByRef(typ, nextType) + elif (typ in (CorTypeInfo.CorElementType.ELEMENT_TYPE_BYREF, CorTypeInfo.CorElementType.ELEMENT_TYPE_PTR)): + paramType = self._decodeSignatureForTypeHandle(moduleIndex) + return TypeParamType.createByRef(typ, paramType) + elif (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_FNPTR): + callConv = self._decodeByte() + cArgs = self._decodeValue() + retAndArgs = [] + for i in range(cArgs): + retAndArgs.append(self._decodeSignatureForTypeHandle(moduleIndex)) + return TypeFNPtr.createByRef(typ, callConv, retAndArgs) + elif (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_INTERNAL): # pylint: disable=no-else-raise + # TODO: support this? + raise UnsupportedError() + elif (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_SENTINEL): # pylint: disable=no-else-raise + # TODO: support this? + raise UnsupportedError() + else: + raise InternalError() + + # Decode binary signature for method, result can be used by reference + # + # See ZapSig::DecodeMethod + def decodeMethod(self): + typeHandle = None + methodToken = None + numInstArgs = None + methodInstArgs = None + + # I. Decode method flags + methodFlags = self._decodeValue() + + # II. Decode type + if (methodFlags & SignatureDecoderUtil.EncodeMethodSigFlags.ENCODE_METHOD_SIG_UpdateContext != 0): + # Should not be encoded in mcj profile + raise UnsupportedError() + + if ((methodFlags & SignatureDecoderUtil.EncodeMethodSigFlags.ENCODE_METHOD_SIG_OwnerType) != 0): + typeHandle = self._decodeSignatureForTypeHandle(self._moduleIndex) + else: + raise UnsupportedError() + + # III. Decode method token + if (methodFlags & SignatureDecoderUtil.EncodeMethodSigFlags.ENCODE_METHOD_SIG_SlotInsteadOfToken != 0): # pylint: disable=no-else-raise + raise UnsupportedError() + else: + rid = self._decodeValue() + + if (methodFlags & SignatureDecoderUtil.EncodeMethodSigFlags.ENCODE_METHOD_SIG_MemberRefToken): + methodToken = SignatureDecoderUtil.getTokenFromRid(rid, SignatureDecoderUtil.CorTokenType.mdtMemberRef) + else: + methodToken = SignatureDecoderUtil.getTokenFromRid(rid, SignatureDecoderUtil.CorTokenType.mdtMethodDef) + + # IV. Decode method instantiation args + if (methodFlags & SignatureDecoderUtil.EncodeMethodSigFlags.ENCODE_METHOD_SIG_MethodInstantiation != 0): + numInstArgs = self._decodeValue() + + methodInstArgs = [] + for i in range(numInstArgs): # pylint: disable=unused-variable + methodInstArgs.append(self._decodeSignatureForTypeHandle(self._moduleIndex)) + + if (methodFlags & SignatureDecoderUtil.EncodeMethodSigFlags.ENCODE_METHOD_SIG_Constrained != 0): + raise UnsupportedError() + + ret = GenericMethod.createByRef(methodFlags, self._moduleIndex, typeHandle, methodToken, methodInstArgs) + + self._moduleIndex = None + self._bytesArr = None + self._index = None + + return ret + +#---------------------------------------------------------------------------------------------------------------------- +# Encoder for binary signature of method that is stored in MCJ profile +# +# Conceptually corresponds to ZapSig::EncodeMethod +# +class MethodBinarySignatureEncoder: # pylint: disable=too-few-public-methods + + # Constructor with generic method handle + def __init__(self, methodHandle): + if (methodHandle is None or not issubclass(type(methodHandle), GenericMethod)): + raise InternalError() + + self._methodHandle = methodHandle + self._bytesArr = [] + + # Encode one byte to binary signature + # + # See SigBuilder::AppendByte + def _encodeByte(self, value): + if (value is None or not issubclass(type(value), int)): + raise InternalError() + if (value < 0 or value > Utility.getMaxForNBytes(RuntimeTypeSizes.char)): + raise InternalError() + + self._bytesArr.append(value) + + # Encode value (1, 2 or 4 bytes) to binary signature + # + # See SigBuilder::AppendData + def _encodeValue(self, value): + if (value is None or not issubclass(type(value), int)): + raise InternalError() + if (value < 0 or value > Utility.getMaxForNBytes(RuntimeTypeSizes.int)): + raise InternalError() + + if (value <= 0x7f): + self._bytesArr.append(value) + elif (value <= 0x3fff): + self._bytesArr.append((value >> 8) | 0x80) + self._bytesArr.append(value & 0xff) + elif (value <= 0x1fffffff): + self._bytesArr.append((value >> 24) | 0xc0) + self._bytesArr.append((value >> 16) & 0xff) + self._bytesArr.append((value >> 8) & 0xff) + self._bytesArr.append(value & 0xff) + else: + raise InternalError() + + # Encode token to binary signature + # + # See SigBuilder::AppendToken + def _encodeToken(self, value): + if (value is None or not issubclass(type(value), int)): + raise InternalError() + if (value < 0 or value > Utility.getMaxForNBytes(RuntimeTypeSizes.int)): + raise InternalError() + + rid = SignatureDecoderUtil.getRidFromToken(value) + typ = SignatureDecoderUtil.getTypeFromToken(value) + + if (rid > 0x3ffffff): + raise InternalError() + + rid = rid << 2 + + if (typ == SignatureDecoderUtil.CorTokenType.mdtTypeDef): + pass + elif (typ == SignatureDecoderUtil.CorTokenType.mdtTypeRef): + rid |= 0x1 + elif (typ == SignatureDecoderUtil.CorTokenType.mdtTypeSpec): + rid |= 0x2 + elif (typ == SignatureDecoderUtil.CorTokenType.mdtBaseType): + rid |= 0x3 + + self._encodeValue(rid) + + # Encode type to binary signature + # + # See ZapSig::GetSignatureForTypeHandle + def _encodeSignatureForTypeHandle(self, typeHandle): + if (typeHandle is None or not issubclass(type(typeHandle), IType)): + raise InternalError() + + # I. Encode element type + if (issubclass(type(typeHandle), TypeSimple)): + self._encodeByte(typeHandle.getElementKind()) + elif (issubclass(type(typeHandle), TypeToken)): + if (typeHandle.getModuleIndex() != self._methodHandle.getModuleIndex()): + self._encodeByte(CorTypeInfo.CorElementType.ELEMENT_TYPE_MODULE_ZAPSIG) + self._encodeValue(typeHandle.getModuleIndex()) + + self._encodeByte(typeHandle.getElementKind()) + + if (typeHandle.getElementKind() == CorTypeInfo.CorElementType.ELEMENT_TYPE_VAR_ZAPSIG): + self._encodeValue(SignatureDecoderUtil.getRidFromToken(typeHandle.getTypeToken())) + else: + self._encodeToken(typeHandle.getTypeToken()) + elif (issubclass(type(typeHandle), TypeParamType)): + self._encodeByte(typeHandle.getElementKind()) + self._encodeSignatureForTypeHandle(typeHandle.getParamType()) + elif (issubclass(type(typeHandle), TypeArray)): + self._encodeByte(typeHandle.getElementKind()) + self._encodeSignatureForTypeHandle(typeHandle.getArrayElementType()) + self._encodeValue(typeHandle.getRank()) + self._encodeValue(0) + self._encodeValue(0) + elif (issubclass(type(typeHandle), TypeSZArray)): + self._encodeByte(typeHandle.getElementKind()) + self._encodeSignatureForTypeHandle(typeHandle.getArrayElementType()) + elif (issubclass(type(typeHandle), TypeGeneric)): + genericBaseType = typeHandle.getGenericBaseType() + if (genericBaseType.getModuleIndex() != self._methodHandle.getModuleIndex()): + self._encodeByte(CorTypeInfo.CorElementType.ELEMENT_TYPE_MODULE_ZAPSIG) + self._encodeValue(genericBaseType.getModuleIndex()) + + self._encodeByte(typeHandle.getElementKind()) + self._encodeByte(genericBaseType.getElementKind()) + self._encodeToken(genericBaseType.getTypeToken()) + + self._encodeValue(len(typeHandle.getInstArgs())) + for i in typeHandle.getInstArgs(): + self._encodeSignatureForTypeHandle(i) + elif (issubclass(type(typeHandle), TypeFNPtr)): + self._encodeByte(typeHandle.getElementKind()) + self._encodeByte(typeHandle.getCallConv()) + + self._encodeValue(len(typeHandle.getRetAndArgs())) + for i in typeHandle.getRetAndArgs(): + self._encodeSignatureForTypeHandle(i) + + # Encode binary signature for method, result can be used by reference + # + # See ZapSig::EncodeMethod + def encodeMethod(self): + methodFlags = self._methodHandle.getMethodFlags() + + # I. Encode method flags + self._encodeValue(methodFlags) + + # II. Encode type + if ((methodFlags & SignatureDecoderUtil.EncodeMethodSigFlags.ENCODE_METHOD_SIG_OwnerType) != 0): + self._encodeSignatureForTypeHandle(self._methodHandle.getTypeHandle()) + else: + raise UnsupportedError() + + # III. Encode method token + if (methodFlags & SignatureDecoderUtil.EncodeMethodSigFlags.ENCODE_METHOD_SIG_SlotInsteadOfToken != 0): # pylint: disable=no-else-raise + raise UnsupportedError() + else: + self._encodeValue(SignatureDecoderUtil.getRidFromToken(self._methodHandle.getMethodToken())) + + # IV. Encode method instantiation args + if (methodFlags & SignatureDecoderUtil.EncodeMethodSigFlags.ENCODE_METHOD_SIG_MethodInstantiation != 0): + methodInstArgs = self._methodHandle.getMethodInstArgs() + + if (methodInstArgs is None): + raise InternalError() + + self._encodeValue(len(methodInstArgs)) + for i in methodInstArgs: + self._encodeSignatureForTypeHandle(i) + + ret = self._bytesArr + + self._bytesArr = None + self._methodHandle = None + + return ret + +# ---------------------------------------------------------------------------------------------------------------------- +# Base class for records with module dependency or method +# +class Info(ABC): + + # Get record type + @abstractmethod + def getRecordType(self): + pass + + # Get module index + @abstractmethod + def getModuleIndex(self): + pass + + # Get all module indexes used in related types + def getAllModuleIndexes(self): + pass + + # Check if info is related to generic method + @abstractmethod + def isGenericMethodInfo(self): + pass + + # Check if info is related to non-generic method + @abstractmethod + def isNonGenericMethodInfo(self): + pass + + # Check if info is related to method + @abstractmethod + def isMethodInfo(self): + pass + + # Check if info is related to module + @abstractmethod + def isModuleInfo(self): + pass + +# ---------------------------------------------------------------------------------------------------------------------- +# Record with module dependency +# +# Conceptually corresponds to "struct RecorderInfo" from multicorejitimpl.h, but has slight differences +# +# To create from bytes: InfoModuleDependency.createFromBytes(bytes) +# To create from data structures using references: InfoModuleDependency.createByRef(...) +# To create from data structures using copy: InfoModuleDependency.createByCopy(...) +# +class InfoModuleDependency(Info): + + # Empty constructor, do not use it directly + # Create new objects by createByCopy or createByRef + def __init__(self): + self._moduleIndex = None + self._moduleLoadLevel = None + + # Equality comparison operator + def __eq__(self, rhs): + if (rhs is None or not issubclass(type(rhs), InfoModuleDependency)): + return False + return self._moduleIndex == rhs._moduleIndex and self._moduleLoadLevel == rhs._moduleLoadLevel + + # Get record type + def getRecordType(self): # pylint: disable=no-self-use + return RuntimeConstants.MULTICOREJIT_MODULEDEPENDENCY_RECORD_ID + + # Check if info is related to generic method + def isGenericMethodInfo(self): # pylint: disable=no-self-use + return False + + # Check if info is related to non-generic method + def isNonGenericMethodInfo(self): # pylint: disable=no-self-use + return False + + # Check if info is related to method + def isMethodInfo(self): # pylint: disable=no-self-use + return False + + # Check if info is related to module + def isModuleInfo(self): # pylint: disable=no-self-use + return True + + # Get module index + def getModuleIndex(self): + return self._moduleIndex + + # Get all module indexes used in related types + def getAllModuleIndexes(self): + return [self._moduleIndex] + + # Get module load level + def getModuleLoadLevel(self): + return self._moduleLoadLevel + + # Update module index according to map old_index->new_index + def updateModuleIndex(self, moduleIndexMap): + if (moduleIndexMap is None or not issubclass(type(moduleIndexMap), list)): + raise InternalError() + self._moduleIndex = moduleIndexMap[self._moduleIndex] + self.verify() + + # Verify consistency + def verify(self): + if (self._moduleIndex is None or self._moduleLoadLevel is None): + raise InternalError() + + if (not issubclass(type(self._moduleIndex), int) or not issubclass(type(self._moduleLoadLevel), int)): + raise InternalError() + + if (self._moduleIndex < 0 or self._moduleIndex >= RuntimeConstants.MAX_MODULES): + raise InternalError() + + if (self._moduleLoadLevel < 0 or self._moduleLoadLevel >= RuntimeConstants.MAX_MODULE_LEVELS): + raise InternalError() + + # Encode info + def _encodeInfo(self): + data1 = 0 + # high byte is record id + data1 |= RuntimeConstants.MULTICOREJIT_MODULEDEPENDENCY_RECORD_ID << RuntimeConstants.RECORD_TYPE_OFFSET + # next byte is load level + data1 |= self._moduleLoadLevel << RuntimeConstants.MODULE_LEVEL_OFFSET + # two low bytes are module index + data1 |= self._moduleIndex + return data1 + + # Decode type of this record, module index and module load level + @staticmethod + def _decodeInfo(data1): + recordType = data1 >> RuntimeConstants.RECORD_TYPE_OFFSET + loadLevel = (data1 >> RuntimeConstants.MODULE_LEVEL_OFFSET) & (RuntimeConstants.MAX_MODULE_LEVELS - 1) + moduleIndex = data1 & RuntimeConstants.MODULE_MASK + return (recordType, loadLevel, moduleIndex) + + # Print raw + def printRaw(self, offsetStr=""): + if (offsetStr is None or not issubclass(type(offsetStr), str)): + raise InternalError() + + data1 = self._encodeInfo() + + print(offsetStr + ">>> Raw ModuleDependency:") + print(offsetStr + "data1 = " + str(data1)) + + # Print pretty + def print(self, offsetStr="", modules=None): + if (offsetStr is None or not issubclass(type(offsetStr), str)): + raise InternalError() + + # Get module name if it is available + moduleName = "" + if (not modules is None): + moduleName = modules[self.getModuleIndex()].getModuleName() + + print(offsetStr + ">>> Record, Module Dependency:") + print(offsetStr + "") + print(offsetStr + "Module index: " + str(self.getModuleIndex()) + + ((" (" + moduleName + ")") if moduleName != "" else "")) + print(offsetStr + "Module load level: " + str(self.getModuleLoadLevel())) + print(offsetStr + "") + + # Create from bytes + @staticmethod + def createFromBytes(bytesArr): + if (bytesArr is None): + raise InternalError() + + if (not issubclass(type(bytesArr), list)): + raise InternalError() + + if (len(bytesArr) != RuntimeTypeSizes.int): + raise ProfileInconsistencyError() + + index = 0 + + data1 = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int]) + index += RuntimeTypeSizes.int + + if (index != RuntimeTypeSizes.int): + raise InternalError() + + recordType, moduleLoadLevel, moduleIndex = InfoModuleDependency._decodeInfo(data1) + + if (recordType != RuntimeConstants.MULTICOREJIT_MODULEDEPENDENCY_RECORD_ID): + raise InternalError() + + return InfoModuleDependency.createByRef(moduleIndex, moduleLoadLevel) + + # Create from objects taking them by reference + @staticmethod + def createByRef(moduleIndex, moduleLoadLevel): + moduleDependency = InfoModuleDependency() + + moduleDependency._moduleIndex = moduleIndex # pylint: disable=protected-access + moduleDependency._moduleLoadLevel = moduleLoadLevel # pylint: disable=protected-access + + moduleDependency.verify() + return moduleDependency + + # Create from objects taking them by copy + @staticmethod + def createByCopy(moduleIndex, moduleLoadLevel): + return InfoModuleDependency.createByRef(moduleIndex, moduleLoadLevel) + + # Copy object + def copy(self): + return InfoModuleDependency.createByCopy(self._moduleIndex, self._moduleLoadLevel) + + # Convert object to list of bytes + def convertToBytes(self): + index = 0 + + bytesArr = [] + + data1 = self._encodeInfo() + + bytesArr += Utility.splitNBytes(data1, RuntimeTypeSizes.int) + index += RuntimeTypeSizes.int + + if (index != RuntimeTypeSizes.int): + raise InternalError() + + return bytesArr + +# ---------------------------------------------------------------------------------------------------------------------- +# Record with non-generic method +# +# Conceptually corresponds to "struct RecorderInfo" from multicorejitimpl.h, but has slight differences +# +# To create from bytes: InfoNonGenericMethod.createFromBytes(bytes) +# To create from data structures using references: InfoNonGenericMethod.createByRef(...) +# To create from data structures using copy: InfoNonGenericMethod.createByCopy(...) +# +class InfoNonGenericMethod(Info): + + # Empty constructor, do not use it directly + # Create new objects by createByCopy or createByRef + def __init__(self): + self._moduleIndex = None + self._methodFlags = None + self._methodToken = None + + # Equality comparison operator + def __eq__(self, rhs): + if (rhs is None or not issubclass(type(rhs), InfoNonGenericMethod)): + return False + return self._moduleIndex == rhs._moduleIndex and self._methodFlags == rhs._methodFlags \ + and self._methodToken == rhs._methodToken + + # Get record type + def getRecordType(self): # pylint: disable=no-self-use + return RuntimeConstants.MULTICOREJIT_METHOD_RECORD_ID + + # Check if info is related to generic method + def isGenericMethodInfo(self): # pylint: disable=no-self-use + return False + + # Check if info is related to non-generic method + def isNonGenericMethodInfo(self): # pylint: disable=no-self-use + return True + + # Check if info is related to method + def isMethodInfo(self): # pylint: disable=no-self-use + return True + + # Check if info is related to module + def isModuleInfo(self): # pylint: disable=no-self-use + return False + + # Get module index + def getModuleIndex(self): + return self._moduleIndex + + # Get all module indexes used in related types + def getAllModuleIndexes(self): + return [self._moduleIndex] + + # Get method flags + def getMethodFlags(self): + return self._methodFlags + + # Get method token + def getMethodToken(self): + return self._methodToken + + # Update module index according to map old_index->new_index + def updateModuleIndex(self, moduleIndexMap): + if (moduleIndexMap is None or not issubclass(type(moduleIndexMap), list)): + raise InternalError() + self._moduleIndex = moduleIndexMap[self._moduleIndex] + self.verify() + + # Verify consistency + def verify(self): + if (self._moduleIndex is None or self._methodFlags is None or self._methodToken is None): + raise InternalError() + + if (not issubclass(type(self._moduleIndex), int) or not issubclass(type(self._methodFlags), int) + or not issubclass(type(self._methodToken), int)): + raise InternalError() + + if (self._moduleIndex < 0 or self._moduleIndex >= RuntimeConstants.MAX_MODULES): + raise InternalError() + + if (self._methodFlags < 0 + or ((self._methodFlags | RuntimeConstants.METHOD_FLAGS_MASK) ^ RuntimeConstants.METHOD_FLAGS_MASK) != 0): + raise InternalError() + + if (self._methodToken < 0 or self._methodToken > Utility.getMaxForNBytes(RuntimeTypeSizes.int)): + raise InternalError() + + # Encode info + def _encodeInfo(self): + data1 = 0 + # high byte is record id + data1 |= RuntimeConstants.MULTICOREJIT_METHOD_RECORD_ID << RuntimeConstants.RECORD_TYPE_OFFSET + # next byte is method flags + data1 |= self._methodFlags + # two low bytes are module index + data1 |= self._moduleIndex + + # this is simply token + data2 = self._methodToken + + return (data1, data2) + + # Decode type of this record, module index and module load level + @staticmethod + def _decodeInfo(data1, data2): + recordType = data1 >> RuntimeConstants.RECORD_TYPE_OFFSET + methodFlags = data1 & RuntimeConstants.METHOD_FLAGS_MASK + moduleIndex = data1 & RuntimeConstants.MODULE_MASK + methodToken = data2 + return (recordType, methodFlags, moduleIndex, methodToken) + + # Print raw + def printRaw(self, offsetStr=""): + if (offsetStr is None or not issubclass(type(offsetStr), str)): + raise InternalError() + + data1, data2 = self._encodeInfo() + + print(offsetStr + ">>> Raw Non-Generic MethodRecord:") + print(offsetStr + "data1 = " + str(data1)) + print(offsetStr + "data2 = " + str(data2)) + + # Print pretty + def print(self, offsetStr="", modules=None): + if (offsetStr is None or not issubclass(type(offsetStr), str)): + raise InternalError() + + # Get module name if it is available + moduleName = "" + if (not modules is None): + moduleName = modules[self.getModuleIndex()].getModuleName() + + flagsStr = "jitted by background thread" + if (self._methodFlags & RuntimeConstants.JIT_BY_APP_THREAD_TAG != 0): + flagsStr = "jitted by foreground (app) thread" + + print(offsetStr + ">>> Record, Non-generic Method:") + print(offsetStr + "") + print(offsetStr + "Module index: " + str(self.getModuleIndex()) + + ((" (" + moduleName + ")") if moduleName != "" else "")) + print(offsetStr + "Method flags: " + str(self.getMethodFlags()) + " (" + flagsStr + ")") + print(offsetStr + "Method token: " + str(self.getMethodToken())) + print(offsetStr + "") + + # Create from bytes + @staticmethod + def createFromBytes(bytesArr): + if (bytesArr is None): + raise InternalError() + + if (not issubclass(type(bytesArr), list)): + raise InternalError() + + if (len(bytesArr) != 2 * RuntimeTypeSizes.int): + raise ProfileInconsistencyError() + + index = 0 + + data1 = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int]) + index += RuntimeTypeSizes.int + + data2 = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int]) + index += RuntimeTypeSizes.int + + if (index != 2 * RuntimeTypeSizes.int): + raise InternalError() + + recordType, methodFlags, moduleIndex, methodToken = InfoNonGenericMethod._decodeInfo(data1, data2) + + if (recordType != RuntimeConstants.MULTICOREJIT_METHOD_RECORD_ID): + raise InternalError() + + return InfoNonGenericMethod.createByRef(moduleIndex, methodFlags, methodToken) + + # Create from objects taking them by reference + @staticmethod + def createByRef(moduleIndex, methodFlags, methodToken): + method = InfoNonGenericMethod() + + method._moduleIndex = moduleIndex # pylint: disable=protected-access + method._methodFlags = methodFlags # pylint: disable=protected-access + method._methodToken = methodToken # pylint: disable=protected-access + + method.verify() + return method + + # Create from objects taking them by copy + @staticmethod + def createByCopy(moduleIndex, methodFlags, methodToken): + return InfoNonGenericMethod.createByRef(moduleIndex, methodFlags, methodToken) + + # Copy object + def copy(self): + return InfoNonGenericMethod.createByCopy(self._moduleIndex, self._methodFlags, self._methodToken) + + # Convert object to list of bytes + def convertToBytes(self): + index = 0 + + bytesArr = [] + + data1, data2 = self._encodeInfo() + + bytesArr += Utility.splitNBytes(data1, RuntimeTypeSizes.int) + index += RuntimeTypeSizes.int + + bytesArr += Utility.splitNBytes(data2, RuntimeTypeSizes.int) + index += RuntimeTypeSizes.int + + if (index != 2 * RuntimeTypeSizes.int): + raise InternalError() + + return bytesArr +# ---------------------------------------------------------------------------------------------------------------------- +# Record with generic method +# +# Conceptually corresponds to "struct RecorderInfo" from multicorejitimpl.h, but has slight differences +# +# To create from bytes: InfoGenericMethod.createFromBytes(bytes) +# To create from data structures using references: InfoGenericMethod.createByRef(...) +# To create from data structures using copy: InfoGenericMethod.createByCopy(...) +# +class InfoGenericMethod(Info): # pylint: disable=too-many-public-methods + + # Empty constructor, do not use it directly + # Create new objects by createByCopy or createByRef + def __init__(self): + self._methodFlags = None + self._methodHandle = None + + # Equality comparison operator + def __eq__(self, rhs): + if (rhs is None or not issubclass(type(rhs), InfoGenericMethod)): + return False + return self._methodFlags == rhs._methodFlags and self._methodHandle == rhs._methodHandle + + # Get record type + def getRecordType(self): # pylint: disable=no-self-use + return RuntimeConstants.MULTICOREJIT_GENERICMETHOD_RECORD_ID + + # Check if info is related to generic method + def isGenericMethodInfo(self): # pylint: disable=no-self-use + return True + + # Check if info is related to non-generic method + def isNonGenericMethodInfo(self): # pylint: disable=no-self-use + return False + + # Check if info is related to method + def isMethodInfo(self): # pylint: disable=no-self-use + return True + + # Check if info is related to module + def isModuleInfo(self): # pylint: disable=no-self-use + return False + + # Get module index + def getModuleIndex(self): + return self._methodHandle.getModuleIndex() + + # Get all module indexes used in related types + def getAllModuleIndexes(self): + return self._methodHandle.getAllModuleIndexes() + + # Get method flags + def getMethodFlags(self): + return self._methodFlags + + # Get method handle + def getMethodHandle(self): + return self._methodHandle + + # Get method token + def getMethodToken(self): + return self._methodHandle.getMethodToken() + + # Update module index according to map old_index->new_index + def updateModuleIndex(self, moduleIndexMap): + if (moduleIndexMap is None or not issubclass(type(moduleIndexMap), list)): + raise InternalError() + self._methodHandle.updateModuleIndex(moduleIndexMap) + self.verify() + + # Verify consistency + def verify(self): + if (self._methodFlags is None or self._methodHandle is None): + raise InternalError() + + if (not issubclass(type(self._methodFlags), int) or not issubclass(type(self._methodHandle), GenericMethod)): + raise InternalError() + + if (self._methodFlags < 0 + or ((self._methodFlags | RuntimeConstants.METHOD_FLAGS_MASK) ^ RuntimeConstants.METHOD_FLAGS_MASK) != 0): + raise InternalError() + + # Encode info + def _encodeInfo(self): + binarySignature = MethodBinarySignatureEncoder(self._methodHandle).encodeMethod() + + data1 = 0 + # high byte is record id + data1 |= RuntimeConstants.MULTICOREJIT_GENERICMETHOD_RECORD_ID << RuntimeConstants.RECORD_TYPE_OFFSET + # next byte is method flags + data1 |= self._methodFlags + # two low bytes are module index + data1 |= self._methodHandle.getModuleIndex() + + # this is simply length of binary signature + data2 = len(binarySignature) + + # this is simply binary signature + ptr = binarySignature + + return (data1, data2, ptr) + + # Decode type of this record, module index and module load level + @staticmethod + def _decodeInfo(data1, data2, ptr): # pylint: disable=unused-argument + recordType = data1 >> RuntimeConstants.RECORD_TYPE_OFFSET + methodFlags = data1 & RuntimeConstants.METHOD_FLAGS_MASK + moduleIndex = data1 & RuntimeConstants.MODULE_MASK + + method = MethodBinarySignatureDecoder(moduleIndex, ptr).decodeMethod() + + return (recordType, methodFlags, method) + + # Print raw + def printRaw(self, offsetStr=""): + if (offsetStr is None or not issubclass(type(offsetStr), str)): + raise InternalError() + + data1, data2, ptr = self._encodeInfo() + + size = RuntimeTypeSizes.int + RuntimeTypeSizes.short + data2 + padding = Utility.alignUp(size, RuntimeTypeSizes.int) - size + + print(offsetStr + ">>> Raw Generic MethodRecord:") + print(offsetStr + "data1 = " + str(data1)) + print(offsetStr + "data2 = " + str(data2)) + print(offsetStr + "ptr = " + str(ptr)) + print(offsetStr + "alignment padding = " + str(padding) + " bytes") + + # Print pretty + def print(self, offsetStr="", modules=None): + if (offsetStr is None or not issubclass(type(offsetStr), str)): + raise InternalError() + + # Get module name if it is available + moduleName = "" + if (not modules is None): + if (modules is None or not issubclass(type(modules), list)): + raise InternalError() + for i in modules: + if (i is None or not issubclass(type(i), ModuleRecordExtended)): + raise InternalError() + + moduleName = modules[self.getModuleIndex()].getModuleName() + + flagsStr = "jitted by background thread" + if (self._methodFlags & RuntimeConstants.JIT_BY_APP_THREAD_TAG != 0): + flagsStr = "jitted by foreground (app) thread" + + print(offsetStr + ">>> Record, Generic Method:") + print(offsetStr + "") + print(offsetStr + "Module index: " + str(self.getModuleIndex()) + + ((" (" + moduleName + ")") if moduleName != "" else "")) + print(offsetStr + "Method flags: " + str(self.getMethodFlags()) + " (" + flagsStr + ")") + print(offsetStr + "Decoded binary signature: " + self.getMethodHandle().getStr(modules)) + print(offsetStr + "") + + # Create from bytes + @staticmethod + def createFromBytes(bytesArr): + if (bytesArr is None): + raise InternalError() + + if (not issubclass(type(bytesArr), list)): + raise InternalError() + + if (len(bytesArr) < (RuntimeTypeSizes.int + RuntimeTypeSizes.short)): + raise ProfileInconsistencyError() + + index = 0 + + data1 = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int]) + index += RuntimeTypeSizes.int + + data2 = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short]) + index += RuntimeTypeSizes.short + + if (len(bytesArr) != Utility.alignUp(RuntimeTypeSizes.int + RuntimeTypeSizes.short + data2, + RuntimeTypeSizes.int)): + raise ProfileInconsistencyError() + + ptr = bytesArr[index:index+data2] + index += data2 + + if (index != RuntimeTypeSizes.int + RuntimeTypeSizes.short + data2): + raise InternalError() + + recordType, methodFlags, methodHandle = InfoGenericMethod._decodeInfo(data1, data2, ptr) + + if (recordType != RuntimeConstants.MULTICOREJIT_GENERICMETHOD_RECORD_ID): + raise InternalError() + + return InfoGenericMethod.createByRef(methodFlags, methodHandle) + + # Create from objects taking them by reference + @staticmethod + def createByRef(methodFlags, methodHandle): + method = InfoGenericMethod() + + method._methodFlags = methodFlags # pylint: disable=protected-access + method._methodHandle = methodHandle # pylint: disable=protected-access + + method.verify() + return method + + # Create from objects taking them by copy + @staticmethod + def createByCopy(methodFlags, methodHandle): + return InfoGenericMethod.createByRef(methodFlags, methodHandle.copy()) + + # Copy object + def copy(self): + return InfoGenericMethod.createByCopy(self._methodFlags, self._methodHandle) + + # Convert object to list of bytes + def convertToBytes(self): + index = 0 + + bytesArr = [] + + data1, data2, ptr = self._encodeInfo() + + bytesArr += Utility.splitNBytes(data1, RuntimeTypeSizes.int) + index += RuntimeTypeSizes.int + + bytesArr += Utility.splitNBytes(data2, RuntimeTypeSizes.short) + index += RuntimeTypeSizes.short + + bytesArr += ptr + index += len(ptr) + + padding = Utility.alignUp(index, RuntimeTypeSizes.int) - index + bytesArr += [0] * padding + index += padding + + if (index != Utility.alignUp(RuntimeTypeSizes.int + RuntimeTypeSizes.short + data2, + RuntimeTypeSizes.int)): + raise InternalError() + + return bytesArr + +# ---------------------------------------------------------------------------------------------------------------------- +# MultiCoreJit profile +# +# _moduleOrMethodInfo contains records with module deps and methods, both generic and non-generic, +# records' order is the same as in profile +# +# To create from bytes: MCJProfile.createFromBytes(bytes) +# To create from data structures using references: MCJProfile.createByRef(...) +# To create from data structures using copy: MCJProfile.createByCopy(...) +# +class MCJProfile: # pylint: disable=too-many-public-methods + + # Empty constructor, do not use it directly + # Create new objects by createByCopy or createByRef + def __init__(self): + self._header = None + self._modules = None + self._moduleOrMethodInfo = None + + # Equality comparison operator + def __eq__(self, rhs): + if (rhs is None): + return False + if (not issubclass(type(rhs), MCJProfile)): + return False + + if (self._header != rhs._header + or len(self._modules) != len(rhs._modules) + or len(self._moduleOrMethodInfo) != len(rhs._moduleOrMethodInfo)): + return False + + for index, module in enumerate(self._modules): + if (module != rhs._modules[index]): + return False + + for index, info in enumerate(self._moduleOrMethodInfo): + if (info != rhs._moduleOrMethodInfo[index]): + return False + + return True + + # Get header + def getHeader(self): + return self._header + + # Get modules + def getModules(self): + return self._modules + + # Get moduleOrMethodInfo + def getModuleOrMethodInfo(self): + return self._moduleOrMethodInfo + + # Verify consistency + def verify(self): + if (self._header is None or self._modules is None or self._moduleOrMethodInfo is None): + raise InternalError() + + if (not issubclass(type(self._header), HeaderRecord) + or not issubclass(type(self._modules), list) or not issubclass(type(self._moduleOrMethodInfo), list)): + raise InternalError() + + for i in self._modules: + if (i is None): + raise InternalError() + if (not issubclass(type(i), ModuleRecordExtended)): + raise InternalError() + + for i in self._moduleOrMethodInfo: + if (i is None): + raise InternalError() + if (not issubclass(type(i), InfoModuleDependency) + and not issubclass(type(i), InfoNonGenericMethod) + and not issubclass(type(i), InfoGenericMethod)): + raise InternalError() + + if (self._header.getModuleCount() != len(self._modules)): + raise ProfileInconsistencyError() + + if ((self._header.getMethodCount() + self._header.getModuleDepCount()) != len(self._moduleOrMethodInfo)): + raise ProfileInconsistencyError() + + for info in self._moduleOrMethodInfo: + indexes = info.getAllModuleIndexes() + for i in indexes: + if (i >= len(self._modules)): + raise InternalError() + + # Print raw header + def printRawHeader(self, offsetStr=""): + if (offsetStr is None or not issubclass(type(offsetStr), str)): + raise InternalError() + + print(offsetStr + ">>> Raw MCJProfile:") + print(offsetStr + "header = {") + self._header.printRaw(offsetStr + " ") + print(offsetStr + "}") + + # Print raw modules + def printRawModules(self, offsetStr=""): + if (offsetStr is None or not issubclass(type(offsetStr), str)): + raise InternalError() + + print(offsetStr + "modules = [") + for i in self._modules: + print(offsetStr + " " + "{") + i.printRaw(offsetStr + " ") + print(offsetStr + " " + "},") + print(offsetStr + "]") + + # Print raw module dependencies and methods + def printRawModuleOrMethodInfo(self, offsetStr="", printModuleDeps=True, + printGenericMethods=True, printNonGenericMethods=True): + if (offsetStr is None or not issubclass(type(offsetStr), str)): + raise InternalError() + + if (printModuleDeps is None or printGenericMethods is None or printNonGenericMethods is None): + raise InternalError() + + if (not issubclass(type(printModuleDeps), bool) or not issubclass(type(printGenericMethods), bool) + or not issubclass(type(printNonGenericMethods), bool)): + raise InternalError() + + name = "" + if (printModuleDeps and printGenericMethods and printNonGenericMethods): + name = "moduleOrMethodInfo" + else: + if (printModuleDeps): + if (name != ""): + name += ", " + name += "module deps" + if (printGenericMethods): + if (name != ""): + name += ", " + name += "generic methods" + if (printNonGenericMethods): + if (name != ""): + name += ", " + name += "non generic methods" + + print(offsetStr + name + " = [") + for i in self._moduleOrMethodInfo: + doPrint = (i.isModuleInfo() and printModuleDeps) or (i.isGenericMethodInfo() and printGenericMethods) \ + or (i.isNonGenericMethodInfo() and printNonGenericMethods) + + if (doPrint): + print(offsetStr + " " + "{") + i.printRaw(offsetStr + " ") + print(offsetStr + " " + "},") + print(offsetStr + "]") + + # Print raw + def printRaw(self, offsetStr=""): + self.printRawHeader(offsetStr) + self.printRawModules(offsetStr) + self.printRawModuleOrMethodInfo(offsetStr) + + # Print pretty header + def printHeader(self, offsetStr=""): + if (offsetStr is None or not issubclass(type(offsetStr), str)): + raise InternalError() + + self._header.print(offsetStr) + + # Print pretty modules + def printModules(self, offsetStr=""): + if (offsetStr is None or not issubclass(type(offsetStr), str)): + raise InternalError() + + for i in self._modules: + i.print(offsetStr) + + # Print pretty module dependencies and methods + def printModuleOrMethodInfo(self, offsetStr="", printModuleDeps=True, + printGenericMethods=True, printNonGenericMethods=True): + if (offsetStr is None or not issubclass(type(offsetStr), str)): + raise InternalError() + + if (printModuleDeps is None or printGenericMethods is None or printNonGenericMethods is None): + raise InternalError() + + if (not issubclass(type(printModuleDeps), bool) or not issubclass(type(printGenericMethods), bool) + or not issubclass(type(printNonGenericMethods), bool)): + raise InternalError() + + for i in self._moduleOrMethodInfo: + doPrint = (i.isModuleInfo() and printModuleDeps) or (i.isGenericMethodInfo() and printGenericMethods) \ + or (i.isNonGenericMethodInfo() and printNonGenericMethods) + + if (doPrint): + i.print(offsetStr, self._modules) + + # Print pretty + def print(self, offsetStr=""): + self.printHeader(offsetStr) + self.printModules(offsetStr) + self.printModuleOrMethodInfo(offsetStr) + + # Get length and type of record at specified byte + @staticmethod + def _getRecordTypeAndLen(bytesArr, index): + if (bytesArr is None or index is None): + raise InternalError() + + if (not issubclass(type(bytesArr), list) or not issubclass(type(index), int)): + raise InternalError() + + if (index + RuntimeTypeSizes.int > len(bytesArr)): + raise ProfileInconsistencyError() + + data1 = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int]) + rcdTyp = data1 >> RuntimeConstants.RECORD_TYPE_OFFSET + rcdLen = 0 + + if (rcdTyp == RuntimeConstants.MULTICOREJIT_MODULE_RECORD_ID): + rcdLen = data1 & RuntimeConstants.X_MODULE_RECORD_LEN_MASK + elif (rcdTyp == RuntimeConstants.MULTICOREJIT_MODULEDEPENDENCY_RECORD_ID): + rcdLen = RuntimeTypeSizes.int + elif (rcdTyp == RuntimeConstants.MULTICOREJIT_METHOD_RECORD_ID): + rcdLen = 2 * RuntimeTypeSizes.int + elif (rcdTyp == RuntimeConstants.MULTICOREJIT_GENERICMETHOD_RECORD_ID): + if (index + RuntimeTypeSizes.int + RuntimeTypeSizes.short > len(bytesArr)): + raise ProfileInconsistencyError() + + tmpindex = index+RuntimeTypeSizes.int + signatureLength = Utility.mergeNBytes(bytesArr[tmpindex:tmpindex+RuntimeTypeSizes.short]) + dataSize = signatureLength + RuntimeTypeSizes.int + RuntimeTypeSizes.short + dataSize = Utility.alignUp(dataSize, RuntimeTypeSizes.int) + rcdLen = dataSize + else: + raise ProfileInconsistencyError() + + if ((index + rcdLen > len(bytesArr)) or ((rcdLen & 3) != 0)): + raise ProfileInconsistencyError() + + return rcdTyp, rcdLen + + # Create from bytes + @staticmethod + def createFromBytes(bytesArr): + if (bytesArr is None or not issubclass(type(bytesArr), list)): + raise InternalError() + + index = 0 + header = HeaderRecord.createFromBytes(bytesArr[index:index+HeaderRecord.Size]) + index += HeaderRecord.Size + + modules = [] + moduleOrMethodInfo = [] + + while (index <= len(bytesArr) - RuntimeTypeSizes.int): + rcdTyp, rcdLen = MCJProfile._getRecordTypeAndLen(bytesArr, index) + + if (rcdTyp == RuntimeConstants.MULTICOREJIT_MODULE_RECORD_ID): + modules.append(ModuleRecordExtended.createFromBytes(bytesArr[index:index+rcdLen])) + elif (rcdTyp == RuntimeConstants.MULTICOREJIT_MODULEDEPENDENCY_RECORD_ID): + moduleOrMethodInfo.append(InfoModuleDependency.createFromBytes(bytesArr[index:index+rcdLen])) + elif (rcdTyp == RuntimeConstants.MULTICOREJIT_METHOD_RECORD_ID): + moduleOrMethodInfo.append(InfoNonGenericMethod.createFromBytes(bytesArr[index:index+rcdLen])) + elif (rcdTyp == RuntimeConstants.MULTICOREJIT_GENERICMETHOD_RECORD_ID): + moduleOrMethodInfo.append(InfoGenericMethod.createFromBytes(bytesArr[index:index+rcdLen])) + else: + raise InternalError() + + index += rcdLen + + if (index != len(bytesArr)): + raise ProfileInconsistencyError() + + return MCJProfile.createByRef(header, modules, moduleOrMethodInfo) + + # Create from objects taking them by reference + @staticmethod + def createByRef(header, modules, moduleOrMethodInfo): + profile = MCJProfile() + + profile._header = header # pylint: disable=protected-access + profile._modules = modules # pylint: disable=protected-access + profile._moduleOrMethodInfo = moduleOrMethodInfo # pylint: disable=protected-access + + profile.verify() + return profile + + # Create from objects taking them by copy + @staticmethod + def createByCopy(header, modules, moduleOrMethodInfo): + newModules = [] + for i in modules: + newModules.append(i.copy()) + + newModuleOrMethodInfo = [] + for i in moduleOrMethodInfo: + newModuleOrMethodInfo.append(i.copy()) + + return MCJProfile.createByRef(header.copy(), newModules, newModuleOrMethodInfo) + + # Copy object + def copy(self): + return MCJProfile.createByCopy(self._header, self._modules, self._moduleOrMethodInfo) + + # Convert object to list of bytes + def convertToBytes(self): + bytesArr = [] + + bytesArr += self._header.convertToBytes() + + for module in self._modules: + bytesArr += module.convertToBytes() + + for info in self._moduleOrMethodInfo: + bytesArr += info.convertToBytes() + + return bytesArr + + # Split mcj profile in two: app-dependent (app) and app-independent (system) + def split(self, systemModules): # pylint: disable=too-many-locals,too-many-statements,too-many-branches + if (systemModules is None or not issubclass(type(systemModules), list)): + raise InternalError() + + for i in systemModules: + if (i is None): + raise InternalError() + if (not issubclass(type(i), str)): + raise InternalError() + + cIdxApp = 0 + cIdxSys = 1 + + # App header at [0], sys header at [1] + header = [self._header.copy(), self._header.copy()] + # App modules at [0], sys modules at [1] + modules = [[], []] + # App moduleOrMethodInfo at [0], sys moduleOrMethodInfo at [1] + moduleOrMethodInfo = [[], []] + # App methodCount at [0], sys methodCount at [1] + methodCount = [0, 0] + # App moduleDepCount at [0], sys moduleDepCount at [1] + moduleDepCount = [0, 0] + + # Map from old module index to flag, whether module should be added to: + # app profile at [0], system profile at [1] + moduleMap = [[False] * len(self._modules), [False] * len(self._modules)] + # Map from old method info index to flag, whether method info should be added to: + # app profile (True) or to sys profile (False) + methodInfoAppMap = [False] * len(self._moduleOrMethodInfo) + # Map from old module index to new module index in: + # app profile at [0], system profile at [1] + moduleIndexMap = [[None] * len(self._modules), [None] * len(self._modules)] + + # I. ==== Create map of system modules ==== + + # Map from system module name to flag True + systemModulesMap = {} + for sysmodule in systemModules: + systemModulesMap[sysmodule] = True + + # II. ==== Go through all modules and mark system modules ==== + + for index, module in enumerate(self._modules): + moduleMap[cIdxSys][index] = module.getModuleName() in systemModulesMap + + # III. ==== Go through all method infos and create lists of module indexes for system and app profiles + + for index, value in enumerate(moduleMap[cIdxSys]): + moduleMap[cIdxApp][index] = not value + + for index, info in enumerate(self._moduleOrMethodInfo): + if (info.isMethodInfo()): + indexes = info.getAllModuleIndexes() + + for i in indexes: + if (not moduleMap[cIdxSys][i]): + methodInfoAppMap[index] = True + break + + if (methodInfoAppMap[index]): + # mark all modules as requiremens for app profile + for i in indexes: + moduleMap[cIdxApp][i] = True + + # IV. === Go through all modules again and add to profiles accordingly ==== + + for index, module in enumerate(self._modules): + + isAdded = False + + # add to app and system profiles + for i in range(2): + if (moduleMap[i][index]): + newModule = module.copy() + moduleIndexMap[i][index] = len(modules[i]) + modules[i].append(newModule) + isAdded = True + + if (not isAdded): + raise InternalError() + + # V. ==== Go through all infos again and add to profiles accordingly ==== + + for index, info in enumerate(self._moduleOrMethodInfo): + isAdded = False + + # add to app and system profiles + for i in range(2): + doAddModule = info.isModuleInfo() and moduleMap[i][info.getModuleIndex()] + doAddMethodApp = (i == cIdxApp) and methodInfoAppMap[index] + doAddMethodSys = (i == cIdxSys) and not methodInfoAppMap[index] + + doAdd = doAddModule or (info.isMethodInfo() and (doAddMethodApp or doAddMethodSys)) + + if (doAdd): + if (info.isMethodInfo() and isAdded): + raise InternalError() + + newInfo = info.copy() + newInfo.updateModuleIndex(moduleIndexMap[i]) + moduleOrMethodInfo[i].append(newInfo) + + if (info.isModuleInfo()): + moduleDepCount[i] += 1 + elif (info.isMethodInfo()): + methodCount[i] += 1 + else: + raise InternalError() + + isAdded = True + + if (not isAdded): + raise InternalError() + + # VI. ==== Recalculate jitMethodCount ==== + + for index in range(2): + for module in modules[index]: + module.getModuleRecord().setJitMethodCount(0) + + for info in moduleOrMethodInfo[index]: + if (info.isMethodInfo()): + indexes = info.getAllModuleIndexes() + for i in indexes: + moduleRecord = modules[index][i].getModuleRecord() + count = moduleRecord.getJitMethodCount() + moduleRecord.setJitMethodCount(count + 1) + + # VII. ==== Initialize new headers ==== + + for index in range(2): + header[index].setModuleCount(len(modules[index])) + header[index].setMethodCount(methodCount[index]) + header[index].setModuleDepCount(moduleDepCount[index]) + header[index].dropGlobalUsageStats() + + # VIII. ==== Perform some consistency checks ==== + + if (methodCount[0] + methodCount[1] != self._header.getMethodCount()): + raise InternalError() + + # IX. ==== Create new profiles ==== + + mcjProfileApp = MCJProfile.createByRef(header[0], modules[0], moduleOrMethodInfo[0]) + mcjProfileSys = MCJProfile.createByRef(header[1], modules[1], moduleOrMethodInfo[1]) + + return mcjProfileApp, mcjProfileSys + + # Merge new mcj profile with existing one + def merge(self, mcjProfile): # pylint: disable=too-many-locals,too-many-statements + if (mcjProfile is None or not issubclass(type(mcjProfile), MCJProfile)): + raise InternalError() + + # Map from module name in self to module index + moduleNameMap = {} + # Map from str method representation to info index + methodMap = [] + # Map from old module index in mcjProfile to previous max module level in self (if existed, otherwise None) + moduleLoadLevelMap = [None] * len(mcjProfile.getModules()) + # Map from old module index in mcjProfile to new module index in self profile + moduleIndexMap = [None] * len(mcjProfile.getModules()) + + # I. ==== Create map of existing module names ==== + + for index, module in enumerate(self._modules): + moduleNameMap[module.getModuleName()] = index + + # II. ==== Merge modules ==== + + # Merge modules: add new modules if needed, update max load level for existing modules + for index, newmodule in enumerate(mcjProfile.getModules()): + # check if modules match by simple name, because module search is performed by it + existingModuleIndex = moduleNameMap.get(newmodule.getModuleName()) + + if (not existingModuleIndex is None): + # exists, update max load level (if load levels do not match, use max one) + existingModule = self._modules[existingModuleIndex] + + if (existingModule.getAssemblyName() != newmodule.getAssemblyName()): + print("Can't merge profiles: two modules with same names but different assembly names!") + raise UnsupportedError() + if (existingModule.getModuleRecord().getVersion() != newmodule.getModuleRecord().getVersion()): + print("Can't merge profiles: two modules with same names but different versions!") + raise UnsupportedError() + if (existingModule.getModuleRecord().getFlags() != newmodule.getModuleRecord().getFlags()): + print("Can't merge profiles: two modules with same names but different flags!") + raise UnsupportedError() + + existingModuleLoadLevel = existingModule.getModuleRecord().getLoadLevel() + moduleLoadLevelMap[index] = existingModuleLoadLevel + moduleIndexMap[index] = existingModuleIndex + existingModule.getModuleRecord().setLoadLevel(max(newmodule.getModuleRecord().getLoadLevel(), + existingModuleLoadLevel)) + else: + # simple module names do not match, safe to add new module + moduleLoadLevelMap[index] = None + moduleIndexMap[index] = len(self._modules) + newmoduleToAdd = newmodule.copy() + self._modules.append(newmoduleToAdd) + + # III. ==== Fill method map ==== + + for module in self._modules: + methodMap.append({}) + + # Prepare map from method str representation to index of info + for index, info in enumerate(self._moduleOrMethodInfo): + moduleIndex = info.getModuleIndex() + + if (info.isNonGenericMethodInfo()): + methodMap[moduleIndex][str(info.getMethodToken())] = index + elif (info.isGenericMethodInfo()): + methodMap[moduleIndex][info.getMethodHandle().getStr(self._modules)] = index + + # IV. ==== Merge infos ==== + + # Merge module and method info (existing part of self doesn't change, simply add mcjProfile after self) + for newinfo in mcjProfile.getModuleOrMethodInfo(): + if (newinfo.isMethodInfo()): + infoIndex = None + + newModuleIndex = moduleIndexMap[newinfo.getModuleIndex()] + + if (newinfo.isNonGenericMethodInfo()): + infoIndex = methodMap[newModuleIndex].get(str(newinfo.getMethodToken())) + elif (newinfo.isGenericMethodInfo()): + infoIndex = methodMap[newModuleIndex].get(newinfo.getMethodHandle().getStr(mcjProfile.getModules())) + else: + raise InternalError() + + if (infoIndex is None): + newinfoToAdd = newinfo.copy() + newinfoToAdd.updateModuleIndex(moduleIndexMap) + self._moduleOrMethodInfo.append(newinfoToAdd) + else: + if (newinfo.getMethodFlags() != self._moduleOrMethodInfo[infoIndex].getMethodFlags()): + print("Can't merge profiles: two methods with same token/signature but different flags!") + raise UnsupportedError() + else: + oldExistingLoadLevel = moduleLoadLevelMap[newinfo.getModuleIndex()] + + # module dependency + if ((not oldExistingLoadLevel is None) and oldExistingLoadLevel >= newinfo.getModuleLoadLevel()): + # nothing to do, don't add module dependency, already loaded at required level + pass + else: + newinfoToAdd = newinfo.copy() + newinfoToAdd.updateModuleIndex(moduleIndexMap) + self._moduleOrMethodInfo.append(newinfoToAdd) + + # IV. ==== Set stats ==== + + methodCount = 0 + moduleDepCount = 0 + + # Reset method count + for module in self._modules: + module.getModuleRecord().setJitMethodCount(0) + + # Update stats in modules + for info in self._moduleOrMethodInfo: + if (info.isMethodInfo()): + methodCount += 1 + + indexes = info.getAllModuleIndexes() + for i in indexes: + moduleRecord = self._modules[i].getModuleRecord() + count = moduleRecord.getJitMethodCount() + moduleRecord.setJitMethodCount(count + 1) + else: + moduleDepCount += 1 + + # update stats in headers + self._header.setModuleCount(len(self._modules)) + self._header.setMethodCount(methodCount) + self._header.setModuleDepCount(moduleDepCount) + # new profile was not used yet, so drop usage stats + self._header.dropGlobalUsageStats() + + self.verify() + + # Find module by name + def findModuleByName(self, moduleName): + if (moduleName is None or not issubclass(type(moduleName), str)): + raise InternalError() + for module in self._modules: + if (moduleName == module.getModuleName()): + return module + return None + + # Find method by token + def findMethodByToken(self, methodToken): + if (methodToken is None or not issubclass(type(methodToken), int)): + raise InternalError() + for moduleOrMethodInfo in self._moduleOrMethodInfo: + if (moduleOrMethodInfo.isMethodInfo() and moduleOrMethodInfo.getMethodToken() == methodToken): + return moduleOrMethodInfo + return None + + # Read MCJ profile from file + @staticmethod + def readFromFile(inputFile): + file = open(inputFile, "rb") + bytesArr = list(file.read()) + file.close() + + mcjProfile = MCJProfile.createFromBytes(bytesArr) + + return mcjProfile + + # Write MCJ profile to file + @staticmethod + def writeToFile(outputFile, mcjProfile): + file = open(outputFile, "wb") + file.write(bytearray(mcjProfile.convertToBytes())) + file.close() + +# ---------------------------------------------------------------------------------------------------------------------- +class CLI: + + # Constructor with command line arguments + def __init__(self, args): + self._args = args + + # Split mcj profiles in two: app-dependent (app) and app-independent (system) + def commandSplit(self): + systemModulesFile = open(self._args.system_modules_list, "r") + systemModules = systemModulesFile.readlines() + systemModulesFile.close() + + for i, module in enumerate(systemModules): + systemModules[i] = module.rstrip("\n") + + for filepath in self._args.input: + outFilepathApp = filepath + ".app" + outFilepathSys = filepath + ".sys" + + mcjProfile = MCJProfile.readFromFile(filepath) + mcjProfileApp, mcjProfileSys = mcjProfile.split(systemModules) + + MCJProfile.writeToFile(outFilepathApp, mcjProfileApp) + MCJProfile.writeToFile(outFilepathSys, mcjProfileSys) + + print("MCJ profile " + filepath + " was split in:") + print(" 1. app-dependent " + outFilepathApp) + print(" 2. app-independent " + outFilepathSys) + print("") + + # Merge mcj profiles + def commandMerge(self): + mcjProfileBase = MCJProfile.readFromFile(self._args.input[0]) + + for index in range(1, len(self._args.input)): + mcjProfile = MCJProfile.readFromFile(self._args.input[index]) + mcjProfileBase.merge(mcjProfile) + + MCJProfile.writeToFile(self._args.output, mcjProfileBase) + + print("MCJ profiles " + str(self._args.input) + " were merged in: " + self._args.output) + print("") + + # Verify mcj profiles format consistency + def commandVerify(self): + for filepath in self._args.input: + mcjProfile = MCJProfile.readFromFile(filepath) # pylint: disable=unused-variable + print("MCJ profile " + filepath + " is correct!") + + # Find module or method in mcj profile + def commandFind(self): + for filepath in self._args.input: + mcjProfile = MCJProfile.readFromFile(filepath) + + if (not self._args.module is None): + for module in self._args.module: + if (not mcjProfile.findModuleByName(module) is None): + print("MCJ profile " + filepath + " contains module " + module) + else: + print("MCJ profile " + filepath + " does not contain module " + module) + + if (not self._args.method_token is None): + for method in self._args.method_token: + methodToken = int(method) + if (not mcjProfile.findMethodByToken(methodToken) is None): + print("MCJ profile " + filepath + " contains method with token " + method) + else: + print("MCJ profile " + filepath + " does not contain method with token " + method) + + # Compare multiple mcj profiles for equality + def commandCompare(self): + if (self._args.sha256): + resBase = subprocess.run(["sha256sum", self._args.input[0]], check=True, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + shaBase = resBase.stdout.decode("ascii").split(" ")[0] + for index in range(1, len(self._args.input)): + res = subprocess.run(["sha256sum", self._args.input[index]], check=True, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + sha = res.stdout.decode("ascii").split(" ")[0] + resultStr = " are equal by hash." if sha == shaBase else " are not equal by hash." + print("MCJ profiles " + self._args.input[0] + " and " + self._args.input[index] + resultStr) + else: + mcjProfileBase = MCJProfile.readFromFile(self._args.input[0]) + for index in range(1, len(self._args.input)): + mcjProfile = MCJProfile.readFromFile(self._args.input[index]) + resultStr = " are equal." if mcjProfile == mcjProfileBase else " are not equal." + print("MCJ profiles " + self._args.input[0] + " and " + self._args.input[index] + resultStr) + + # Clean usage stats in profile + def commandCleanStats(self): + for filepath in self._args.input: + outfilepath = filepath + ".cleaned" + + mcjProfile = MCJProfile.readFromFile(filepath) + mcjProfile.getHeader().dropGlobalUsageStats() + MCJProfile.writeToFile(outfilepath, mcjProfile) + + print("Cleaned usage stats: " + filepath + " is saved as " + outfilepath) + print("") + + def commandPrint(self): + for filepath in self._args.input: + print("============ MCJ profile " + filepath + " ============") + mcjProfile = MCJProfile.readFromFile(filepath) + + doPrintModuleDeps = self._args.module_deps + doPrintGenericMethods = self._args.methods or self._args.generics + doPrintNonGenericMethods = self._args.methods or self._args.non_generics + doPrintModuleOrMethodInfo = doPrintModuleDeps or doPrintGenericMethods or doPrintNonGenericMethods + + if (self._args.raw): + # Print raw mcj profile + if (self._args.header): + mcjProfile.printRawHeader() + if (self._args.modules): + mcjProfile.printRawModules() + if (doPrintModuleOrMethodInfo): + mcjProfile.printRawModuleOrMethodInfo("", doPrintModuleDeps, doPrintGenericMethods, + doPrintNonGenericMethods) + if (not self._args.header and not self._args.modules and not doPrintModuleOrMethodInfo): + mcjProfile.printRaw() + else: + # Pretty-print mcj profile + if (self._args.header): + mcjProfile.printHeader() + if (self._args.modules): + mcjProfile.printModules() + if (doPrintModuleOrMethodInfo): + mcjProfile.printModuleOrMethodInfo("", doPrintModuleDeps, doPrintGenericMethods, + doPrintNonGenericMethods) + if (not self._args.header and not self._args.modules and not doPrintModuleOrMethodInfo): + mcjProfile.print() + + # Show short summary on mcj profile format + def commandHelp(self): # pylint: disable=no-self-use,too-many-statements + print("! To show command options help use --help option !") + print("") + + if (self._args.mcj_format): + print(">>> MCJ format help.") + print("") + print("MCJ file is a binary file with next sections:") + print("1. Header, i.e. 'HeaderRecord'") + print("2. Modules, i.e. multiple 'ModuleRecord'") + print("3. Methods and Module dependencies, i.e. multiple 'JitInfRecord':") + print(" 'ModuleDependency', 'GenericMethod', 'NonGenericMethod'") + print("") + print("I. Header.") + print("") + print("Header contains:") + print("1. MULTICOREJIT_HEADER_RECORD_ID tag") + print("2. Version of profile, MULTICOREJIT_PROFILE_VERSION") + print("3. Number of used modules, module dependencies and methods") + print("4. Profile usage stats (0 if profile was not written after usage)") + print("") + print("II. Modules.") + print("") + print("These section contains multiple ModuleRecord, each ModuleRecord contains:") + print("1. MULTICOREJIT_MODULE_RECORD_ID tag") + print("2. Module version") + print("3. Number of methods from module in profile") + print("4. Final load level for module") + print("5. Simple name of module") + print("6. Assembly name") + print("") + print("III. Modules and Methods dependencies") + print("") + print("This section contains multiple JitInfRecord, each JitInfRecord can be:") + print(" Module dependency, non-generic Method or generic Method.") + print("") + print("Each Module dependency contains:") + print("1. Module index") + print("2. Current module load level") + print("3. MULTICOREJIT_MODULEDEPENDENCY_RECORD_ID tag") + print("") + print("Each non-generic Method contains:") + print("1. Module index") + print("2. Method flags") + print("3. MULTICOREJIT_METHOD_RECORD_ID tag") + print("4. Method token from dll") + print("") + print("Each generic Method contains:") + print("1. Module index") + print("2. Method flags") + print("3. MULTICOREJIT_GENERICMETHOD_RECORD_ID tag") + print("4. Length of binary signature for method") + print("5. Binary signature for method") + elif (self._args.binary_signature_format): + print(">>> Binary signature format help.") + print("") + print("I. Value encoding") + print("") + print("Binary signature for method (as well as binary signature for type) is a byte array.") + print("") + print("Each value that is stored in this byte array is compacted (see _encodeValue) (except plain bytes):") + print(" - values '<= 0x7f' are stored as 1 byte without changes") + print(" - values '> 0x7f and <= 0x3fff' are stored as 2 bytes in big endian order (1st byte | 0x80)") + print(" - values '> 0x3fff and <= 0x1fffffff' are stored as 4 bytes in big endian order (1st byte | 0xc0)") + print("As a result of this 3 high bits of 1st byte determine length of value:") + print(" - 0yz mean 1 byte") + print(" - 10y mean 2 bytes") + print(" - 110 mean 4 bytes") + print("As mentioned above, sometimes plain bytes are saved (see _encodeByte).") + print("") + print("Tokens (method, type, etc.) are stored as plain values (see above) or tokens (see _encodeToken):") + print(" 1. rid and typ are obtained from token") + print(" 2. rid is shifted left on 2 bits") + print(" 3. rid is ORed with special 2bit constant determined by typ") + print(" 4. resulting modified rid goes through value encoding procedure above") + print("As a result of this typ of token is determined by 2 lowest bits of saved value.") + print("") + print("II. Type signature encoding") + print("") + print("Each type is encoded using logic mentioned in previous section.") + print("") + print("This logic is pretty complex, but main building blocks of all types are:") + print(" - other types") + print(" - type tokens") + print(" - calling convention") + print(" - number of func args") + print(" - number of generic args") + print(" - array rank") + print(" - module index <-- this is module index in array of modules that are processed by MCJ!") + print("For more details see source code (see _encodeSignatureForTypeHandle).") + print("") + print("III. Method signature encoding") + print("") + print("Each method is encoded using logic mentioned in previous section.") + print("") + print("Method encoding order:") + print(" 1. Method flags") + print(" 2. Type from which this method comes from") + print(" 3. Method token") + print(" 4*. Number of method instantion args (for generic methods)") + print(" 5*. Types of all method instantion args (for generic methods)") + print("For more details see source code (see encodeMethod).") + else: + print("! To show format help use --mcj-format or --binary-signature-format options !") + + # Perform various self testing + def commandSelfTest(self): # pylint: disable=too-many-locals,too-many-statements + if (self._args.rw): + # Read mcj profile, write it to file, read it back again and compare + for filepath in self._args.input: + outFilepath = filepath + ".__tmp" + mcjProfileIn = MCJProfile.readFromFile(filepath) + MCJProfile.writeToFile(outFilepath, mcjProfileIn) + mcjProfileOut = MCJProfile.readFromFile(outFilepath) + if (mcjProfileIn == mcjProfileOut): + print("Read-write self test passed for " + filepath) + else: + print("Read-write self test failed for " + filepath) + elif (self._args.rw_sha256): + # Read mcj profile, write it to file, compare with sha256sum with original file + for filepath in self._args.input: + outFilepath = filepath + ".__tmp" + mcjProfile = MCJProfile.readFromFile(filepath) + MCJProfile.writeToFile(outFilepath, mcjProfile) + + inputRes = subprocess.run(["sha256sum", filepath], check=True, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + outputRes = subprocess.run(["sha256sum", outFilepath], check=True, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + inputSha = inputRes.stdout.decode("ascii").split(" ")[0] + outputSha = outputRes.stdout.decode("ascii").split(" ")[0] + + if (inputSha == outputSha): + print("Read-write sha256sum self test passed for " + filepath) + else: + print("Read-write sha256sum self test failed for " + filepath) + elif (self._args.sm): + # Split mcj profile, merge two resulting profiles, split again and compare + systemModulesFile = open(self._args.system_modules_list, "r") + systemModules = systemModulesFile.readlines() + systemModulesFile.close() + + for i, moduleName in enumerate(systemModules): + systemModules[i] = moduleName.rstrip("\n") + + for filepath in self._args.input: + mcjProfile = MCJProfile.readFromFile(filepath) + mcjProfileApp, mcjProfileSys = mcjProfile.split(systemModules) + + prevMergedAppFirst = mcjProfile + prevMergedSysFirst = mcjProfile + prevSplitAppFirstApp = mcjProfileApp + prevSplitAppFirstSys = mcjProfileSys + prevSplitSysFirstApp = mcjProfileApp + prevSplitSysFirstSys = mcjProfileSys + + isCorrect = True + depthCheck = 1 + + # Note: first split&merge won't match because order changes, but it stabilizes on 2nd merge + for depth in range(1,5): + # Merge two prev profiles + mergedAppFirst = prevSplitAppFirstApp.copy() + mergedAppFirst.merge(prevSplitAppFirstSys) + + mergedSysFirst = prevSplitSysFirstSys.copy() + mergedSysFirst.merge(prevSplitSysFirstApp) + + if (depth > depthCheck + and (mergedAppFirst != prevMergedAppFirst or mergedSysFirst != prevMergedSysFirst)): + isCorrect = False + break + + prevMergedAppFirst = mergedAppFirst + prevMergedSysFirst = mergedSysFirst + + mergedAppFirst2 = mergedAppFirst.copy() + mergedAppFirst2.merge(mergedSysFirst) + + mergedSysFirst2 = mergedSysFirst.copy() + mergedSysFirst2.merge(mergedAppFirst) + + if (mergedAppFirst2 != mergedAppFirst or mergedSysFirst2 != mergedSysFirst): + isCorrect = False + break + + # Split cur profiles + splitAppFirstApp, splitAppFirstSys = mergedAppFirst.split(systemModules) + splitSysFirstApp, splitSysFirstSys = mergedSysFirst.split(systemModules) + + if (depth > depthCheck + and (splitAppFirstApp != prevSplitAppFirstApp or splitAppFirstSys != prevSplitAppFirstSys + or splitSysFirstApp != prevSplitSysFirstApp or splitSysFirstSys != prevSplitSysFirstSys)): + isCorrect = False + break + + prevSplitAppFirstApp = splitAppFirstApp + prevSplitAppFirstSys = splitAppFirstSys + prevSplitSysFirstApp = splitSysFirstApp + prevSplitSysFirstSys = splitSysFirstSys + + splitAppFirstApp2, splitAppFirstSys2 = splitAppFirstApp.split(systemModules) + + if (splitAppFirstApp2 != splitAppFirstApp): + isCorrect = False + break + + splitAppFirstApp2, splitAppFirstSys2 = splitAppFirstSys.split(systemModules) + + if (splitAppFirstSys2 != splitAppFirstSys): + isCorrect = False + break + + splitSysFirstApp2, splitSysFirstSys2 = splitSysFirstApp.split(systemModules) + + if (splitSysFirstApp2 != splitSysFirstApp): + isCorrect = False + break + + splitSysFirstApp2, splitSysFirstSys2 = splitSysFirstSys.split(systemModules) + + if (splitSysFirstSys2 != splitSysFirstSys): + isCorrect = False + break + + if (isCorrect): + print("Split-merge self test passed for " + filepath) + else: + print("Split-merge self test failed for " + filepath) + elif (self._args.unit): + # TODO: add unit tests + pass + else: + pass + +# ---------------------------------------------------------------------------------------------------------------------- + +def main(): + parser = argparse.ArgumentParser() + + commands = "split, merge, verify, find, compare, clean-stats, print, help, self-test" + + parser.add_argument("command", help="Command to execute: " + commands) + + # Overall options + parser.add_argument("-i", "--input", help="Input mcj profiles", action="append") + + # Split options + parser.add_argument("--system-modules-list", help="[split], file with app-independent (i.e. system) module names") + + # Merge options + parser.add_argument("-o", "--output", help="[merge], output mcj profile") + + # Find options + parser.add_argument("--module", help="[find], name of module to find in mcj profile", action="append") + parser.add_argument("--method-token", help="[find], token of method to find in mcj profile", action="append") + + # Compare options + parser.add_argument("--sha256", help="[compare], compare mcj profiles using sha256sum", action="store_true") + + # Print options + parser.add_argument("--raw", help="[print], print raw mcj profile", action="store_true") + parser.add_argument("--header", help="[print], print header of mcj profile", action="store_true") + parser.add_argument("--modules", help="[print], print modules in mcj profile", action="store_true") + + parser.add_argument("--methods", help="[print], print methods in mcj profile", action="store_true") + parser.add_argument("--generics", help="[print], print generic methods in mcj profile", action="store_true") + parser.add_argument("--non-generics", help="[print], print non-generic methods in mcj profile", action="store_true") + parser.add_argument("--module-deps", help="[print], print module dependencies in mcj profile", action="store_true") + + # Help options + parser.add_argument("--mcj-format", help="[help], show help on mcj format", action="store_true") + parser.add_argument("--binary-signature-format", help="[help], show help on binary signature format", + action="store_true") + + # Self test option + parser.add_argument("--rw", help="[self-test], perform read-write self-test", action="store_true") + parser.add_argument("--rw-sha256", + help="[self-test], perform read-write self-test using sha256sum", action="store_true") + parser.add_argument("--sm", help="[self-test], perform split-merge self-test", action="store_true") + parser.add_argument("--unit", help="TODO, [self-test], perform unit testing self-test", action="store_true") + + args = parser.parse_args() + + cli = CLI(args) + + if (args.command == "split"): + cli.commandSplit() + elif (args.command == "merge"): + cli.commandMerge() + elif (args.command == "verify"): + cli.commandVerify() + elif (args.command == "find"): + cli.commandFind() + elif (args.command == "compare"): + cli.commandCompare() + elif (args.command == "clean-stats"): + cli.commandCleanStats() + elif (args.command == "print"): + cli.commandPrint() + elif (args.command == "help"): + cli.commandHelp() + elif (args.command == "self-test"): + cli.commandSelfTest() + +if __name__ == "__main__": + main() -- 2.7.4