2 # The MIT License (MIT)
4 # Copyright (c) 2022 Samsung Electronics Co., Ltd.
8 # Permission is hereby granted, free of charge, to any person obtaining a copy
9 # of this software and associated documentation files (the "Software"), to deal
10 # in the Software without restriction, including without limitation the rights
11 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 # copies of the Software, and to permit persons to whom the Software is
13 # furnished to do so, subject to the following conditions:
15 # The above copyright notice and this permission notice shall be included in all
16 # copies or substantial portions of the Software.
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 from abc import ABC, abstractmethod
31 # ----------------------------------------------------------------------------------------------------------------------
32 # Base class for error exceptions
33 class Error(Exception):
37 class MessageError(Error):
38 def __init__(self, message):
40 self.message = message
42 # Error with message about mcj profile inconsistency
43 class ProfileInconsistencyError(MessageError):
45 super().__init__("Inconsistency in mcj format")
47 # Error with message about mcj-edit internal error
48 class InternalError(MessageError):
50 super().__init__("Internal error in mcj-edit")
52 # Error with message about unsupported case in mcj-edit
53 class UnsupportedError(MessageError):
55 super().__init__("Unsupported case in mcj-edit")
57 # ----------------------------------------------------------------------------------------------------------------------
58 # Class with helper functions
61 # Align value to specified alignment
63 def alignUp(value, alignment):
64 if (value is None or alignment is None):
66 if (not issubclass(type(value), int) or not issubclass(type(alignment), int)):
68 if (value < 0 or alignment < 0):
70 return (value + alignment - 1) // alignment * alignment
72 # Merge bytes into a value
74 def mergeNBytes(bytesArr, isLittleEndian=True):
75 if (bytesArr is None or isLittleEndian is None):
77 if (not issubclass(type(bytesArr), list) or not issubclass(type(isLittleEndian), bool)):
82 for index, byte in enumerate(bytesArr):
83 if (not issubclass(type(byte), int)):
85 if (byte < 0 or byte > Utility.getMaxForNBytes(1)):
89 value = value | (byte << index * 8)
91 value = (value << 8) | byte
95 # Split bytes of value
97 def splitNBytes(value, numbytes, isLittleEndian=True):
98 if (value is None or numbytes is None or isLittleEndian is None):
100 if (not issubclass(type(value), int) or not issubclass(type(numbytes), int)
101 or not issubclass(type(isLittleEndian), bool)):
102 raise InternalError()
103 if (value < 0 or numbytes < 0):
104 raise InternalError()
108 for index in range(numbytes): # pylint: disable=unused-variable
110 bytesArr.append(value & 0xff)
112 bytesArr.insert(0, value & 0xff)
116 raise InternalError()
120 # Pack bits: 8 high bits for value1, 24 low bits for value2
122 def pack8_24(value1, value2): # pylint: disable=invalid-name
123 if (value1 is None or value2 is None):
124 raise InternalError()
125 if (not issubclass(type(value1), int) or not issubclass(type(value2), int)):
126 raise InternalError()
127 if (value1 < 0 or value1 > Utility.getMaxForNBytes(1)
128 or value2 < 0 or value2 > Utility.getMaxForNBytes(3)):
129 raise InternalError()
130 return (value1 << 24) | value2
132 # Get max allowed value for unsigned N bits
134 def getMaxForNBits(numBits):
135 if (numBits is None):
136 raise InternalError()
137 if (not issubclass(type(numBits), int)):
138 raise InternalError()
140 raise InternalError()
141 return (1 << numBits) - 1
143 # Get max allowed value for unsigned N bytes
145 def getMaxForNBytes(numBytes):
146 if (numBytes is None):
147 raise InternalError()
148 if (not issubclass(type(numBytes), int)):
149 raise InternalError()
151 raise InternalError()
152 return Utility.getMaxForNBits(numBytes * 8)
154 # ----------------------------------------------------------------------------------------------------------------------
155 # These are some constants from runtime, which should be checked before usage!
157 # - src/coreclr/vm/multicorejitimpl.h
160 # TODO: add function that checks/sets these by parsing file from runtime
161 class RuntimeConstants: # pylint: disable=too-few-public-methods
162 METHOD_FLAGS_MASK = 0xff0000
163 JIT_BY_APP_THREAD_TAG = 0x10000
164 RECORD_TYPE_OFFSET = 24
167 MODULE_LEVEL_OFFSET = 16
168 MAX_MODULE_LEVELS = 0x100
170 #SIGNATURE_LENGTH_MASK = 0xffff
171 HEADER_W_COUNTER = 14
173 #MULTICOREJITLIFE = 60 * 1000
176 MULTICOREJIT_PROFILE_VERSION = 102
177 MULTICOREJIT_HEADER_RECORD_ID = 1
178 MULTICOREJIT_MODULE_RECORD_ID = 2
179 MULTICOREJIT_MODULEDEPENDENCY_RECORD_ID = 3
180 MULTICOREJIT_METHOD_RECORD_ID = 4
181 MULTICOREJIT_GENERICMETHOD_RECORD_ID = 5
183 # Next constant are used directly and have no named variables in runtime
184 X_MODULE_RECORD_LEN_MASK = 0xffffff
186 # ----------------------------------------------------------------------------------------------------------------------
187 # These are sizes of types in bytes
188 class RuntimeTypeSizes: # pylint: disable=too-few-public-methods
193 # ----------------------------------------------------------------------------------------------------------------------
194 # Header of MCJ profile.
196 # Corresponds to "struct HeaderRecord" from multicorejitimpl.h
198 # To create from bytes: HeaderRecord.createFromBytes(bytes)
199 # To create from data structures using references: HeaderRecord.createByRef(...)
200 # To create from data structures using copy: HeaderRecord.createByCopy(...)
202 class HeaderRecord: # pylint: disable=too-many-instance-attributes
203 Alignment = RuntimeTypeSizes.int
205 Size = 6 * RuntimeTypeSizes.int \
206 + Utility.alignUp(RuntimeConstants.HEADER_W_COUNTER * RuntimeTypeSizes.short, Alignment) \
207 + RuntimeConstants.HEADER_D_COUNTER * RuntimeTypeSizes.int
209 # Empty constructor, do not use it directly
210 # Create new objects by createByCopy or createByRef
212 self._recordId = None
214 self._timeStamp = None
215 self._moduleCount = None
216 self._methodCount = None
217 self._moduleDepCount = None
218 self._shortCounters = None
219 self._longCounters = None
221 # Equality comparison operator
222 def __eq__(self, rhs):
225 if (not issubclass(type(rhs), HeaderRecord)):
227 return self._recordId == rhs._recordId and self._version == rhs._version \
228 and self._timeStamp == rhs._timeStamp and self._moduleCount == rhs._moduleCount \
229 and self._methodCount == rhs._methodCount and self._moduleDepCount == rhs._moduleDepCount \
230 and self._shortCounters == rhs._shortCounters and self._longCounters == rhs._longCounters
233 def getModuleCount(self):
234 return self._moduleCount
237 def getMethodCount(self):
238 return self._methodCount
241 def getModuleDepCount(self):
242 return self._moduleDepCount
245 def setModuleCount(self, moduleCount):
246 self._moduleCount = moduleCount
250 def setMethodCount(self, methodCount):
251 self._methodCount = methodCount
255 def setModuleDepCount(self, moduleDepCount):
256 self._moduleDepCount = moduleDepCount
260 def dropGlobalUsageStats(self):
261 self._shortCounters = [0] * RuntimeConstants.HEADER_W_COUNTER
262 self._longCounters = [0] * RuntimeConstants.HEADER_D_COUNTER
267 if (self._recordId is None or self._version is None
268 or self._timeStamp is None or self._moduleCount is None
269 or self._methodCount is None or self._moduleDepCount is None
270 or self._shortCounters is None or self._longCounters is None):
271 raise InternalError()
273 if (not issubclass(type(self._recordId), int) or not issubclass(type(self._version), int)
274 or not issubclass(type(self._timeStamp), int) or not issubclass(type(self._moduleCount), int)
275 or not issubclass(type(self._methodCount), int) or not issubclass(type(self._moduleDepCount), int)
276 or not issubclass(type(self._shortCounters), list) or not issubclass(type(self._longCounters), list)):
277 raise InternalError()
279 if (self._recordId < 0 or self._recordId > Utility.getMaxForNBytes(RuntimeTypeSizes.int)
280 or self._version < 0 or self._version > Utility.getMaxForNBytes(RuntimeTypeSizes.int)
281 or self._timeStamp < 0 or self._timeStamp > Utility.getMaxForNBytes(RuntimeTypeSizes.int)
282 or self._moduleCount < 0 or self._moduleCount > Utility.getMaxForNBytes(RuntimeTypeSizes.int)
283 or self._methodCount < 0 or self._methodCount > Utility.getMaxForNBytes(RuntimeTypeSizes.int)
284 or self._moduleDepCount < 0 or self._moduleDepCount > Utility.getMaxForNBytes(RuntimeTypeSizes.int)
285 or len(self._shortCounters) != RuntimeConstants.HEADER_W_COUNTER
286 or len(self._longCounters) != RuntimeConstants.HEADER_D_COUNTER):
287 raise InternalError()
289 for i in self._shortCounters:
290 if (i < 0 or i > Utility.getMaxForNBytes(RuntimeTypeSizes.short)):
291 raise InternalError()
293 for i in self._longCounters:
294 if (i < 0 or i > Utility.getMaxForNBytes(RuntimeTypeSizes.short)):
295 raise InternalError()
297 if (self._version != RuntimeConstants.MULTICOREJIT_PROFILE_VERSION):
298 raise ProfileInconsistencyError()
300 if (self._moduleCount > RuntimeConstants.MAX_MODULES):
301 raise ProfileInconsistencyError()
303 if (self._methodCount > RuntimeConstants.MAX_METHODS):
304 raise ProfileInconsistencyError()
306 if (self._recordId != Utility.pack8_24(RuntimeConstants.MULTICOREJIT_HEADER_RECORD_ID, HeaderRecord.Size)):
307 raise ProfileInconsistencyError()
310 def printRaw(self, offsetStr=""):
311 if (offsetStr is None or not issubclass(type(offsetStr), str)):
312 raise InternalError()
314 print(offsetStr + ">>> Raw HeaderRecord:")
315 print(offsetStr + "recordId = " + str(self._recordId))
316 print(offsetStr + "version = " + str(self._version))
317 print(offsetStr + "timeStamp = " + str(self._timeStamp))
318 print(offsetStr + "moduleCount = " + str(self._moduleCount))
319 print(offsetStr + "methodCount = " + str(self._methodCount))
320 print(offsetStr + "moduleDepCount = " + str(self._moduleDepCount))
321 print(offsetStr + "shortCounters = " + str(self._shortCounters))
322 print(offsetStr + "longCounters = " + str(self._longCounters))
325 def print(self, offsetStr=""):
326 if (offsetStr is None or not issubclass(type(offsetStr), str)):
327 raise InternalError()
329 print(offsetStr + ">>> MultiCoreJit profile (version: " + str(self._version)
330 + ", time stamp: " + str(self._timeStamp) + ")")
332 print(offsetStr + "Number of used modules: " + str(self._moduleCount))
333 print(offsetStr + "Number of method dependencies: " + str(self._methodCount))
334 print(offsetStr + "Number of module dependencies: " + str(self._moduleDepCount))
336 print(offsetStr + ">>> Stats for played profile (these are 0 if profile was not played):")
338 print(offsetStr + "Total number of methods: "
339 + str(self._shortCounters[0]))
340 print(offsetStr + "Number of methods, which had native code (i.e. no jit in mcj thread for them): "
341 + str(self._shortCounters[1]))
342 print(offsetStr + "Number of methods, which were tried to be jitted in mcj thread: "
343 + str(self._shortCounters[2]))
344 print(offsetStr + "Number of methods, which were successfully jitted in mcj thread: "
345 + str(self._shortCounters[3]))
346 print(offsetStr + "Number of methods, jit code for which was used after jit in mcj thread: "
347 + str(self._shortCounters[4]))
348 print(offsetStr + "Number of methods, which were skipped for some reason: "
349 + str(self._shortCounters[5]))
350 print(offsetStr + "Number of methods, which were skipped because of missing module: "
351 + str(self._shortCounters[6]))
352 print(offsetStr + "Number of methods, which were traversed backwards: "
353 + str(self._shortCounters[9]))
358 def createFromBytes(bytesArr):
359 if (bytesArr is None or not issubclass(type(bytesArr), list)):
360 raise InternalError()
362 if (len(bytesArr) != HeaderRecord.Size):
363 raise ProfileInconsistencyError()
367 recordId = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int])
368 index += RuntimeTypeSizes.int
370 version = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int])
371 index += RuntimeTypeSizes.int
373 timeStamp = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int])
374 index += RuntimeTypeSizes.int
376 moduleCount = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int])
377 index += RuntimeTypeSizes.int
379 methodCount = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int])
380 index += RuntimeTypeSizes.int
382 moduleDepCount = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int])
383 index += RuntimeTypeSizes.int
386 for i in range(0, RuntimeConstants.HEADER_W_COUNTER): # pylint: disable=unused-variable
387 shortCounters.append(Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short]))
388 index += RuntimeTypeSizes.short
390 index = Utility.alignUp(index, HeaderRecord.Alignment)
393 for i in range(0, RuntimeConstants.HEADER_D_COUNTER): # pylint: disable=unused-variable
394 longCounters.append(Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int]))
395 index += RuntimeTypeSizes.int
397 return HeaderRecord.createByRef(recordId, version, timeStamp, moduleCount, methodCount,
398 moduleDepCount, shortCounters, longCounters)
400 # Create from objects taking them by reference
402 def createByRef(recordId, version, timeStamp, moduleCount, methodCount,
403 moduleDepCount, shortCounters, longCounters):
404 header = HeaderRecord()
406 header._recordId = recordId # pylint: disable=protected-access
407 header._version = version # pylint: disable=protected-access
408 header._timeStamp = timeStamp # pylint: disable=protected-access
409 header._moduleCount = moduleCount # pylint: disable=protected-access
410 header._methodCount = methodCount # pylint: disable=protected-access
411 header._moduleDepCount = moduleDepCount # pylint: disable=protected-access
412 header._shortCounters = shortCounters # pylint: disable=protected-access
413 header._longCounters = longCounters # pylint: disable=protected-access
418 # Create from objects taking them by copy
420 def createByCopy(recordId, version, timeStamp, moduleCount, methodCount,
421 moduleDepCount, shortCounters, longCounters):
422 return HeaderRecord.createByRef(recordId, version, timeStamp, moduleCount, methodCount,
423 moduleDepCount, shortCounters.copy(), longCounters.copy())
427 return HeaderRecord.createByCopy(self._recordId, self._version, self._timeStamp,
428 self._moduleCount, self._methodCount, self._moduleDepCount,
429 self._shortCounters, self._longCounters)
431 # Convert object to list of bytes
432 def convertToBytes(self):
437 bytesArr += Utility.splitNBytes(self._recordId, RuntimeTypeSizes.int)
438 index += RuntimeTypeSizes.int
440 bytesArr += Utility.splitNBytes(self._version, RuntimeTypeSizes.int)
441 index += RuntimeTypeSizes.int
443 bytesArr += Utility.splitNBytes(self._timeStamp, RuntimeTypeSizes.int)
444 index += RuntimeTypeSizes.int
446 bytesArr += Utility.splitNBytes(self._moduleCount, RuntimeTypeSizes.int)
447 index += RuntimeTypeSizes.int
449 bytesArr += Utility.splitNBytes(self._methodCount, RuntimeTypeSizes.int)
450 index += RuntimeTypeSizes.int
452 bytesArr += Utility.splitNBytes(self._moduleDepCount, RuntimeTypeSizes.int)
453 index += RuntimeTypeSizes.int
455 for i in self._shortCounters:
456 bytesArr += Utility.splitNBytes(i, RuntimeTypeSizes.short)
457 index += RuntimeTypeSizes.short
459 padding = Utility.alignUp(index, HeaderRecord.Alignment) - index
460 bytesArr += [0] * padding
463 for i in self._longCounters:
464 bytesArr += Utility.splitNBytes(i, RuntimeTypeSizes.int)
465 index += RuntimeTypeSizes.int
467 if (index != HeaderRecord.Size):
468 raise InternalError()
472 # ----------------------------------------------------------------------------------------------------------------------
475 # Corresponds to "GUID" from pal_mstypes.h
477 # To create from bytes: GUID.createFromBytes(bytes)
478 # To create from data structures using references: GUID.createByRef(...)
479 # To create from data structures using copy: GUID.createByCopy(...)
482 Alignment = RuntimeTypeSizes.int
484 Size = RuntimeTypeSizes.int + 2 * RuntimeTypeSizes.short + 8 * RuntimeTypeSizes.char
486 # Empty constructor, do not use it directly
487 # Create new objects by createByCopy or createByRef
494 # Equality comparison operator
495 def __eq__(self, rhs):
498 if (not issubclass(type(rhs), GUID)):
500 return self._data1 == rhs._data1 and self._data2 == rhs._data2 \
501 and self._data3 == rhs._data3 and self._data4 == rhs._data4
505 if (self._data1 is None or self._data2 is None or self._data3 is None or self._data4 is None):
506 raise InternalError()
508 if (not issubclass(type(self._data1), int) or not issubclass(type(self._data2), int)
509 or not issubclass(type(self._data3), int) or not issubclass(type(self._data4), list)):
510 raise InternalError()
512 if (self._data1 < 0 or self._data1 > Utility.getMaxForNBytes(RuntimeTypeSizes.int)
513 or self._data2 < 0 or self._data2 > Utility.getMaxForNBytes(RuntimeTypeSizes.short)
514 or self._data3 < 0 or self._data3 > Utility.getMaxForNBytes(RuntimeTypeSizes.short)
515 or len(self._data4) != 8):
516 raise InternalError()
518 for i in self._data4:
519 if (i < 0 or i > Utility.getMaxForNBytes(RuntimeTypeSizes.char)):
520 raise InternalError()
523 def printRaw(self, offsetStr=""):
524 if (offsetStr is None or not issubclass(type(offsetStr), str)):
525 raise InternalError()
527 print(offsetStr + ">>> Raw GUID:")
528 print(offsetStr + "data1 = " + str(self._data1))
529 print(offsetStr + "data2 = " + str(self._data2))
530 print(offsetStr + "data3 = " + str(self._data3))
531 print(offsetStr + "data4 = " + str(self._data4))
534 def print(self, offsetStr=""):
535 if (offsetStr is None or not issubclass(type(offsetStr), str)):
536 raise InternalError()
538 print(offsetStr + "GUID: " + str(self._data1)
539 + "," + str(self._data2)
540 + "," + str(self._data3)
541 + "," + str(self._data4))
542 print(offsetStr + "")
546 def createFromBytes(bytesArr):
547 if (bytesArr is None or not issubclass(type(bytesArr), list)):
548 raise InternalError()
550 if (len(bytesArr) != GUID.Size):
551 raise ProfileInconsistencyError()
555 data1 = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int])
556 index += RuntimeTypeSizes.int
558 data2 = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short])
559 index += RuntimeTypeSizes.short
561 data3 = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short])
562 index += RuntimeTypeSizes.short
565 for i in range(0, 8):
566 data4[i] = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.char])
567 index += RuntimeTypeSizes.char
569 return GUID.createByRef(data1, data2, data3, data4)
571 # Create from objects taking them by reference
573 def createByRef(data1, data2, data3, data4):
576 guid._data1 = data1 # pylint: disable=protected-access
577 guid._data2 = data2 # pylint: disable=protected-access
578 guid._data3 = data3 # pylint: disable=protected-access
579 guid._data4 = data4 # pylint: disable=protected-access
584 # Create from objects taking them by copy
586 def createByCopy(data1, data2, data3, data4):
587 return GUID.createByRef(data1, data2, data3, data4.copy())
591 return GUID.createByCopy(self._data1, self._data2, self._data3, self._data4)
593 # Convert object to list of bytes
594 def convertToBytes(self):
599 bytesArr += Utility.splitNBytes(self._data1, RuntimeTypeSizes.int)
600 index += RuntimeTypeSizes.int
602 bytesArr += Utility.splitNBytes(self._data2, RuntimeTypeSizes.short)
603 index += RuntimeTypeSizes.short
605 bytesArr += Utility.splitNBytes(self._data3, RuntimeTypeSizes.short)
606 index += RuntimeTypeSizes.short
608 for i in self._data4:
609 bytesArr += Utility.splitNBytes(i, RuntimeTypeSizes.char)
610 index += RuntimeTypeSizes.char
612 if (index != GUID.Size):
613 raise InternalError()
617 # ----------------------------------------------------------------------------------------------------------------------
620 # Corresponds to "class ModuleVersion" from multicorejitimpl.h
622 # To create from bytes: ModuleVersion.createFromBytes(bytes)
623 # To create from data structures using references: ModuleVersion.createByRef(...)
624 # To create from data structures using copy: ModuleVersion.createByCopy(...)
627 Alignment = RuntimeTypeSizes.int
629 Size = 4 * RuntimeTypeSizes.short + RuntimeTypeSizes.int + GUID.Size
631 # Empty constructor, do not use it directly
632 # Create new objects by createByCopy or createByRef
637 self._revision = None
638 self._versionFlags = None
639 self._hasNativeImage = None
642 # Equality comparison operator
643 def __eq__(self, rhs):
646 if (not issubclass(type(rhs), ModuleVersion)):
648 return self._major == rhs._major and self._minor == rhs._minor and self._build == rhs._build \
649 and self._revision == rhs._revision and self._versionFlags == rhs._versionFlags \
650 and self._hasNativeImage == rhs._hasNativeImage and self._mvid == rhs._mvid
654 if (self._major is None or self._minor is None or self._build is None or self._revision is None
655 or self._versionFlags is None or self._hasNativeImage is None or self._mvid is None):
656 raise InternalError()
658 if (not issubclass(type(self._major), int) or not issubclass(type(self._minor), int)
659 or not issubclass(type(self._build), int) or not issubclass(type(self._revision), int)
660 or not issubclass(type(self._versionFlags), int) or not issubclass(type(self._hasNativeImage), int)
661 or not issubclass(type(self._mvid), GUID)):
662 raise InternalError()
664 if (self._major < 0 or self._major > Utility.getMaxForNBytes(RuntimeTypeSizes.short)
665 or self._minor < 0 or self._minor > Utility.getMaxForNBytes(RuntimeTypeSizes.short)
666 or self._build < 0 or self._build > Utility.getMaxForNBytes(RuntimeTypeSizes.short)
667 or self._revision < 0 or self._revision > Utility.getMaxForNBytes(RuntimeTypeSizes.short)
668 or self._versionFlags < 0 or self._versionFlags > Utility.getMaxForNBits(RuntimeTypeSizes.int * 8 - 1)
669 or self._hasNativeImage < 0 or self._hasNativeImage > Utility.getMaxForNBits(1)):
670 raise InternalError()
673 def printRaw(self, offsetStr=""):
674 if (offsetStr is None or not issubclass(type(offsetStr), str)):
675 raise InternalError()
677 print(offsetStr + ">>> Raw ModuleVersion:")
678 print(offsetStr + "major = " + str(self._major))
679 print(offsetStr + "minor = " + str(self._minor))
680 print(offsetStr + "build = " + str(self._build))
681 print(offsetStr + "revision = " + str(self._revision))
682 print(offsetStr + "versionFlags = " + str(self._versionFlags))
683 print(offsetStr + "hasNativeImage = " + str(self._hasNativeImage))
684 print(offsetStr + "mvid = {")
685 self._mvid.printRaw(offsetStr + " ")
686 print(offsetStr + "}")
689 def print(self, offsetStr=""):
690 if (offsetStr is None or not issubclass(type(offsetStr), str)):
691 raise InternalError()
693 print(offsetStr + "ModuleVersion: " + str(self._major)
694 + "." + str(self._minor)
695 + "." + str(self._build)
696 + "." + str(self._revision)
697 + ", " + str(self._versionFlags)
698 + ", " + str(self._hasNativeImage))
699 self._mvid.print(offsetStr)
703 def createFromBytes(bytesArr):
704 if (bytesArr is None or not issubclass(type(bytesArr), list)):
705 raise InternalError()
707 if (len(bytesArr) != ModuleVersion.Size):
708 raise ProfileInconsistencyError()
712 major = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short])
713 index += RuntimeTypeSizes.short
715 minor = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short])
716 index += RuntimeTypeSizes.short
718 build = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short])
719 index += RuntimeTypeSizes.short
721 revision = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short])
722 index += RuntimeTypeSizes.short
724 versionFlags = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int])
725 hasNativeImage = versionFlags & 0x01
726 versionFlags = versionFlags & 0xfffffffe
727 index += RuntimeTypeSizes.int
729 mvid = GUID.createFromBytes(bytesArr[index:index+GUID.Size])
732 return ModuleVersion.createByRef(major, minor, build, revision, versionFlags, hasNativeImage, mvid)
734 # Create from objects taking them by reference
736 def createByRef(major, minor, build, revision, versionFlags, hasNativeImage, mvid):
737 moduleVersion = ModuleVersion()
739 moduleVersion._major = major # pylint: disable=protected-access
740 moduleVersion._minor = minor # pylint: disable=protected-access
741 moduleVersion._build = build # pylint: disable=protected-access
742 moduleVersion._revision = revision # pylint: disable=protected-access
743 moduleVersion._versionFlags = versionFlags # pylint: disable=protected-access
744 moduleVersion._hasNativeImage = hasNativeImage # pylint: disable=protected-access
745 moduleVersion._mvid = mvid # pylint: disable=protected-access
747 moduleVersion.verify()
750 # Create from objects taking them by copy
752 def createByCopy(major, minor, build, revision, versionFlags, hasNativeImage, mvid):
753 return ModuleVersion.createByRef(major, minor, build, revision, versionFlags, hasNativeImage, mvid.copy())
757 return ModuleVersion.createByCopy(self._major, self._minor, self._build, self._revision,
758 self._versionFlags, self._hasNativeImage, self._mvid)
760 # Convert object to list of bytes
761 def convertToBytes(self):
766 bytesArr += Utility.splitNBytes(self._major, RuntimeTypeSizes.short)
767 index += RuntimeTypeSizes.short
769 bytesArr += Utility.splitNBytes(self._minor, RuntimeTypeSizes.short)
770 index += RuntimeTypeSizes.short
772 bytesArr += Utility.splitNBytes(self._build, RuntimeTypeSizes.short)
773 index += RuntimeTypeSizes.short
775 bytesArr += Utility.splitNBytes(self._revision, RuntimeTypeSizes.short)
776 index += RuntimeTypeSizes.short
778 versionFlags = self._versionFlags | self._hasNativeImage
779 bytesArr += Utility.splitNBytes(versionFlags, RuntimeTypeSizes.int)
780 index += RuntimeTypeSizes.int
782 bytesArr += self._mvid.convertToBytes()
785 if (index != ModuleVersion.Size):
786 raise InternalError()
790 # ----------------------------------------------------------------------------------------------------------------------
791 # Record with information about used module.
793 # Corresponds to "struct ModuleRecord" from multicorejitimpl.h
794 # ModuleRecord in runtime implicitly "contains" module name and assembly name strings after itself,
795 # here they are a part of ModuleRecordExtended.
797 # To create from bytes: ModuleRecord.createFromBytes(bytes)
798 # To create from data structures using references: ModuleRecord.createByRef(...)
799 # To create from data structures using copy: ModuleRecord.createByCopy(...)
801 class ModuleRecord: # pylint: disable=too-many-public-methods
802 Alignment = RuntimeTypeSizes.int
804 Size = RuntimeTypeSizes.int + ModuleVersion.Size + Utility.alignUp(5 * RuntimeTypeSizes.short, Alignment)
806 # Empty constructor, do not use it directly
807 # Create new objects by createByCopy or createByRef
809 self._recordId = None
811 self._jitMethodCount = None
813 self._wLoadLevel = None
814 self._lenModuleName = None
815 self._lenAssemblyName = None
817 # Equality comparison operator
818 def __eq__(self, rhs):
821 if (not issubclass(type(rhs), ModuleRecord)):
823 return self._recordId == rhs._recordId and self._version == rhs._version \
824 and self._jitMethodCount == rhs._jitMethodCount and self._flags == rhs._flags \
825 and self._wLoadLevel == rhs._wLoadLevel and self._lenModuleName == rhs._lenModuleName \
826 and self._lenAssemblyName == rhs._lenAssemblyName
829 def getRecordId(self):
830 return self._recordId
833 def getVersion(self):
837 def getJitMethodCount(self):
838 return self._jitMethodCount
845 def getLoadLevel(self):
846 return self._wLoadLevel
849 def getLenModuleName(self):
850 return self._lenModuleName
852 # Get lenAssemblyName
853 def getLenAssemblyName(self):
854 return self._lenAssemblyName
857 def setJitMethodCount(self, count):
858 self._jitMethodCount = count
862 def setLoadLevel(self, level):
863 self._wLoadLevel = level
868 if (self._recordId is None or self._version is None or self._jitMethodCount is None or self._flags is None
869 or self._wLoadLevel is None or self._lenModuleName is None or self._lenAssemblyName is None):
870 raise InternalError()
872 if (not issubclass(type(self._recordId), int) or not issubclass(type(self._version), ModuleVersion)
873 or not issubclass(type(self._jitMethodCount), int) or not issubclass(type(self._flags), int)
874 or not issubclass(type(self._wLoadLevel), int) or not issubclass(type(self._lenModuleName), int)
875 or not issubclass(type(self._lenAssemblyName), int)):
876 raise InternalError()
878 if (self._recordId < 0 or self._recordId > Utility.getMaxForNBytes(RuntimeTypeSizes.int)
879 or self._jitMethodCount < 0 or self._jitMethodCount > Utility.getMaxForNBytes(RuntimeTypeSizes.short)
880 or self._flags < 0 or self._flags > Utility.getMaxForNBytes(RuntimeTypeSizes.short)
881 or self._wLoadLevel < 0 or self._wLoadLevel > Utility.getMaxForNBytes(RuntimeTypeSizes.short)
882 or self._lenModuleName < 0 or self._lenModuleName > Utility.getMaxForNBytes(RuntimeTypeSizes.short)
883 or self._lenAssemblyName < 0 or self._lenAssemblyName > Utility.getMaxForNBytes(RuntimeTypeSizes.short)):
884 raise InternalError()
887 def printRaw(self, offsetStr=""):
888 if (offsetStr is None or not issubclass(type(offsetStr), str)):
889 raise InternalError()
891 print(offsetStr + ">>> Raw ModuleRecord:")
892 print(offsetStr + "recordId = " + str(self._recordId))
893 print(offsetStr + "version = {")
894 self._version.printRaw(offsetStr + " ")
895 print(offsetStr + "}")
896 print(offsetStr + "jitMethodCount = " + str(self._jitMethodCount))
897 print(offsetStr + "flags = " + str(self._flags))
898 print(offsetStr + "wLoadLevel = " + str(self._wLoadLevel))
899 print(offsetStr + "lenModuleName = " + str(self._lenModuleName))
900 print(offsetStr + "lenAssemblyName = " + str(self._lenAssemblyName))
903 def print(self, offsetStr=""):
904 if (offsetStr is None or not issubclass(type(offsetStr), str)):
905 raise InternalError()
907 self._version.print(offsetStr)
908 print(offsetStr + "Number of used methods from module: " + str(self._jitMethodCount))
909 print(offsetStr + "Final load level for module: " + str(self._wLoadLevel))
913 def createFromBytes(bytesArr):
914 if (bytesArr is None or not issubclass(type(bytesArr), list)):
915 raise InternalError()
917 if (len(bytesArr) != ModuleRecord.Size):
918 raise ProfileInconsistencyError()
922 recordId = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int])
923 index += RuntimeTypeSizes.int
925 version = ModuleVersion.createFromBytes(bytesArr[index:index+ModuleVersion.Size])
926 index += ModuleVersion.Size
928 jitMethodCount = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short])
929 index += RuntimeTypeSizes.short
931 flags = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short])
932 index += RuntimeTypeSizes.short
934 wLoadLevel = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short])
935 index += RuntimeTypeSizes.short
937 lenModuleName = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short])
938 index += RuntimeTypeSizes.short
940 lenAssemblyName = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short])
941 index += RuntimeTypeSizes.short
943 return ModuleRecord.createByRef(recordId, version, jitMethodCount, flags, wLoadLevel,
944 lenModuleName, lenAssemblyName)
946 # Create from objects taking them by reference
948 def createByRef(recordId, version, jitMethodCount, flags, wLoadLevel, lenModuleName, lenAssemblyName):
949 moduleRecord = ModuleRecord()
951 moduleRecord._recordId = recordId # pylint: disable=protected-access
952 moduleRecord._version = version # pylint: disable=protected-access
953 moduleRecord._jitMethodCount = jitMethodCount # pylint: disable=protected-access
954 moduleRecord._flags = flags # pylint: disable=protected-access
955 moduleRecord._wLoadLevel = wLoadLevel # pylint: disable=protected-access
956 moduleRecord._lenModuleName = lenModuleName # pylint: disable=protected-access
957 moduleRecord._lenAssemblyName = lenAssemblyName # pylint: disable=protected-access
959 moduleRecord.verify()
962 # Create from objects taking them by copy
964 def createByCopy(recordId, version, jitMethodCount, flags, wLoadLevel, lenModuleName, lenAssemblyName):
965 return ModuleRecord.createByRef(recordId, version.copy(), jitMethodCount, flags, wLoadLevel,
966 lenModuleName, lenAssemblyName)
970 return ModuleRecord.createByCopy(self._recordId, self._version, self._jitMethodCount,
971 self._flags, self._wLoadLevel,
972 self._lenModuleName, self._lenAssemblyName)
974 # Convert object to list of bytes
975 def convertToBytes(self):
980 bytesArr += Utility.splitNBytes(self._recordId, RuntimeTypeSizes.int)
981 index += RuntimeTypeSizes.int
983 bytesArr += self._version.convertToBytes()
984 index += ModuleVersion.Size
986 bytesArr += Utility.splitNBytes(self._jitMethodCount, RuntimeTypeSizes.short)
987 index += RuntimeTypeSizes.short
989 bytesArr += Utility.splitNBytes(self._flags, RuntimeTypeSizes.short)
990 index += RuntimeTypeSizes.short
992 bytesArr += Utility.splitNBytes(self._wLoadLevel, RuntimeTypeSizes.short)
993 index += RuntimeTypeSizes.short
995 bytesArr += Utility.splitNBytes(self._lenModuleName, RuntimeTypeSizes.short)
996 index += RuntimeTypeSizes.short
998 bytesArr += Utility.splitNBytes(self._lenAssemblyName, RuntimeTypeSizes.short)
999 index += RuntimeTypeSizes.short
1001 padding = Utility.alignUp(index, HeaderRecord.Alignment) - index
1002 bytesArr += [0] * padding
1005 if (index != ModuleRecord.Size):
1006 raise InternalError()
1010 # ----------------------------------------------------------------------------------------------------------------------
1011 # Record with information about used module.
1013 # This is ModuleRecord combined with actual module/assembly name strings.
1015 # To create from bytes: ModuleRecordExtended.createFromBytes(bytes)
1016 # To create from data structures using references: ModuleRecordExtended.createByRef(...)
1017 # To create from data structures using copy: ModuleRecordExtended.createByCopy(...)
1019 class ModuleRecordExtended:
1021 # Empty constructor, do not use it directly
1022 # Create new objects by createByCopy or createByRef
1024 self._moduleRecord = None
1025 self._moduleName = None
1026 self._assemblyName = None
1028 # Equality comparison operator
1029 def __eq__(self, rhs):
1032 if (not issubclass(type(rhs), ModuleRecordExtended)):
1035 return self._moduleRecord == rhs._moduleRecord and \
1036 self._moduleName == rhs._moduleName and self._assemblyName == rhs._assemblyName
1039 def getModuleRecord(self):
1040 return self._moduleRecord
1043 def getModuleName(self):
1044 return self._moduleName
1047 def getAssemblyName(self):
1048 return self._assemblyName
1050 # Verify consistency
1052 if (self._moduleRecord is None or self._moduleName is None or self._assemblyName is None):
1053 raise InternalError()
1055 if (not issubclass(type(self._moduleRecord), ModuleRecord)
1056 or not issubclass(type(self._moduleName), str)
1057 or not issubclass(type(self._assemblyName), str)):
1058 raise InternalError()
1060 if (len(self._moduleName) != self._moduleRecord.getLenModuleName()
1061 or len(self._assemblyName) != self._moduleRecord.getLenAssemblyName()):
1062 raise InternalError()
1065 def printRaw(self, offsetStr=""):
1066 if (offsetStr is None or not issubclass(type(offsetStr), str)):
1067 raise InternalError()
1069 print(offsetStr + "moduleRecord = {")
1070 self._moduleRecord.printRaw(offsetStr + " ")
1071 print(offsetStr + "}")
1072 print(offsetStr + "moduleName = " + self._moduleName)
1073 print(offsetStr + "assemblyName = " + self._assemblyName)
1076 def print(self, offsetStr=""):
1077 if (offsetStr is None or not issubclass(type(offsetStr), str)):
1078 raise InternalError()
1080 print(offsetStr + ">>> Module: " + self._moduleName + "; Assembly: " + self._assemblyName)
1081 print(offsetStr + "")
1082 self._moduleRecord.print(offsetStr)
1083 print(offsetStr + "")
1087 def createFromBytes(bytesArr):
1088 if (bytesArr is None or not issubclass(type(bytesArr), list)):
1089 raise InternalError()
1091 if (len(bytesArr) < ModuleRecord.Size):
1092 raise ProfileInconsistencyError()
1096 moduleRecord = ModuleRecord.createFromBytes(bytesArr[index:index+ModuleRecord.Size])
1097 index += ModuleRecord.Size
1099 lenModuleName = moduleRecord.getLenModuleName()
1100 lenModuleNameAligned = Utility.alignUp(lenModuleName, RuntimeTypeSizes.int)
1102 lenAssemblyName = moduleRecord.getLenAssemblyName()
1103 lenAssemblyNameAligned = Utility.alignUp(lenAssemblyName, RuntimeTypeSizes.int)
1105 if (len(bytesArr) != (ModuleRecord.Size + lenModuleNameAligned + lenAssemblyNameAligned)):
1106 raise ProfileInconsistencyError()
1109 for i in bytesArr[index:index+lenModuleName]:
1110 moduleName += chr(i)
1111 index += lenModuleNameAligned
1114 for i in bytesArr[index:index+lenAssemblyName]:
1115 assemblyName += chr(i)
1116 index += lenAssemblyNameAligned
1118 if (index != (ModuleRecord.Size + lenModuleNameAligned + lenAssemblyNameAligned)):
1119 raise InternalError()
1121 return ModuleRecordExtended.createByRef(moduleRecord, moduleName, assemblyName)
1123 # Create from objects taking them by reference
1125 def createByRef(moduleRecord, moduleName, assemblyName):
1126 moduleRecordExtended = ModuleRecordExtended()
1128 moduleRecordExtended._moduleRecord = moduleRecord # pylint: disable=protected-access
1129 moduleRecordExtended._moduleName = moduleName # pylint: disable=protected-access
1130 moduleRecordExtended._assemblyName = assemblyName # pylint: disable=protected-access
1132 moduleRecordExtended.verify()
1133 return moduleRecordExtended
1135 # Create from objects taking them by copy
1137 def createByCopy(moduleRecord, moduleName, assemblyName):
1138 return ModuleRecordExtended.createByRef(moduleRecord.copy(), moduleName, assemblyName)
1142 return ModuleRecordExtended.createByCopy(self._moduleRecord, self._moduleName, self._assemblyName)
1144 # Convert object to list of bytes
1145 def convertToBytes(self):
1150 bytesArr += self._moduleRecord.convertToBytes()
1151 index += ModuleRecord.Size
1153 lenModuleName = self._moduleRecord.getLenModuleName()
1154 lenModuleNameAligned = Utility.alignUp(lenModuleName, RuntimeTypeSizes.int)
1155 bytesArr += list(bytearray(self._moduleName, "ascii"))
1156 index += lenModuleName
1158 padding = lenModuleNameAligned - lenModuleName
1159 bytesArr += [0] * padding
1162 lenAssemblyName = self._moduleRecord.getLenAssemblyName()
1163 lenAssemblyNameAligned = Utility.alignUp(lenAssemblyName, RuntimeTypeSizes.int)
1164 bytesArr += list(bytearray(self._assemblyName, "ascii"))
1165 index += lenAssemblyName
1167 padding = lenAssemblyNameAligned - lenAssemblyName
1168 bytesArr += [0] * padding
1171 if (index != (ModuleRecord.Size + lenModuleNameAligned + lenAssemblyNameAligned)):
1172 raise InternalError()
1176 # ----------------------------------------------------------------------------------------------------------------------
1177 # Detailed info on types
1179 # Semantically corresponds to CorTypeInfo
1185 # Semantically corresponds to CorElementType
1186 # TODO: verify these constants somehow, see above
1187 class CorElementType: # pylint: disable=too-few-public-methods
1189 ELEMENT_TYPE_END = 0x00
1190 ELEMENT_TYPE_VOID = 0x01
1191 ELEMENT_TYPE_BOOLEAN = 0x02
1192 ELEMENT_TYPE_CHAR = 0x03
1193 ELEMENT_TYPE_I1 = 0x04
1194 ELEMENT_TYPE_U1 = 0x05
1195 ELEMENT_TYPE_I2 = 0x06
1196 ELEMENT_TYPE_U2 = 0x07
1197 ELEMENT_TYPE_I4 = 0x08
1198 ELEMENT_TYPE_U4 = 0x09
1199 ELEMENT_TYPE_I8 = 0x0a
1200 ELEMENT_TYPE_U8 = 0x0b
1201 ELEMENT_TYPE_R4 = 0x0c
1202 ELEMENT_TYPE_R8 = 0x0d
1203 ELEMENT_TYPE_STRING = 0x0e
1205 ELEMENT_TYPE_PTR = 0x0f
1206 ELEMENT_TYPE_BYREF = 0x10
1208 ELEMENT_TYPE_VALUETYPE = 0x11
1209 ELEMENT_TYPE_CLASS = 0x12
1210 ELEMENT_TYPE_VAR = 0x13
1211 ELEMENT_TYPE_ARRAY = 0x14
1212 ELEMENT_TYPE_GENERICINST = 0x15
1213 ELEMENT_TYPE_TYPEDBYREF = 0x16
1214 ELEMENT_TYPE_VALUEARRAY_UNSUPPORTED = 0x17
1215 ELEMENT_TYPE_I = 0x18
1216 ELEMENT_TYPE_U = 0x19
1217 ELEMENT_TYPE_R_UNSUPPORTED = 0x1a
1218 ELEMENT_TYPE_FNPTR = 0x1b
1219 ELEMENT_TYPE_OBJECT = 0x1c
1220 ELEMENT_TYPE_SZARRAY = 0x1d
1221 ELEMENT_TYPE_MVAR = 0x1e
1223 ELEMENT_TYPE_CMOD_REQD = 0x1f
1224 ELEMENT_TYPE_CMOD_OPT = 0x20
1226 ELEMENT_TYPE_INTERNAL = 0x21
1228 ELEMENT_TYPE_MAX = 0x22
1230 ELEMENT_TYPE_VAR_ZAPSIG = 0x3b
1231 ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG = 0x3d
1232 ELEMENT_TYPE_CANON_ZAPSIG = 0x3e
1233 ELEMENT_TYPE_MODULE_ZAPSIG = 0x3f
1235 ELEMENT_TYPE_MODIFIER = 0x40
1236 ELEMENT_TYPE_SENTINEL = 0x01 | ELEMENT_TYPE_MODIFIER
1237 ELEMENT_TYPE_PINNED = 0x05 | ELEMENT_TYPE_MODIFIER
1239 # This constant is not defined in runtime
1240 X_ELEMENT_TYPE_LAST = ELEMENT_TYPE_PINNED + 1
1242 # Entry in map of types info
1245 # Default constructor
1246 def __init__(self, elementKind, name, isPrim):
1247 self._elementKind = elementKind
1249 self._isPrim = isPrim
1251 # Get kind of record
1253 return self._elementKind
1255 # Get name of record
1259 # Get flag whether type is primitive
1260 def getIsPrim(self):
1263 # Fill map with types info
1266 tmpmap = [None] * CorTypeInfo.CorElementType.X_ELEMENT_TYPE_LAST
1267 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_END] = \
1268 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_END, "ELEMENT_TYPE_END", False)
1269 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_VOID] = \
1270 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_VOID, "void", True)
1271 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_BOOLEAN] = \
1272 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_BOOLEAN, "bool", True)
1273 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_CHAR] = \
1274 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_CHAR, "char", True)
1275 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_I1] = \
1276 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_I1, "i1", True)
1277 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_U1] = \
1278 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_U1, "u1", True)
1279 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_I2] = \
1280 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_I2, "i2", True)
1281 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_U2] = \
1282 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_U2, "u2", True)
1283 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_I4] = \
1284 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_I4, "i4", True)
1285 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_U4] = \
1286 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_U4, "u4", True)
1287 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_I8] = \
1288 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_I8, "i8", True)
1289 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_U8] = \
1290 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_U8, "u8", True)
1291 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_R4] = \
1292 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_R4, "r4", True)
1293 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_R8] = \
1294 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_R8, "r8", True)
1295 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_STRING] = \
1296 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_STRING, "string", False)
1297 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_PTR] = \
1298 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_PTR, "ptr", False)
1299 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_BYREF] = \
1300 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_BYREF, "byref", False)
1301 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_VALUETYPE] = \
1302 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_VALUETYPE, "valuetype", False)
1303 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_CLASS] = \
1304 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_CLASS, "class", False)
1305 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_VAR] = \
1306 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_VAR, "var", False)
1307 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_ARRAY] = \
1308 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_ARRAY, "array", False)
1309 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_GENERICINST] = \
1310 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_GENERICINST, "generic", False)
1311 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_TYPEDBYREF] = \
1312 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_TYPEDBYREF, "typedbyref", False)
1313 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_VALUEARRAY_UNSUPPORTED] = \
1314 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_VALUEARRAY_UNSUPPORTED,
1315 "valuearray_unsupported", False)
1316 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_I] = \
1317 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_I, "i", True)
1318 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_U] = \
1319 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_U, "u", True)
1320 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_R_UNSUPPORTED] = \
1321 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_R_UNSUPPORTED, "r_unsupported", False)
1322 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_FNPTR] = \
1323 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_FNPTR, "fnptr", False)
1324 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_OBJECT] = \
1325 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_OBJECT, "object", False)
1326 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_SZARRAY] = \
1327 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_SZARRAY, "szarray", False)
1328 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_MVAR] = \
1329 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_MVAR, "mvar", False)
1330 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_CMOD_REQD] = \
1331 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_CMOD_REQD, "cmod_reqd", False)
1332 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_CMOD_OPT] = \
1333 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_CMOD_OPT, "cmod_opt", False)
1334 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_INTERNAL] = \
1335 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_INTERNAL, "internal", False)
1336 #tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_MAX] = \
1337 # CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_MAX, "ELEMENT_TYPE_MAX", False)
1338 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_VAR_ZAPSIG] = \
1339 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_VAR_ZAPSIG, "vap_zapsig", False)
1340 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG] = \
1341 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG,
1342 "native_valuetype_zapsig", False)
1343 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_CANON_ZAPSIG] = \
1344 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_CANON_ZAPSIG, "canon_zapsig", False)
1345 tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_MODULE_ZAPSIG] = \
1346 CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_MODULE_ZAPSIG, "module_zapsig", False)
1347 #tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_MODIFIER] = \
1348 # CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_MODIFIER, "ELEMENT_TYPE_MODIFIER", False)
1349 #tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_SENTINEL] = \
1350 # CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_SENTINEL, "ELEMENT_TYPE_SENTINEL", False)
1351 #tmpmap[CorTypeInfo.CorElementType.ELEMENT_TYPE_PINNED] = \
1352 # CorTypeInfo.Entry(CorTypeInfo.CorElementType.ELEMENT_TYPE_PINNED, "ELEMENT_TYPE_PINNED", False)
1354 # verify generated map
1355 for index, record in enumerate(tmpmap):
1356 if (not record is None and record.getKind() != index):
1357 raise InternalError()
1361 # Map with types info, is filled explicitly below.
1362 # Records that are absent from CorTypeInfo.CorElementType are None.
1363 # Use getTypeMapEntry to access typemap.
1368 def getTypeMapEntry(elementKind):
1369 if (elementKind is None or not issubclass(type(elementKind), int)):
1370 raise InternalError()
1371 record = CorTypeInfo.typemap[elementKind] # pylint: disable=unsubscriptable-object
1372 if (record is None):
1373 raise InternalError()
1374 if (record.getKind() != elementKind):
1375 raise InternalError()
1378 # Fill map of types info
1379 CorTypeInfo.typemap = CorTypeInfo.fillMap()
1381 # ----------------------------------------------------------------------------------------------------------------------
1382 # These are different kinds of types corresponding to CorTypeInfo.CorElementType
1384 # Base class for all types
1389 def getElementKind(self):
1392 # Get string representation of type
1394 def getStr(self, modules=None):
1397 # Update all module indexes according to map old_index->new_index
1399 def updateModuleIndex(self, moduleIndexMap):
1402 # Get all module indexes used in related types
1404 def getAllModuleIndexes(self):
1413 # Corresponding to simple types that are fully described by their CorElementType
1415 # To create from data structures using references: TypeSimple.createByRef(...)
1416 # To create from data structures using copy: TypeSimple.createByCopy(...)
1418 class TypeSimple(IType):
1420 # Empty constructor, do not use it directly
1421 # Create new objects by createByCopy or createByRef
1423 self._elementKind = None
1425 # Equality comparison operator
1426 def __eq__(self, rhs):
1429 if (not issubclass(type(rhs), TypeSimple)):
1431 return self._elementKind == rhs._elementKind
1434 def getStr(self, modules=None):
1435 if (not modules is None):
1436 if (not issubclass(type(modules), list)):
1437 raise InternalError()
1439 if (i is None or not issubclass(type(i), ModuleRecordExtended)):
1440 raise InternalError()
1442 return CorTypeInfo.getTypeMapEntry(self._elementKind).getName()
1445 def getElementKind(self):
1446 return self._elementKind
1448 # Get all module indexes used in related types
1449 def getAllModuleIndexes(self):
1452 # Update all module indexes according to map old_index->new_index
1453 def updateModuleIndex(self, moduleIndexMap):
1454 if (moduleIndexMap is None or not issubclass(type(moduleIndexMap), list)):
1455 raise InternalError()
1458 # Verify consistency
1460 if (self._elementKind is None):
1461 raise InternalError()
1463 if (not issubclass(type(self._elementKind), int)):
1464 raise InternalError()
1466 if (self._elementKind < 0 or self._elementKind >= CorTypeInfo.CorElementType.X_ELEMENT_TYPE_LAST):
1467 raise InternalError()
1469 # Create from objects taking them by reference
1471 def createByRef(elementKind):
1472 handle = TypeSimple()
1474 handle._elementKind = elementKind # pylint: disable=protected-access
1479 # Create from objects taking them by copy
1481 def createByCopy(elementKind):
1482 return TypeSimple.createByRef(elementKind)
1486 return TypeSimple.createByCopy(self._elementKind)
1489 # Corresponding to types that are fully described by their CorElementType, module index and type token
1491 # To create from data structures using references: TypeToken.createByRef(...)
1492 # To create from data structures using copy: TypeToken.createByCopy(...)
1494 class TypeToken(IType):
1496 # Empty constructor, do not use it directly
1497 # Create new objects by createByCopy or createByRef
1499 self._elementKind = None
1500 self._moduleIndex = None
1501 self._typeToken = None
1503 # Equality comparison operator
1504 def __eq__(self, rhs):
1507 if (not issubclass(type(rhs), TypeToken)):
1509 return self._elementKind == rhs._elementKind and self._moduleIndex == rhs._moduleIndex \
1510 and self._typeToken == rhs._typeToken
1513 def getStr(self, modules=None):
1514 if (not modules is None):
1515 if (not issubclass(type(modules), list)):
1516 raise InternalError()
1518 if (i is None or not issubclass(type(i), ModuleRecordExtended)):
1519 raise InternalError()
1521 moduleStr = str(self._moduleIndex)
1522 if (not modules is None):
1523 moduleStr = modules[self._moduleIndex].getModuleName()
1525 return CorTypeInfo.getTypeMapEntry(self._elementKind).getName() + "{" + str(self._typeToken) \
1526 + ":" + moduleStr + "}"
1529 def getElementKind(self):
1530 return self._elementKind
1533 def getModuleIndex(self):
1534 return self._moduleIndex
1537 def getTypeToken(self):
1538 return self._typeToken
1540 # Get all module indexes used in related types
1541 def getAllModuleIndexes(self):
1542 return [self._moduleIndex]
1544 # Update all module indexes according to map old_index->new_index
1545 def updateModuleIndex(self, moduleIndexMap):
1546 if (moduleIndexMap is None or not issubclass(type(moduleIndexMap), list)):
1547 raise InternalError()
1548 self._moduleIndex = moduleIndexMap[self._moduleIndex]
1551 # Verify consistency
1553 if (self._elementKind is None or self._moduleIndex is None or self._typeToken is None):
1554 raise InternalError()
1556 if (not issubclass(type(self._elementKind), int) or not issubclass(type(self._moduleIndex), int)
1557 or not issubclass(type(self._typeToken), int)):
1558 raise InternalError()
1560 if (self._elementKind < 0 or self._elementKind >= CorTypeInfo.CorElementType.X_ELEMENT_TYPE_LAST):
1561 raise InternalError()
1563 if (self._moduleIndex < 0 or self._moduleIndex >= RuntimeConstants.MAX_MODULES):
1564 raise InternalError()
1566 if (self._typeToken < 0 or self._typeToken > Utility.getMaxForNBytes(RuntimeTypeSizes.int)):
1567 raise InternalError()
1569 # Create from objects taking them by reference
1571 def createByRef(elementKind, moduleIndex, typeToken):
1572 handle = TypeToken()
1574 handle._elementKind = elementKind # pylint: disable=protected-access
1575 handle._moduleIndex = moduleIndex # pylint: disable=protected-access
1576 handle._typeToken = typeToken # pylint: disable=protected-access
1581 # Create from objects taking them by copy
1583 def createByCopy(elementKind, moduleIndex, typeToken):
1584 return TypeToken.createByRef(elementKind, moduleIndex, typeToken)
1588 return TypeToken.createByCopy(self._elementKind, self._moduleIndex, self._typeToken)
1591 # Corresponding to simple types with param type
1593 # To create from data structures using references: TypeParamType.createByRef(...)
1594 # To create from data structures using copy: TypeParamType.createByCopy(...)
1596 class TypeParamType(IType):
1598 # Empty constructor, do not use it directly
1599 # Create new objects by createByCopy or createByRef
1601 self._elementKind = None
1602 self._paramType = None
1604 # Equality comparison operator
1605 def __eq__(self, rhs):
1608 if (not issubclass(type(rhs), TypeParamType)):
1610 return self._elementKind == rhs._elementKind and self._paramType == rhs._paramType
1613 def getStr(self, modules=None):
1614 if (not modules is None):
1615 if (not issubclass(type(modules), list)):
1616 raise InternalError()
1618 if (i is None or not issubclass(type(i), ModuleRecordExtended)):
1619 raise InternalError()
1621 return CorTypeInfo.getTypeMapEntry(self._elementKind).getName() + "{" + self._paramType.getStr(modules) + "}"
1624 def getElementKind(self):
1625 return self._elementKind
1628 def getParamType(self):
1629 return self._paramType
1631 # Get all module indexes used in related types
1632 def getAllModuleIndexes(self):
1633 return self._paramType.getAllModuleIndexes()
1635 # Update all module indexes according to map old_index->new_index
1636 def updateModuleIndex(self, moduleIndexMap):
1637 if (moduleIndexMap is None or not issubclass(type(moduleIndexMap), list)):
1638 raise InternalError()
1639 self._paramType.updateModuleIndex(moduleIndexMap)
1642 # Verify consistency
1644 if (self._elementKind is None or self._paramType is None):
1645 raise InternalError()
1647 if (not issubclass(type(self._elementKind), int) or not issubclass(type(self._paramType), IType)):
1648 raise InternalError()
1650 if (self._elementKind < 0 or self._elementKind >= CorTypeInfo.CorElementType.X_ELEMENT_TYPE_LAST):
1651 raise InternalError()
1653 # Create from objects taking them by reference
1655 def createByRef(elementKind, paramType):
1656 handle = TypeParamType()
1658 handle._elementKind = elementKind # pylint: disable=protected-access
1659 handle._paramType = paramType # pylint: disable=protected-access
1664 # Create from objects taking them by copy
1666 def createByCopy(elementKind, paramType):
1667 return TypeParamType.createByRef(elementKind, paramType.copy())
1671 return TypeParamType.createByCopy(self._elementKind, self._paramType)
1674 # Corresponding to array type
1676 # To create from data structures using references: TypeArray.createByRef(...)
1677 # To create from data structures using copy: TypeArray.createByCopy(...)
1679 class TypeArray(IType):
1681 # Empty constructor, do not use it directly
1682 # Create new objects by createByCopy or createByRef
1684 self._elementKind = None
1685 self._arrayElementType = None
1688 # Equality comparison operator
1689 def __eq__(self, rhs):
1692 if (not issubclass(type(rhs), TypeArray)):
1694 return self._elementKind == rhs._elementKind and self._arrayElementType == rhs._arrayElementType \
1695 and self._rank == rhs._rank
1698 def getStr(self, modules=None):
1699 if (not modules is None):
1700 if (not issubclass(type(modules), list)):
1701 raise InternalError()
1703 if (i is None or not issubclass(type(i), ModuleRecordExtended)):
1704 raise InternalError()
1706 return CorTypeInfo.getTypeMapEntry(self._elementKind).getName() + "{[" \
1707 + self._arrayElementType.getStr(modules) + " ]" + str(self._rank) + "}"
1710 def getElementKind(self):
1711 return self._elementKind
1713 # Get arrayElementType
1714 def getArrayElementType(self):
1715 return self._arrayElementType
1721 # Get all module indexes used in related types
1722 def getAllModuleIndexes(self):
1723 return self._arrayElementType.getAllModuleIndexes()
1725 # Update all module indexes according to map old_index->new_index
1726 def updateModuleIndex(self, moduleIndexMap):
1727 if (moduleIndexMap is None or not issubclass(type(moduleIndexMap), list)):
1728 raise InternalError()
1729 self._arrayElementType.updateModuleIndex(moduleIndexMap)
1732 # Verify consistency
1734 if (self._elementKind is None or self._arrayElementType is None or self._rank is None):
1735 raise InternalError()
1737 if (not issubclass(type(self._elementKind), int) or not issubclass(type(self._arrayElementType), IType)
1738 or not issubclass(type(self._rank), int)):
1739 raise InternalError()
1741 if (self._elementKind < 0 or self._elementKind >= CorTypeInfo.CorElementType.X_ELEMENT_TYPE_LAST):
1742 raise InternalError()
1744 if (self._rank < 0 or self._rank > Utility.getMaxForNBytes(RuntimeTypeSizes.char)):
1745 raise InternalError()
1747 # Create from objects taking them by reference
1749 def createByRef(elementKind, arrayElementType, rank):
1750 handle = TypeArray()
1752 handle._elementKind = elementKind # pylint: disable=protected-access
1753 handle._arrayElementType = arrayElementType # pylint: disable=protected-access
1754 handle._rank = rank # pylint: disable=protected-access
1759 # Create from objects taking them by copy
1761 def createByCopy(elementKind, arrayElementType, rank):
1762 return TypeArray.createByRef(elementKind, arrayElementType.copy(), rank)
1766 return TypeArray.createByCopy(self._elementKind, self._arrayElementType, self._rank)
1769 # Corresponding to szarray type
1771 # To create from data structures using references: TypeSZArray.createByRef(...)
1772 # To create from data structures using copy: TypeSZArray.createByCopy(...)
1774 class TypeSZArray(IType):
1776 # Empty constructor, do not use it directly
1777 # Create new objects by createByCopy or createByRef
1779 self._elementKind = None
1780 self._arrayElementType = None
1782 # Equality comparison operator
1783 def __eq__(self, rhs):
1786 if (not issubclass(type(rhs), TypeSZArray)):
1788 return self._elementKind == rhs._elementKind and self._arrayElementType == rhs._arrayElementType
1791 def getStr(self, modules=None):
1792 if (not modules is None):
1793 if (not issubclass(type(modules), list)):
1794 raise InternalError()
1796 if (i is None or not issubclass(type(i), ModuleRecordExtended)):
1797 raise InternalError()
1799 return CorTypeInfo.getTypeMapEntry(self._elementKind).getName() + "{[" \
1800 + self._arrayElementType.getStr(modules) + "]}"
1803 def getElementKind(self):
1804 return self._elementKind
1806 # Get arrayElementType
1807 def getArrayElementType(self):
1808 return self._arrayElementType
1810 # Get all module indexes used in related types
1811 def getAllModuleIndexes(self):
1812 return self._arrayElementType.getAllModuleIndexes()
1814 # Update all module indexes according to map old_index->new_index
1815 def updateModuleIndex(self, moduleIndexMap):
1816 if (moduleIndexMap is None or not issubclass(type(moduleIndexMap), list)):
1817 raise InternalError()
1818 self._arrayElementType.updateModuleIndex(moduleIndexMap)
1821 # Verify consistency
1823 if (self._elementKind is None or self._arrayElementType is None):
1824 raise InternalError()
1826 if (not issubclass(type(self._elementKind), int) or not issubclass(type(self._arrayElementType), IType)):
1827 raise InternalError()
1829 if (self._elementKind < 0 or self._elementKind >= CorTypeInfo.CorElementType.X_ELEMENT_TYPE_LAST):
1830 raise InternalError()
1832 # Create from objects taking them by reference
1834 def createByRef(elementKind, arrayElementType):
1835 handle = TypeSZArray()
1837 handle._elementKind = elementKind # pylint: disable=protected-access
1838 handle._arrayElementType = arrayElementType # pylint: disable=protected-access
1843 # Create from objects taking them by copy
1845 def createByCopy(elementKind, arrayElementType):
1846 return TypeSZArray.createByRef(elementKind, arrayElementType.copy())
1850 return TypeSZArray.createByCopy(self._elementKind, self._arrayElementType)
1853 # Corresponding to generic type
1855 # To create from data structures using references: TypeGeneric.createByRef(...)
1856 # To create from data structures using copy: TypeGeneric.createByCopy(...)
1858 class TypeGeneric(IType):
1860 # Empty constructor, do not use it directly
1861 # Create new objects by createByCopy or createByRef
1863 self._elementKind = None
1864 self._genericBaseType = None
1865 self._instArgs = None
1867 # Equality comparison operator
1868 def __eq__(self, rhs):
1871 if (not issubclass(type(rhs), TypeGeneric)):
1873 return self._elementKind == rhs._elementKind and self._genericBaseType == rhs._genericBaseType \
1874 and self._instArgs == rhs._instArgs
1877 def getStr(self, modules=None):
1878 if (not modules is None):
1879 if (not issubclass(type(modules), list)):
1880 raise InternalError()
1882 if (i is None or not issubclass(type(i), ModuleRecordExtended)):
1883 raise InternalError()
1885 output = CorTypeInfo.getTypeMapEntry(self._elementKind).getName() + "{" \
1886 + self._genericBaseType.getStr(modules) + "<"
1888 for index in range(len(self._instArgs)):
1889 output += self._instArgs[index].getStr(modules)
1890 if (index != (len(self._instArgs) - 1)):
1897 def getElementKind(self):
1898 return self._elementKind
1900 # Get genericBaseType
1901 def getGenericBaseType(self):
1902 return self._genericBaseType
1905 def getInstArgs(self):
1906 return self._instArgs
1908 # Get all module indexes used in related types
1909 def getAllModuleIndexes(self):
1910 indexes = self._genericBaseType.getAllModuleIndexes()
1911 for i in self._instArgs:
1912 indexes += i.getAllModuleIndexes()
1913 return sorted(set(indexes))
1915 # Update all module indexes according to map old_index->new_index
1916 def updateModuleIndex(self, moduleIndexMap):
1917 if (moduleIndexMap is None or not issubclass(type(moduleIndexMap), list)):
1918 raise InternalError()
1919 self._genericBaseType.updateModuleIndex(moduleIndexMap)
1920 for i in self._instArgs:
1921 i.updateModuleIndex(moduleIndexMap)
1924 # Verify consistency
1926 if (self._elementKind is None or self._genericBaseType is None or self._instArgs is None):
1927 raise InternalError()
1929 if (not issubclass(type(self._elementKind), int) or not issubclass(type(self._genericBaseType), TypeToken)
1930 or not issubclass(type(self._instArgs), list)):
1931 raise InternalError()
1933 if (self._elementKind < 0 or self._elementKind >= CorTypeInfo.CorElementType.X_ELEMENT_TYPE_LAST):
1934 raise InternalError()
1936 for i in self._instArgs:
1937 if (not issubclass(type(i), IType)):
1938 raise InternalError()
1940 # Create from objects taking them by reference
1942 def createByRef(elementKind, genericBaseType, instArgs):
1943 handle = TypeGeneric()
1945 handle._elementKind = elementKind # pylint: disable=protected-access
1946 handle._genericBaseType = genericBaseType # pylint: disable=protected-access
1947 handle._instArgs = instArgs # pylint: disable=protected-access
1952 # Create from objects taking them by copy
1954 def createByCopy(elementKind, genericBaseType, instArgs):
1957 copiedArgs.append(i.copy())
1959 return TypeGeneric.createByRef(elementKind, genericBaseType.copy(), copiedArgs)
1963 return TypeGeneric.createByCopy(self._elementKind, self._genericBaseType, self._instArgs)
1966 # Corresponding to fnptr type
1968 # To create from data structures using references: TypeFNPtr.createByRef(...)
1969 # To create from data structures using copy: TypeFNPtr.createByCopy(...)
1971 class TypeFNPtr(IType):
1973 # Empty constructor, do not use it directly
1974 # Create new objects by createByCopy or createByRef
1976 self._elementKind = None
1977 self._callConv = None
1978 self._retAndArgs = None
1980 # Equality comparison operator
1981 def __eq__(self, rhs):
1984 if (not issubclass(type(rhs), TypeFNPtr)):
1986 return self._elementKind == rhs._elementKind and self._callConv == rhs._callConv \
1987 and self._retAndArgs == rhs._retAndArgs
1990 def getStr(self, modules=None):
1991 if (not modules is None):
1992 if (not issubclass(type(modules), list)):
1993 raise InternalError()
1995 if (i is None or not issubclass(type(i), ModuleRecordExtended)):
1996 raise InternalError()
1998 output = CorTypeInfo.getTypeMapEntry(self._elementKind).getName() + "{" + str(self._callConv) + "("
2000 for index in range(len(self._retAndArgs)):
2001 output += self._retAndArgs[index].getStr(modules)
2002 if (index != (len(self._retAndArgs) - 1)):
2009 def getElementKind(self):
2010 return self._elementKind
2013 def getCallConv(self):
2014 return self._callConv
2017 def getRetAndArgs(self):
2018 return self._retAndArgs
2020 # Get all module indexes used in related types
2021 def getAllModuleIndexes(self):
2023 for i in self._retAndArgs:
2024 indexes += i.getAllModuleIndexes()
2025 return sorted(set(indexes))
2027 # Update all module indexes according to map old_index->new_index
2028 def updateModuleIndex(self, moduleIndexMap):
2029 if (moduleIndexMap is None or not issubclass(type(moduleIndexMap), list)):
2030 raise InternalError()
2031 for i in self._retAndArgs:
2032 i.updateModuleIndex(moduleIndexMap)
2035 # Verify consistency
2037 if (self._elementKind is None or self._callConv is None or self._retAndArgs is None):
2038 raise InternalError()
2040 if (not issubclass(type(self._elementKind), int) or not issubclass(type(self._callConv), int)
2041 or not issubclass(type(self._retAndArgs), list)):
2042 raise InternalError()
2044 if (self._elementKind < 0 or self._elementKind >= CorTypeInfo.CorElementType.X_ELEMENT_TYPE_LAST):
2045 raise InternalError()
2047 if (self._callConv < 0 or self._callConv > Utility.getMaxForNBytes(RuntimeTypeSizes.char)):
2048 raise InternalError()
2050 for i in self._retAndArgs:
2051 if (not issubclass(type(i), IType)):
2052 raise InternalError()
2054 # Create from objects taking them by reference
2056 def createByRef(elementKind, callConv, retAndArgs):
2057 handle = TypeFNPtr()
2059 handle._elementKind = elementKind # pylint: disable=protected-access
2060 handle._callConv = callConv # pylint: disable=protected-access
2061 handle._retAndArgs = retAndArgs # pylint: disable=protected-access
2066 # Create from objects taking them by copy
2068 def createByCopy(elementKind, callConv, retAndArgs):
2069 copiedRetAndArgs = []
2070 for i in retAndArgs:
2071 copiedRetAndArgs.append(i.copy())
2073 return TypeFNPtr.createByRef(elementKind, callConv, copiedRetAndArgs)
2077 return TypeFNPtr.createByCopy(self._elementKind, self._callConv, self._retAndArgs)
2080 # Corresponding to generic method
2082 # To create from data structures using references: GenericMethod.createByRef(...)
2083 # To create from data structures using copy: GenericMethod.createByCopy(...)
2085 class GenericMethod:
2087 # Empty constructor, do not use it directly
2088 # Create new objects by createByCopy or createByRef
2090 self._methodFlags = None
2091 self._moduleIndex = None
2092 self._typeHandle = None
2093 self._methodToken = None
2094 self._methodInstArgs = None
2096 # Equality comparison operator
2097 def __eq__(self, rhs):
2100 if (not issubclass(type(rhs), GenericMethod)):
2102 return self._methodFlags == rhs._methodFlags and self._moduleIndex == rhs._moduleIndex \
2103 and self._typeHandle == rhs._typeHandle and self._methodToken == rhs._methodToken \
2104 and self._methodInstArgs == rhs._methodInstArgs
2107 def getStr(self, modules=None):
2108 if (not modules is None):
2109 if (not issubclass(type(modules), list)):
2110 raise InternalError()
2112 if (i is None or not issubclass(type(i), ModuleRecordExtended)):
2113 raise InternalError()
2115 moduleStr = str(self._moduleIndex)
2116 if (not modules is None):
2117 moduleStr = modules[self._moduleIndex].getModuleName()
2119 output = "method{token{" + str(self._methodToken) + ":" + moduleStr + "}"
2121 if (not self._methodInstArgs is None):
2123 for index in range(len(self._methodInstArgs)):
2124 output += self._methodInstArgs[index].getStr(modules)
2125 if (index != (len(self._methodInstArgs) - 1)):
2129 output += "@type{" + self._typeHandle.getStr(modules) + "}}"
2133 def getMethodFlags(self):
2134 return self._methodFlags
2137 def getModuleIndex(self):
2138 return self._moduleIndex
2141 def getTypeHandle(self):
2142 return self._typeHandle
2145 def getMethodToken(self):
2146 return self._methodToken
2148 # Get methodInstArgs
2149 def getMethodInstArgs(self):
2150 return self._methodInstArgs
2152 # Get all module indexes used in related types
2153 def getAllModuleIndexes(self):
2154 indexes = [self._moduleIndex]
2155 indexes += self._typeHandle.getAllModuleIndexes()
2156 if (not self._methodInstArgs is None):
2157 for i in self._methodInstArgs:
2158 indexes += i.getAllModuleIndexes()
2159 return sorted(set(indexes))
2161 # Update all module indexes according to map old_index->new_index
2162 def updateModuleIndex(self, moduleIndexMap):
2163 if (moduleIndexMap is None or not issubclass(type(moduleIndexMap), list)):
2164 raise InternalError()
2166 self._moduleIndex = moduleIndexMap[self._moduleIndex]
2167 self._typeHandle.updateModuleIndex(moduleIndexMap)
2169 if (not self._methodInstArgs is None):
2170 for i in self._methodInstArgs:
2171 i.updateModuleIndex(moduleIndexMap)
2175 # Verify consistency
2177 if (self._methodFlags is None or self._moduleIndex is None or self._typeHandle is None
2178 or self._methodToken is None):
2179 raise InternalError()
2181 if (not issubclass(type(self._methodFlags), int) or not issubclass(type(self._moduleIndex), int)
2182 or not issubclass(type(self._typeHandle), IType) or not issubclass(type(self._methodToken), int)):
2183 raise InternalError()
2185 if (self._methodFlags < 0 or self._methodFlags > Utility.getMaxForNBytes(RuntimeTypeSizes.int)):
2186 raise InternalError()
2188 if (self._moduleIndex < 0 or self._moduleIndex >= RuntimeConstants.MAX_MODULES):
2189 raise InternalError()
2191 if (self._methodToken < 0 or self._methodToken > Utility.getMaxForNBytes(RuntimeTypeSizes.int)):
2192 raise InternalError()
2194 if (not self._methodInstArgs is None):
2195 if (not issubclass(type(self._methodInstArgs), list)):
2196 raise InternalError()
2198 for i in self._methodInstArgs:
2199 if (not issubclass(type(i), IType)):
2200 raise InternalError()
2202 # Create from objects taking them by reference
2204 def createByRef(methodFlags, moduleIndex, typeHandle, methodToken, methodInstArgs):
2205 method = GenericMethod()
2207 method._methodFlags = methodFlags # pylint: disable=protected-access
2208 method._moduleIndex = moduleIndex # pylint: disable=protected-access
2209 method._typeHandle = typeHandle # pylint: disable=protected-access
2210 method._methodToken = methodToken # pylint: disable=protected-access
2211 method._methodInstArgs = methodInstArgs # pylint: disable=protected-access
2216 # Create from objects taking them by copy
2218 def createByCopy(methodFlags, moduleIndex, typeHandle, methodToken, methodInstArgs):
2219 copiedInstArgs = None
2220 if (not methodInstArgs is None):
2222 for i in methodInstArgs:
2223 copiedInstArgs.append(i.copy())
2225 return GenericMethod.createByRef(methodFlags, moduleIndex, typeHandle.copy(), methodToken, copiedInstArgs)
2229 return GenericMethod.createByCopy(self._methodFlags, self._moduleIndex, self._typeHandle,
2230 self._methodToken, self._methodInstArgs)
2232 #----------------------------------------------------------------------------------------------------------------------
2233 # Utilities for binary signature encoding/decoding
2234 class SignatureDecoderUtil:
2236 # Corresponds to EncodeMethodSigFlags
2237 # TODO: verify these constants somehow, see above
2238 class EncodeMethodSigFlags: # pylint: disable=too-few-public-methods
2239 ENCODE_METHOD_SIG_UnboxingStub = 0x01
2240 ENCODE_METHOD_SIG_InstantiatingStub = 0x02
2241 ENCODE_METHOD_SIG_MethodInstantiation = 0x04
2242 ENCODE_METHOD_SIG_SlotInsteadOfToken = 0x08
2243 ENCODE_METHOD_SIG_MemberRefToken = 0x10
2244 ENCODE_METHOD_SIG_Constrained = 0x20
2245 ENCODE_METHOD_SIG_OwnerType = 0x40
2246 ENCODE_METHOD_SIG_UpdateContext = 0x80
2248 # Corresponds to CorTokenType
2249 # TODO: verify these constants somehow, see above
2250 class CorTokenType: # pylint: disable=too-few-public-methods
2251 mdtModule = 0x00000000
2252 mdtTypeRef = 0x01000000
2253 mdtTypeDef = 0x02000000
2254 mdtFieldDef = 0x04000000
2255 mdtMethodDef = 0x06000000
2256 mdtParamDef = 0x08000000
2257 mdtInterfaceImpl = 0x09000000
2258 mdtMemberRef = 0x0a000000
2259 mdtCustomAttribute = 0x0c000000
2260 mdtPermission = 0x0e000000
2261 mdtSignature = 0x11000000
2262 mdtEvent = 0x14000000
2263 mdtProperty = 0x17000000
2264 mdtMethodImpl = 0x19000000
2265 mdtModuleRef = 0x1a000000
2266 mdtTypeSpec = 0x1b000000
2267 mdtAssembly = 0x20000000
2268 mdtAssemblyRef = 0x23000000
2269 mdtFile = 0x26000000
2270 mdtExportedType = 0x27000000
2271 mdtManifestResource = 0x28000000
2272 mdtNestedClass = 0x29000000
2273 mdtGenericParam = 0x2a000000
2274 mdtMethodSpec = 0x2b000000
2275 mdtGenericParamConstraint = 0x2c000000
2276 mdtString = 0x70000000
2277 mdtName = 0x71000000
2278 mdtBaseType = 0x72000000
2280 # Get token from rid and type
2282 def getTokenFromRid(rid, typ):
2285 # Get rid from token
2287 def getRidFromToken(token):
2288 return token & 0x00ffffff
2290 # Get type from token
2292 def getTypeFromToken(token):
2293 return token & 0xff000000
2295 #----------------------------------------------------------------------------------------------------------------------
2296 # Decoder for binary signature of method that is created by MCJ
2298 # Conceptually corresponds to ZapSig::DecodeMethod
2300 class MethodBinarySignatureDecoder: # pylint: disable=too-few-public-methods
2302 # Constructor with module index for binary signature and binary signature itself
2303 def __init__(self, moduleIndex, bytesArr):
2304 if (moduleIndex is None or bytesArr is None):
2305 raise InternalError()
2306 if (not issubclass(type(moduleIndex), int) or not issubclass(type(bytesArr), list)):
2307 raise InternalError()
2310 if (i < 0 or i > Utility.getMaxForNBytes(RuntimeTypeSizes.char)):
2311 raise InternalError()
2313 self._moduleIndex = moduleIndex
2314 self._bytesArr = bytesArr
2317 # Decode one byte from binary signature
2319 # See SigBuilder::AppendByte
2320 def _decodeByte(self):
2321 value = self._bytesArr[self._index]
2325 # Decode value (1, 2 or 4 bytes) from binary signature
2327 # See SigBuilder::AppendData
2328 def _decodeValue(self):
2331 if ((self._bytesArr[self._index] & 0x80) == 0):
2334 if (self._index + length > len(self._bytesArr)):
2335 raise ProfileInconsistencyError()
2336 value = self._bytesArr[self._index]
2338 raise InternalError()
2339 elif ((self._bytesArr[self._index] & 0xc0) == 0x80):
2342 if (self._index + length > len(self._bytesArr)):
2343 raise ProfileInconsistencyError()
2344 value = ((self._bytesArr[self._index] & 0x3f) << 8) | self._bytesArr[self._index + 1]
2345 if (value > 0x3fff):
2346 raise InternalError()
2347 elif ((self._bytesArr[self._index] & 0xe0) == 0xc0):
2350 if (self._index + length > len(self._bytesArr)):
2351 raise ProfileInconsistencyError()
2352 value = ((self._bytesArr[self._index] & 0x1f) << 24) | (self._bytesArr[self._index + 1] << 16)
2353 value = value | (self._bytesArr[self._index + 2] << 8) | self._bytesArr[self._index + 3]
2354 if (value > 0x1fffffff):
2355 raise InternalError()
2357 raise ProfileInconsistencyError()
2359 self._index += length
2363 # Decode token from binary signature
2365 # See SigBuilder::AppendToken
2366 def _decodeToken(self):
2367 value = self._decodeValue()
2369 # get encode type and rid
2370 encodedType = value & 0x3
2374 if (encodedType == 0x0):
2375 typ = SignatureDecoderUtil.CorTokenType.mdtTypeDef
2376 elif (encodedType == 0x1):
2377 typ = SignatureDecoderUtil.CorTokenType.mdtTypeRef
2378 elif (encodedType == 0x2):
2379 typ = SignatureDecoderUtil.CorTokenType.mdtTypeSpec
2380 elif (encodedType == 0x3):
2381 typ = SignatureDecoderUtil.CorTokenType.mdtBaseType
2383 raise ProfileInconsistencyError()
2385 return SignatureDecoderUtil.getTokenFromRid(rid, typ)
2387 # Decode type from binary signature
2389 # See ZapSig::GetSignatureForTypeHandle
2390 def _decodeSignatureForTypeHandle(self, moduleIndex): # pylint: disable=too-many-locals, too-many-return-statements, too-many-statements
2391 if (moduleIndex is None or not issubclass(type(moduleIndex), int)):
2392 raise InternalError()
2395 typ = self._decodeByte()
2397 # II. Decode primitive type
2398 if (typ < CorTypeInfo.CorElementType.ELEMENT_TYPE_MAX
2399 and (CorTypeInfo.getTypeMapEntry(typ).getIsPrim()
2400 or typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_STRING
2401 or typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_OBJECT)):
2402 return TypeSimple.createByRef(typ)
2404 # III. Decode non-primitive type
2405 if (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_TYPEDBYREF): # pylint: disable=no-else-raise
2406 # TODO: support this?
2407 raise UnsupportedError()
2408 elif (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG):
2409 paramType = self._decodeSignatureForTypeHandle(moduleIndex)
2410 return TypeParamType.createByRef(typ, paramType)
2411 elif (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_CANON_ZAPSIG):
2412 return TypeSimple.createByRef(typ)
2413 elif (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_MODULE_ZAPSIG):
2414 nextModuleIndex = self._decodeValue()
2415 return self._decodeSignatureForTypeHandle(nextModuleIndex)
2416 elif (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_VAR_ZAPSIG):
2417 rid = self._decodeValue()
2418 typeToken = SignatureDecoderUtil.getTokenFromRid(rid, SignatureDecoderUtil.CorTokenType.mdtGenericParam)
2419 return TypeToken.createByRef(typ, moduleIndex, typeToken)
2420 elif (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_VAR): # pylint: disable=no-else-raise
2421 # TODO: support this?
2422 raise UnsupportedError()
2423 elif (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_MVAR): # pylint: disable=no-else-raise
2424 # TODO: support this?
2425 raise UnsupportedError()
2426 elif (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_GENERICINST):
2427 nextTyp = self._decodeByte()
2429 if (nextTyp == CorTypeInfo.CorElementType.ELEMENT_TYPE_INTERNAL): # pylint: disable=no-else-raise
2430 # TODO: support this?
2431 raise UnsupportedError()
2433 typeToken = self._decodeToken()
2434 tid = SignatureDecoderUtil.getTypeFromToken(typeToken)
2436 if (not tid in (SignatureDecoderUtil.CorTokenType.mdtTypeRef,
2437 SignatureDecoderUtil.CorTokenType.mdtTypeDef)):
2438 raise ProfileInconsistencyError()
2440 numArgs = self._decodeValue()
2442 for i in range(numArgs): # pylint: disable=unused-variable
2443 args.append(self._decodeSignatureForTypeHandle(moduleIndex))
2445 return TypeGeneric.createByRef(typ, TypeToken.createByRef(nextTyp, moduleIndex, typeToken), args)
2446 elif (typ in (CorTypeInfo.CorElementType.ELEMENT_TYPE_CLASS,
2447 CorTypeInfo.CorElementType.ELEMENT_TYPE_VALUETYPE)):
2448 typeToken = self._decodeToken()
2449 tid = SignatureDecoderUtil.getTypeFromToken(typeToken)
2451 if (not tid in (SignatureDecoderUtil.CorTokenType.mdtTypeRef,
2452 SignatureDecoderUtil.CorTokenType.mdtTypeDef)):
2453 raise ProfileInconsistencyError()
2455 return TypeToken.createByRef(typ, moduleIndex, typeToken)
2456 elif (typ in (CorTypeInfo.CorElementType.ELEMENT_TYPE_ARRAY, CorTypeInfo.CorElementType.ELEMENT_TYPE_SZARRAY)):
2457 elemType = self._decodeSignatureForTypeHandle(moduleIndex)
2459 if (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_ARRAY): # pylint: disable=no-else-return
2460 rank = self._decodeValue()
2461 # Next two values are always written as 0 (see ZapSig::GetSignatureForTypeHandle)
2462 nsizes = self._decodeValue()
2463 nlbounds = self._decodeValue()
2465 if (nsizes != 0 or nlbounds != 0):
2466 raise UnsupportedError()
2468 return TypeArray.createByRef(typ, elemType, rank)
2470 return TypeSZArray.createByRef(typ, elemType)
2471 elif (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_PINNED):
2472 nextType = self._decodeSignatureForTypeHandle(moduleIndex)
2473 return TypeParamType.createByRef(typ, nextType)
2474 elif (typ in (CorTypeInfo.CorElementType.ELEMENT_TYPE_BYREF, CorTypeInfo.CorElementType.ELEMENT_TYPE_PTR)):
2475 paramType = self._decodeSignatureForTypeHandle(moduleIndex)
2476 return TypeParamType.createByRef(typ, paramType)
2477 elif (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_FNPTR):
2478 callConv = self._decodeByte()
2479 cArgs = self._decodeValue()
2481 for i in range(cArgs):
2482 retAndArgs.append(self._decodeSignatureForTypeHandle(moduleIndex))
2483 return TypeFNPtr.createByRef(typ, callConv, retAndArgs)
2484 elif (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_INTERNAL): # pylint: disable=no-else-raise
2485 # TODO: support this?
2486 raise UnsupportedError()
2487 elif (typ == CorTypeInfo.CorElementType.ELEMENT_TYPE_SENTINEL): # pylint: disable=no-else-raise
2488 # TODO: support this?
2489 raise UnsupportedError()
2491 raise InternalError()
2493 # Decode binary signature for method, result can be used by reference
2495 # See ZapSig::DecodeMethod
2496 def decodeMethod(self):
2500 methodInstArgs = None
2502 # I. Decode method flags
2503 methodFlags = self._decodeValue()
2506 if (methodFlags & SignatureDecoderUtil.EncodeMethodSigFlags.ENCODE_METHOD_SIG_UpdateContext != 0):
2507 # Should not be encoded in mcj profile
2508 raise UnsupportedError()
2510 if ((methodFlags & SignatureDecoderUtil.EncodeMethodSigFlags.ENCODE_METHOD_SIG_OwnerType) != 0):
2511 typeHandle = self._decodeSignatureForTypeHandle(self._moduleIndex)
2513 raise UnsupportedError()
2515 # III. Decode method token
2516 if (methodFlags & SignatureDecoderUtil.EncodeMethodSigFlags.ENCODE_METHOD_SIG_SlotInsteadOfToken != 0): # pylint: disable=no-else-raise
2517 raise UnsupportedError()
2519 rid = self._decodeValue()
2521 if (methodFlags & SignatureDecoderUtil.EncodeMethodSigFlags.ENCODE_METHOD_SIG_MemberRefToken):
2522 methodToken = SignatureDecoderUtil.getTokenFromRid(rid, SignatureDecoderUtil.CorTokenType.mdtMemberRef)
2524 methodToken = SignatureDecoderUtil.getTokenFromRid(rid, SignatureDecoderUtil.CorTokenType.mdtMethodDef)
2526 # IV. Decode method instantiation args
2527 if (methodFlags & SignatureDecoderUtil.EncodeMethodSigFlags.ENCODE_METHOD_SIG_MethodInstantiation != 0):
2528 numInstArgs = self._decodeValue()
2531 for i in range(numInstArgs): # pylint: disable=unused-variable
2532 methodInstArgs.append(self._decodeSignatureForTypeHandle(self._moduleIndex))
2534 if (methodFlags & SignatureDecoderUtil.EncodeMethodSigFlags.ENCODE_METHOD_SIG_Constrained != 0):
2535 raise UnsupportedError()
2537 ret = GenericMethod.createByRef(methodFlags, self._moduleIndex, typeHandle, methodToken, methodInstArgs)
2539 self._moduleIndex = None
2540 self._bytesArr = None
2545 #----------------------------------------------------------------------------------------------------------------------
2546 # Encoder for binary signature of method that is stored in MCJ profile
2548 # Conceptually corresponds to ZapSig::EncodeMethod
2550 class MethodBinarySignatureEncoder: # pylint: disable=too-few-public-methods
2552 # Constructor with generic method handle
2553 def __init__(self, methodHandle):
2554 if (methodHandle is None or not issubclass(type(methodHandle), GenericMethod)):
2555 raise InternalError()
2557 self._methodHandle = methodHandle
2560 # Encode one byte to binary signature
2562 # See SigBuilder::AppendByte
2563 def _encodeByte(self, value):
2564 if (value is None or not issubclass(type(value), int)):
2565 raise InternalError()
2566 if (value < 0 or value > Utility.getMaxForNBytes(RuntimeTypeSizes.char)):
2567 raise InternalError()
2569 self._bytesArr.append(value)
2571 # Encode value (1, 2 or 4 bytes) to binary signature
2573 # See SigBuilder::AppendData
2574 def _encodeValue(self, value):
2575 if (value is None or not issubclass(type(value), int)):
2576 raise InternalError()
2577 if (value < 0 or value > Utility.getMaxForNBytes(RuntimeTypeSizes.int)):
2578 raise InternalError()
2581 self._bytesArr.append(value)
2582 elif (value <= 0x3fff):
2583 self._bytesArr.append((value >> 8) | 0x80)
2584 self._bytesArr.append(value & 0xff)
2585 elif (value <= 0x1fffffff):
2586 self._bytesArr.append((value >> 24) | 0xc0)
2587 self._bytesArr.append((value >> 16) & 0xff)
2588 self._bytesArr.append((value >> 8) & 0xff)
2589 self._bytesArr.append(value & 0xff)
2591 raise InternalError()
2593 # Encode token to binary signature
2595 # See SigBuilder::AppendToken
2596 def _encodeToken(self, value):
2597 if (value is None or not issubclass(type(value), int)):
2598 raise InternalError()
2599 if (value < 0 or value > Utility.getMaxForNBytes(RuntimeTypeSizes.int)):
2600 raise InternalError()
2602 rid = SignatureDecoderUtil.getRidFromToken(value)
2603 typ = SignatureDecoderUtil.getTypeFromToken(value)
2605 if (rid > 0x3ffffff):
2606 raise InternalError()
2610 if (typ == SignatureDecoderUtil.CorTokenType.mdtTypeDef):
2612 elif (typ == SignatureDecoderUtil.CorTokenType.mdtTypeRef):
2614 elif (typ == SignatureDecoderUtil.CorTokenType.mdtTypeSpec):
2616 elif (typ == SignatureDecoderUtil.CorTokenType.mdtBaseType):
2619 self._encodeValue(rid)
2621 # Encode type to binary signature
2623 # See ZapSig::GetSignatureForTypeHandle
2624 def _encodeSignatureForTypeHandle(self, typeHandle):
2625 if (typeHandle is None or not issubclass(type(typeHandle), IType)):
2626 raise InternalError()
2628 # I. Encode element type
2629 if (issubclass(type(typeHandle), TypeSimple)):
2630 self._encodeByte(typeHandle.getElementKind())
2631 elif (issubclass(type(typeHandle), TypeToken)):
2632 if (typeHandle.getModuleIndex() != self._methodHandle.getModuleIndex()):
2633 self._encodeByte(CorTypeInfo.CorElementType.ELEMENT_TYPE_MODULE_ZAPSIG)
2634 self._encodeValue(typeHandle.getModuleIndex())
2636 self._encodeByte(typeHandle.getElementKind())
2638 if (typeHandle.getElementKind() == CorTypeInfo.CorElementType.ELEMENT_TYPE_VAR_ZAPSIG):
2639 self._encodeValue(SignatureDecoderUtil.getRidFromToken(typeHandle.getTypeToken()))
2641 self._encodeToken(typeHandle.getTypeToken())
2642 elif (issubclass(type(typeHandle), TypeParamType)):
2643 self._encodeByte(typeHandle.getElementKind())
2644 self._encodeSignatureForTypeHandle(typeHandle.getParamType())
2645 elif (issubclass(type(typeHandle), TypeArray)):
2646 self._encodeByte(typeHandle.getElementKind())
2647 self._encodeSignatureForTypeHandle(typeHandle.getArrayElementType())
2648 self._encodeValue(typeHandle.getRank())
2649 self._encodeValue(0)
2650 self._encodeValue(0)
2651 elif (issubclass(type(typeHandle), TypeSZArray)):
2652 self._encodeByte(typeHandle.getElementKind())
2653 self._encodeSignatureForTypeHandle(typeHandle.getArrayElementType())
2654 elif (issubclass(type(typeHandle), TypeGeneric)):
2655 genericBaseType = typeHandle.getGenericBaseType()
2656 if (genericBaseType.getModuleIndex() != self._methodHandle.getModuleIndex()):
2657 self._encodeByte(CorTypeInfo.CorElementType.ELEMENT_TYPE_MODULE_ZAPSIG)
2658 self._encodeValue(genericBaseType.getModuleIndex())
2660 self._encodeByte(typeHandle.getElementKind())
2661 self._encodeByte(genericBaseType.getElementKind())
2662 self._encodeToken(genericBaseType.getTypeToken())
2664 self._encodeValue(len(typeHandle.getInstArgs()))
2665 for i in typeHandle.getInstArgs():
2666 self._encodeSignatureForTypeHandle(i)
2667 elif (issubclass(type(typeHandle), TypeFNPtr)):
2668 self._encodeByte(typeHandle.getElementKind())
2669 self._encodeByte(typeHandle.getCallConv())
2671 self._encodeValue(len(typeHandle.getRetAndArgs()))
2672 for i in typeHandle.getRetAndArgs():
2673 self._encodeSignatureForTypeHandle(i)
2675 # Encode binary signature for method, result can be used by reference
2677 # See ZapSig::EncodeMethod
2678 def encodeMethod(self):
2679 methodFlags = self._methodHandle.getMethodFlags()
2681 # I. Encode method flags
2682 self._encodeValue(methodFlags)
2685 if ((methodFlags & SignatureDecoderUtil.EncodeMethodSigFlags.ENCODE_METHOD_SIG_OwnerType) != 0):
2686 self._encodeSignatureForTypeHandle(self._methodHandle.getTypeHandle())
2688 raise UnsupportedError()
2690 # III. Encode method token
2691 if (methodFlags & SignatureDecoderUtil.EncodeMethodSigFlags.ENCODE_METHOD_SIG_SlotInsteadOfToken != 0): # pylint: disable=no-else-raise
2692 raise UnsupportedError()
2694 self._encodeValue(SignatureDecoderUtil.getRidFromToken(self._methodHandle.getMethodToken()))
2696 # IV. Encode method instantiation args
2697 if (methodFlags & SignatureDecoderUtil.EncodeMethodSigFlags.ENCODE_METHOD_SIG_MethodInstantiation != 0):
2698 methodInstArgs = self._methodHandle.getMethodInstArgs()
2700 if (methodInstArgs is None):
2701 raise InternalError()
2703 self._encodeValue(len(methodInstArgs))
2704 for i in methodInstArgs:
2705 self._encodeSignatureForTypeHandle(i)
2707 ret = self._bytesArr
2709 self._bytesArr = None
2710 self._methodHandle = None
2714 # ----------------------------------------------------------------------------------------------------------------------
2715 # Base class for records with module dependency or method
2721 def getRecordType(self):
2726 def getModuleIndex(self):
2729 # Get all module indexes used in related types
2730 def getAllModuleIndexes(self):
2733 # Check if info is related to generic method
2735 def isGenericMethodInfo(self):
2738 # Check if info is related to non-generic method
2740 def isNonGenericMethodInfo(self):
2743 # Check if info is related to method
2745 def isMethodInfo(self):
2748 # Check if info is related to module
2750 def isModuleInfo(self):
2753 # ----------------------------------------------------------------------------------------------------------------------
2754 # Record with module dependency
2756 # Conceptually corresponds to "struct RecorderInfo" from multicorejitimpl.h, but has slight differences
2758 # To create from bytes: InfoModuleDependency.createFromBytes(bytes)
2759 # To create from data structures using references: InfoModuleDependency.createByRef(...)
2760 # To create from data structures using copy: InfoModuleDependency.createByCopy(...)
2762 class InfoModuleDependency(Info):
2764 # Empty constructor, do not use it directly
2765 # Create new objects by createByCopy or createByRef
2767 self._moduleIndex = None
2768 self._moduleLoadLevel = None
2770 # Equality comparison operator
2771 def __eq__(self, rhs):
2772 if (rhs is None or not issubclass(type(rhs), InfoModuleDependency)):
2774 return self._moduleIndex == rhs._moduleIndex and self._moduleLoadLevel == rhs._moduleLoadLevel
2777 def getRecordType(self): # pylint: disable=no-self-use
2778 return RuntimeConstants.MULTICOREJIT_MODULEDEPENDENCY_RECORD_ID
2780 # Check if info is related to generic method
2781 def isGenericMethodInfo(self): # pylint: disable=no-self-use
2784 # Check if info is related to non-generic method
2785 def isNonGenericMethodInfo(self): # pylint: disable=no-self-use
2788 # Check if info is related to method
2789 def isMethodInfo(self): # pylint: disable=no-self-use
2792 # Check if info is related to module
2793 def isModuleInfo(self): # pylint: disable=no-self-use
2797 def getModuleIndex(self):
2798 return self._moduleIndex
2800 # Get all module indexes used in related types
2801 def getAllModuleIndexes(self):
2802 return [self._moduleIndex]
2804 # Get module load level
2805 def getModuleLoadLevel(self):
2806 return self._moduleLoadLevel
2808 # Update module index according to map old_index->new_index
2809 def updateModuleIndex(self, moduleIndexMap):
2810 if (moduleIndexMap is None or not issubclass(type(moduleIndexMap), list)):
2811 raise InternalError()
2812 self._moduleIndex = moduleIndexMap[self._moduleIndex]
2815 # Verify consistency
2817 if (self._moduleIndex is None or self._moduleLoadLevel is None):
2818 raise InternalError()
2820 if (not issubclass(type(self._moduleIndex), int) or not issubclass(type(self._moduleLoadLevel), int)):
2821 raise InternalError()
2823 if (self._moduleIndex < 0 or self._moduleIndex >= RuntimeConstants.MAX_MODULES):
2824 raise InternalError()
2826 if (self._moduleLoadLevel < 0 or self._moduleLoadLevel >= RuntimeConstants.MAX_MODULE_LEVELS):
2827 raise InternalError()
2830 def _encodeInfo(self):
2832 # high byte is record id
2833 data1 |= RuntimeConstants.MULTICOREJIT_MODULEDEPENDENCY_RECORD_ID << RuntimeConstants.RECORD_TYPE_OFFSET
2834 # next byte is load level
2835 data1 |= self._moduleLoadLevel << RuntimeConstants.MODULE_LEVEL_OFFSET
2836 # two low bytes are module index
2837 data1 |= self._moduleIndex
2840 # Decode type of this record, module index and module load level
2842 def _decodeInfo(data1):
2843 recordType = data1 >> RuntimeConstants.RECORD_TYPE_OFFSET
2844 loadLevel = (data1 >> RuntimeConstants.MODULE_LEVEL_OFFSET) & (RuntimeConstants.MAX_MODULE_LEVELS - 1)
2845 moduleIndex = data1 & RuntimeConstants.MODULE_MASK
2846 return (recordType, loadLevel, moduleIndex)
2849 def printRaw(self, offsetStr=""):
2850 if (offsetStr is None or not issubclass(type(offsetStr), str)):
2851 raise InternalError()
2853 data1 = self._encodeInfo()
2855 print(offsetStr + ">>> Raw ModuleDependency:")
2856 print(offsetStr + "data1 = " + str(data1))
2859 def print(self, offsetStr="", modules=None):
2860 if (offsetStr is None or not issubclass(type(offsetStr), str)):
2861 raise InternalError()
2863 # Get module name if it is available
2865 if (not modules is None):
2866 moduleName = modules[self.getModuleIndex()].getModuleName()
2868 print(offsetStr + ">>> Record, Module Dependency:")
2869 print(offsetStr + "")
2870 print(offsetStr + "Module index: " + str(self.getModuleIndex())
2871 + ((" (" + moduleName + ")") if moduleName != "" else ""))
2872 print(offsetStr + "Module load level: " + str(self.getModuleLoadLevel()))
2873 print(offsetStr + "")
2877 def createFromBytes(bytesArr):
2878 if (bytesArr is None):
2879 raise InternalError()
2881 if (not issubclass(type(bytesArr), list)):
2882 raise InternalError()
2884 if (len(bytesArr) != RuntimeTypeSizes.int):
2885 raise ProfileInconsistencyError()
2889 data1 = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int])
2890 index += RuntimeTypeSizes.int
2892 if (index != RuntimeTypeSizes.int):
2893 raise InternalError()
2895 recordType, moduleLoadLevel, moduleIndex = InfoModuleDependency._decodeInfo(data1)
2897 if (recordType != RuntimeConstants.MULTICOREJIT_MODULEDEPENDENCY_RECORD_ID):
2898 raise InternalError()
2900 return InfoModuleDependency.createByRef(moduleIndex, moduleLoadLevel)
2902 # Create from objects taking them by reference
2904 def createByRef(moduleIndex, moduleLoadLevel):
2905 moduleDependency = InfoModuleDependency()
2907 moduleDependency._moduleIndex = moduleIndex # pylint: disable=protected-access
2908 moduleDependency._moduleLoadLevel = moduleLoadLevel # pylint: disable=protected-access
2910 moduleDependency.verify()
2911 return moduleDependency
2913 # Create from objects taking them by copy
2915 def createByCopy(moduleIndex, moduleLoadLevel):
2916 return InfoModuleDependency.createByRef(moduleIndex, moduleLoadLevel)
2920 return InfoModuleDependency.createByCopy(self._moduleIndex, self._moduleLoadLevel)
2922 # Convert object to list of bytes
2923 def convertToBytes(self):
2928 data1 = self._encodeInfo()
2930 bytesArr += Utility.splitNBytes(data1, RuntimeTypeSizes.int)
2931 index += RuntimeTypeSizes.int
2933 if (index != RuntimeTypeSizes.int):
2934 raise InternalError()
2938 # ----------------------------------------------------------------------------------------------------------------------
2939 # Record with non-generic method
2941 # Conceptually corresponds to "struct RecorderInfo" from multicorejitimpl.h, but has slight differences
2943 # To create from bytes: InfoNonGenericMethod.createFromBytes(bytes)
2944 # To create from data structures using references: InfoNonGenericMethod.createByRef(...)
2945 # To create from data structures using copy: InfoNonGenericMethod.createByCopy(...)
2947 class InfoNonGenericMethod(Info):
2949 # Empty constructor, do not use it directly
2950 # Create new objects by createByCopy or createByRef
2952 self._moduleIndex = None
2953 self._methodFlags = None
2954 self._methodToken = None
2956 # Equality comparison operator
2957 def __eq__(self, rhs):
2958 if (rhs is None or not issubclass(type(rhs), InfoNonGenericMethod)):
2960 return self._moduleIndex == rhs._moduleIndex and self._methodFlags == rhs._methodFlags \
2961 and self._methodToken == rhs._methodToken
2964 def getRecordType(self): # pylint: disable=no-self-use
2965 return RuntimeConstants.MULTICOREJIT_METHOD_RECORD_ID
2967 # Check if info is related to generic method
2968 def isGenericMethodInfo(self): # pylint: disable=no-self-use
2971 # Check if info is related to non-generic method
2972 def isNonGenericMethodInfo(self): # pylint: disable=no-self-use
2975 # Check if info is related to method
2976 def isMethodInfo(self): # pylint: disable=no-self-use
2979 # Check if info is related to module
2980 def isModuleInfo(self): # pylint: disable=no-self-use
2984 def getModuleIndex(self):
2985 return self._moduleIndex
2987 # Get all module indexes used in related types
2988 def getAllModuleIndexes(self):
2989 return [self._moduleIndex]
2992 def getMethodFlags(self):
2993 return self._methodFlags
2996 def getMethodToken(self):
2997 return self._methodToken
2999 # Update module index according to map old_index->new_index
3000 def updateModuleIndex(self, moduleIndexMap):
3001 if (moduleIndexMap is None or not issubclass(type(moduleIndexMap), list)):
3002 raise InternalError()
3003 self._moduleIndex = moduleIndexMap[self._moduleIndex]
3006 # Verify consistency
3008 if (self._moduleIndex is None or self._methodFlags is None or self._methodToken is None):
3009 raise InternalError()
3011 if (not issubclass(type(self._moduleIndex), int) or not issubclass(type(self._methodFlags), int)
3012 or not issubclass(type(self._methodToken), int)):
3013 raise InternalError()
3015 if (self._moduleIndex < 0 or self._moduleIndex >= RuntimeConstants.MAX_MODULES):
3016 raise InternalError()
3018 if (self._methodFlags < 0
3019 or ((self._methodFlags | RuntimeConstants.METHOD_FLAGS_MASK) ^ RuntimeConstants.METHOD_FLAGS_MASK) != 0):
3020 raise InternalError()
3022 if (self._methodToken < 0 or self._methodToken > Utility.getMaxForNBytes(RuntimeTypeSizes.int)):
3023 raise InternalError()
3026 def _encodeInfo(self):
3028 # high byte is record id
3029 data1 |= RuntimeConstants.MULTICOREJIT_METHOD_RECORD_ID << RuntimeConstants.RECORD_TYPE_OFFSET
3030 # next byte is method flags
3031 data1 |= self._methodFlags
3032 # two low bytes are module index
3033 data1 |= self._moduleIndex
3035 # this is simply token
3036 data2 = self._methodToken
3038 return (data1, data2)
3040 # Decode type of this record, module index and module load level
3042 def _decodeInfo(data1, data2):
3043 recordType = data1 >> RuntimeConstants.RECORD_TYPE_OFFSET
3044 methodFlags = data1 & RuntimeConstants.METHOD_FLAGS_MASK
3045 moduleIndex = data1 & RuntimeConstants.MODULE_MASK
3047 return (recordType, methodFlags, moduleIndex, methodToken)
3050 def printRaw(self, offsetStr=""):
3051 if (offsetStr is None or not issubclass(type(offsetStr), str)):
3052 raise InternalError()
3054 data1, data2 = self._encodeInfo()
3056 print(offsetStr + ">>> Raw Non-Generic MethodRecord:")
3057 print(offsetStr + "data1 = " + str(data1))
3058 print(offsetStr + "data2 = " + str(data2))
3061 def print(self, offsetStr="", modules=None):
3062 if (offsetStr is None or not issubclass(type(offsetStr), str)):
3063 raise InternalError()
3065 # Get module name if it is available
3067 if (not modules is None):
3068 moduleName = modules[self.getModuleIndex()].getModuleName()
3070 flagsStr = "jitted by background thread"
3071 if (self._methodFlags & RuntimeConstants.JIT_BY_APP_THREAD_TAG != 0):
3072 flagsStr = "jitted by foreground (app) thread"
3074 print(offsetStr + ">>> Record, Non-generic Method:")
3075 print(offsetStr + "")
3076 print(offsetStr + "Module index: " + str(self.getModuleIndex())
3077 + ((" (" + moduleName + ")") if moduleName != "" else ""))
3078 print(offsetStr + "Method flags: " + str(self.getMethodFlags()) + " (" + flagsStr + ")")
3079 print(offsetStr + "Method token: " + str(self.getMethodToken()))
3080 print(offsetStr + "")
3084 def createFromBytes(bytesArr):
3085 if (bytesArr is None):
3086 raise InternalError()
3088 if (not issubclass(type(bytesArr), list)):
3089 raise InternalError()
3091 if (len(bytesArr) != 2 * RuntimeTypeSizes.int):
3092 raise ProfileInconsistencyError()
3096 data1 = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int])
3097 index += RuntimeTypeSizes.int
3099 data2 = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int])
3100 index += RuntimeTypeSizes.int
3102 if (index != 2 * RuntimeTypeSizes.int):
3103 raise InternalError()
3105 recordType, methodFlags, moduleIndex, methodToken = InfoNonGenericMethod._decodeInfo(data1, data2)
3107 if (recordType != RuntimeConstants.MULTICOREJIT_METHOD_RECORD_ID):
3108 raise InternalError()
3110 return InfoNonGenericMethod.createByRef(moduleIndex, methodFlags, methodToken)
3112 # Create from objects taking them by reference
3114 def createByRef(moduleIndex, methodFlags, methodToken):
3115 method = InfoNonGenericMethod()
3117 method._moduleIndex = moduleIndex # pylint: disable=protected-access
3118 method._methodFlags = methodFlags # pylint: disable=protected-access
3119 method._methodToken = methodToken # pylint: disable=protected-access
3124 # Create from objects taking them by copy
3126 def createByCopy(moduleIndex, methodFlags, methodToken):
3127 return InfoNonGenericMethod.createByRef(moduleIndex, methodFlags, methodToken)
3131 return InfoNonGenericMethod.createByCopy(self._moduleIndex, self._methodFlags, self._methodToken)
3133 # Convert object to list of bytes
3134 def convertToBytes(self):
3139 data1, data2 = self._encodeInfo()
3141 bytesArr += Utility.splitNBytes(data1, RuntimeTypeSizes.int)
3142 index += RuntimeTypeSizes.int
3144 bytesArr += Utility.splitNBytes(data2, RuntimeTypeSizes.int)
3145 index += RuntimeTypeSizes.int
3147 if (index != 2 * RuntimeTypeSizes.int):
3148 raise InternalError()
3151 # ----------------------------------------------------------------------------------------------------------------------
3152 # Record with generic method
3154 # Conceptually corresponds to "struct RecorderInfo" from multicorejitimpl.h, but has slight differences
3156 # To create from bytes: InfoGenericMethod.createFromBytes(bytes)
3157 # To create from data structures using references: InfoGenericMethod.createByRef(...)
3158 # To create from data structures using copy: InfoGenericMethod.createByCopy(...)
3160 class InfoGenericMethod(Info): # pylint: disable=too-many-public-methods
3162 # Empty constructor, do not use it directly
3163 # Create new objects by createByCopy or createByRef
3165 self._methodFlags = None
3166 self._methodHandle = None
3168 # Equality comparison operator
3169 def __eq__(self, rhs):
3170 if (rhs is None or not issubclass(type(rhs), InfoGenericMethod)):
3172 return self._methodFlags == rhs._methodFlags and self._methodHandle == rhs._methodHandle
3175 def getRecordType(self): # pylint: disable=no-self-use
3176 return RuntimeConstants.MULTICOREJIT_GENERICMETHOD_RECORD_ID
3178 # Check if info is related to generic method
3179 def isGenericMethodInfo(self): # pylint: disable=no-self-use
3182 # Check if info is related to non-generic method
3183 def isNonGenericMethodInfo(self): # pylint: disable=no-self-use
3186 # Check if info is related to method
3187 def isMethodInfo(self): # pylint: disable=no-self-use
3190 # Check if info is related to module
3191 def isModuleInfo(self): # pylint: disable=no-self-use
3195 def getModuleIndex(self):
3196 return self._methodHandle.getModuleIndex()
3198 # Get all module indexes used in related types
3199 def getAllModuleIndexes(self):
3200 return self._methodHandle.getAllModuleIndexes()
3203 def getMethodFlags(self):
3204 return self._methodFlags
3207 def getMethodHandle(self):
3208 return self._methodHandle
3211 def getMethodToken(self):
3212 return self._methodHandle.getMethodToken()
3214 # Update module index according to map old_index->new_index
3215 def updateModuleIndex(self, moduleIndexMap):
3216 if (moduleIndexMap is None or not issubclass(type(moduleIndexMap), list)):
3217 raise InternalError()
3218 self._methodHandle.updateModuleIndex(moduleIndexMap)
3221 # Verify consistency
3223 if (self._methodFlags is None or self._methodHandle is None):
3224 raise InternalError()
3226 if (not issubclass(type(self._methodFlags), int) or not issubclass(type(self._methodHandle), GenericMethod)):
3227 raise InternalError()
3229 if (self._methodFlags < 0
3230 or ((self._methodFlags | RuntimeConstants.METHOD_FLAGS_MASK) ^ RuntimeConstants.METHOD_FLAGS_MASK) != 0):
3231 raise InternalError()
3234 def _encodeInfo(self):
3235 binarySignature = MethodBinarySignatureEncoder(self._methodHandle).encodeMethod()
3238 # high byte is record id
3239 data1 |= RuntimeConstants.MULTICOREJIT_GENERICMETHOD_RECORD_ID << RuntimeConstants.RECORD_TYPE_OFFSET
3240 # next byte is method flags
3241 data1 |= self._methodFlags
3242 # two low bytes are module index
3243 data1 |= self._methodHandle.getModuleIndex()
3245 # this is simply length of binary signature
3246 data2 = len(binarySignature)
3248 # this is simply binary signature
3249 ptr = binarySignature
3251 return (data1, data2, ptr)
3253 # Decode type of this record, module index and module load level
3255 def _decodeInfo(data1, data2, ptr): # pylint: disable=unused-argument
3256 recordType = data1 >> RuntimeConstants.RECORD_TYPE_OFFSET
3257 methodFlags = data1 & RuntimeConstants.METHOD_FLAGS_MASK
3258 moduleIndex = data1 & RuntimeConstants.MODULE_MASK
3260 method = MethodBinarySignatureDecoder(moduleIndex, ptr).decodeMethod()
3262 return (recordType, methodFlags, method)
3265 def printRaw(self, offsetStr=""):
3266 if (offsetStr is None or not issubclass(type(offsetStr), str)):
3267 raise InternalError()
3269 data1, data2, ptr = self._encodeInfo()
3271 size = RuntimeTypeSizes.int + RuntimeTypeSizes.short + data2
3272 padding = Utility.alignUp(size, RuntimeTypeSizes.int) - size
3274 print(offsetStr + ">>> Raw Generic MethodRecord:")
3275 print(offsetStr + "data1 = " + str(data1))
3276 print(offsetStr + "data2 = " + str(data2))
3277 print(offsetStr + "ptr = " + str(ptr))
3278 print(offsetStr + "alignment padding = " + str(padding) + " bytes")
3281 def print(self, offsetStr="", modules=None):
3282 if (offsetStr is None or not issubclass(type(offsetStr), str)):
3283 raise InternalError()
3285 # Get module name if it is available
3287 if (not modules is None):
3288 if (modules is None or not issubclass(type(modules), list)):
3289 raise InternalError()
3291 if (i is None or not issubclass(type(i), ModuleRecordExtended)):
3292 raise InternalError()
3294 moduleName = modules[self.getModuleIndex()].getModuleName()
3296 flagsStr = "jitted by background thread"
3297 if (self._methodFlags & RuntimeConstants.JIT_BY_APP_THREAD_TAG != 0):
3298 flagsStr = "jitted by foreground (app) thread"
3300 print(offsetStr + ">>> Record, Generic Method:")
3301 print(offsetStr + "")
3302 print(offsetStr + "Module index: " + str(self.getModuleIndex())
3303 + ((" (" + moduleName + ")") if moduleName != "" else ""))
3304 print(offsetStr + "Method flags: " + str(self.getMethodFlags()) + " (" + flagsStr + ")")
3305 print(offsetStr + "Decoded binary signature: " + self.getMethodHandle().getStr(modules))
3306 print(offsetStr + "")
3310 def createFromBytes(bytesArr):
3311 if (bytesArr is None):
3312 raise InternalError()
3314 if (not issubclass(type(bytesArr), list)):
3315 raise InternalError()
3317 if (len(bytesArr) < (RuntimeTypeSizes.int + RuntimeTypeSizes.short)):
3318 raise ProfileInconsistencyError()
3322 data1 = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int])
3323 index += RuntimeTypeSizes.int
3325 data2 = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.short])
3326 index += RuntimeTypeSizes.short
3328 if (len(bytesArr) != Utility.alignUp(RuntimeTypeSizes.int + RuntimeTypeSizes.short + data2,
3329 RuntimeTypeSizes.int)):
3330 raise ProfileInconsistencyError()
3332 ptr = bytesArr[index:index+data2]
3335 if (index != RuntimeTypeSizes.int + RuntimeTypeSizes.short + data2):
3336 raise InternalError()
3338 recordType, methodFlags, methodHandle = InfoGenericMethod._decodeInfo(data1, data2, ptr)
3340 if (recordType != RuntimeConstants.MULTICOREJIT_GENERICMETHOD_RECORD_ID):
3341 raise InternalError()
3343 return InfoGenericMethod.createByRef(methodFlags, methodHandle)
3345 # Create from objects taking them by reference
3347 def createByRef(methodFlags, methodHandle):
3348 method = InfoGenericMethod()
3350 method._methodFlags = methodFlags # pylint: disable=protected-access
3351 method._methodHandle = methodHandle # pylint: disable=protected-access
3356 # Create from objects taking them by copy
3358 def createByCopy(methodFlags, methodHandle):
3359 return InfoGenericMethod.createByRef(methodFlags, methodHandle.copy())
3363 return InfoGenericMethod.createByCopy(self._methodFlags, self._methodHandle)
3365 # Convert object to list of bytes
3366 def convertToBytes(self):
3371 data1, data2, ptr = self._encodeInfo()
3373 bytesArr += Utility.splitNBytes(data1, RuntimeTypeSizes.int)
3374 index += RuntimeTypeSizes.int
3376 bytesArr += Utility.splitNBytes(data2, RuntimeTypeSizes.short)
3377 index += RuntimeTypeSizes.short
3382 padding = Utility.alignUp(index, RuntimeTypeSizes.int) - index
3383 bytesArr += [0] * padding
3386 if (index != Utility.alignUp(RuntimeTypeSizes.int + RuntimeTypeSizes.short + data2,
3387 RuntimeTypeSizes.int)):
3388 raise InternalError()
3392 # ----------------------------------------------------------------------------------------------------------------------
3393 # MultiCoreJit profile
3395 # _moduleOrMethodInfo contains records with module deps and methods, both generic and non-generic,
3396 # records' order is the same as in profile
3398 # To create from bytes: MCJProfile.createFromBytes(bytes)
3399 # To create from data structures using references: MCJProfile.createByRef(...)
3400 # To create from data structures using copy: MCJProfile.createByCopy(...)
3402 class MCJProfile: # pylint: disable=too-many-public-methods
3404 # Empty constructor, do not use it directly
3405 # Create new objects by createByCopy or createByRef
3408 self._modules = None
3409 self._moduleOrMethodInfo = None
3411 # Equality comparison operator
3412 def __eq__(self, rhs):
3415 if (not issubclass(type(rhs), MCJProfile)):
3418 if (self._header != rhs._header
3419 or len(self._modules) != len(rhs._modules)
3420 or len(self._moduleOrMethodInfo) != len(rhs._moduleOrMethodInfo)):
3423 for index, module in enumerate(self._modules):
3424 if (module != rhs._modules[index]):
3427 for index, info in enumerate(self._moduleOrMethodInfo):
3428 if (info != rhs._moduleOrMethodInfo[index]):
3434 def getHeader(self):
3438 def getModules(self):
3439 return self._modules
3441 # Get moduleOrMethodInfo
3442 def getModuleOrMethodInfo(self):
3443 return self._moduleOrMethodInfo
3445 # Verify consistency
3447 if (self._header is None or self._modules is None or self._moduleOrMethodInfo is None):
3448 raise InternalError()
3450 if (not issubclass(type(self._header), HeaderRecord)
3451 or not issubclass(type(self._modules), list) or not issubclass(type(self._moduleOrMethodInfo), list)):
3452 raise InternalError()
3454 for i in self._modules:
3456 raise InternalError()
3457 if (not issubclass(type(i), ModuleRecordExtended)):
3458 raise InternalError()
3460 for i in self._moduleOrMethodInfo:
3462 raise InternalError()
3463 if (not issubclass(type(i), InfoModuleDependency)
3464 and not issubclass(type(i), InfoNonGenericMethod)
3465 and not issubclass(type(i), InfoGenericMethod)):
3466 raise InternalError()
3468 if (self._header.getModuleCount() != len(self._modules)):
3469 raise ProfileInconsistencyError()
3471 if ((self._header.getMethodCount() + self._header.getModuleDepCount()) != len(self._moduleOrMethodInfo)):
3472 raise ProfileInconsistencyError()
3474 for info in self._moduleOrMethodInfo:
3475 indexes = info.getAllModuleIndexes()
3477 if (i >= len(self._modules)):
3478 raise InternalError()
3481 def printRawHeader(self, offsetStr=""):
3482 if (offsetStr is None or not issubclass(type(offsetStr), str)):
3483 raise InternalError()
3485 print(offsetStr + ">>> Raw MCJProfile:")
3486 print(offsetStr + "header = {")
3487 self._header.printRaw(offsetStr + " ")
3488 print(offsetStr + "}")
3491 def printRawModules(self, offsetStr=""):
3492 if (offsetStr is None or not issubclass(type(offsetStr), str)):
3493 raise InternalError()
3495 print(offsetStr + "modules = [")
3496 for i in self._modules:
3497 print(offsetStr + " " + "{")
3498 i.printRaw(offsetStr + " ")
3499 print(offsetStr + " " + "},")
3500 print(offsetStr + "]")
3502 # Print raw module dependencies and methods
3503 def printRawModuleOrMethodInfo(self, offsetStr="", printModuleDeps=True,
3504 printGenericMethods=True, printNonGenericMethods=True):
3505 if (offsetStr is None or not issubclass(type(offsetStr), str)):
3506 raise InternalError()
3508 if (printModuleDeps is None or printGenericMethods is None or printNonGenericMethods is None):
3509 raise InternalError()
3511 if (not issubclass(type(printModuleDeps), bool) or not issubclass(type(printGenericMethods), bool)
3512 or not issubclass(type(printNonGenericMethods), bool)):
3513 raise InternalError()
3516 if (printModuleDeps and printGenericMethods and printNonGenericMethods):
3517 name = "moduleOrMethodInfo"
3519 if (printModuleDeps):
3522 name += "module deps"
3523 if (printGenericMethods):
3526 name += "generic methods"
3527 if (printNonGenericMethods):
3530 name += "non generic methods"
3532 print(offsetStr + name + " = [")
3533 for i in self._moduleOrMethodInfo:
3534 doPrint = (i.isModuleInfo() and printModuleDeps) or (i.isGenericMethodInfo() and printGenericMethods) \
3535 or (i.isNonGenericMethodInfo() and printNonGenericMethods)
3538 print(offsetStr + " " + "{")
3539 i.printRaw(offsetStr + " ")
3540 print(offsetStr + " " + "},")
3541 print(offsetStr + "]")
3544 def printRaw(self, offsetStr=""):
3545 self.printRawHeader(offsetStr)
3546 self.printRawModules(offsetStr)
3547 self.printRawModuleOrMethodInfo(offsetStr)
3549 # Print pretty header
3550 def printHeader(self, offsetStr=""):
3551 if (offsetStr is None or not issubclass(type(offsetStr), str)):
3552 raise InternalError()
3554 self._header.print(offsetStr)
3556 # Print pretty modules
3557 def printModules(self, offsetStr=""):
3558 if (offsetStr is None or not issubclass(type(offsetStr), str)):
3559 raise InternalError()
3561 for i in self._modules:
3564 # Print pretty module dependencies and methods
3565 def printModuleOrMethodInfo(self, offsetStr="", printModuleDeps=True,
3566 printGenericMethods=True, printNonGenericMethods=True):
3567 if (offsetStr is None or not issubclass(type(offsetStr), str)):
3568 raise InternalError()
3570 if (printModuleDeps is None or printGenericMethods is None or printNonGenericMethods is None):
3571 raise InternalError()
3573 if (not issubclass(type(printModuleDeps), bool) or not issubclass(type(printGenericMethods), bool)
3574 or not issubclass(type(printNonGenericMethods), bool)):
3575 raise InternalError()
3577 for i in self._moduleOrMethodInfo:
3578 doPrint = (i.isModuleInfo() and printModuleDeps) or (i.isGenericMethodInfo() and printGenericMethods) \
3579 or (i.isNonGenericMethodInfo() and printNonGenericMethods)
3582 i.print(offsetStr, self._modules)
3585 def print(self, offsetStr=""):
3586 self.printHeader(offsetStr)
3587 self.printModules(offsetStr)
3588 self.printModuleOrMethodInfo(offsetStr)
3590 # Get length and type of record at specified byte
3592 def _getRecordTypeAndLen(bytesArr, index):
3593 if (bytesArr is None or index is None):
3594 raise InternalError()
3596 if (not issubclass(type(bytesArr), list) or not issubclass(type(index), int)):
3597 raise InternalError()
3599 if (index + RuntimeTypeSizes.int > len(bytesArr)):
3600 raise ProfileInconsistencyError()
3602 data1 = Utility.mergeNBytes(bytesArr[index:index+RuntimeTypeSizes.int])
3603 rcdTyp = data1 >> RuntimeConstants.RECORD_TYPE_OFFSET
3606 if (rcdTyp == RuntimeConstants.MULTICOREJIT_MODULE_RECORD_ID):
3607 rcdLen = data1 & RuntimeConstants.X_MODULE_RECORD_LEN_MASK
3608 elif (rcdTyp == RuntimeConstants.MULTICOREJIT_MODULEDEPENDENCY_RECORD_ID):
3609 rcdLen = RuntimeTypeSizes.int
3610 elif (rcdTyp == RuntimeConstants.MULTICOREJIT_METHOD_RECORD_ID):
3611 rcdLen = 2 * RuntimeTypeSizes.int
3612 elif (rcdTyp == RuntimeConstants.MULTICOREJIT_GENERICMETHOD_RECORD_ID):
3613 if (index + RuntimeTypeSizes.int + RuntimeTypeSizes.short > len(bytesArr)):
3614 raise ProfileInconsistencyError()
3616 tmpindex = index+RuntimeTypeSizes.int
3617 signatureLength = Utility.mergeNBytes(bytesArr[tmpindex:tmpindex+RuntimeTypeSizes.short])
3618 dataSize = signatureLength + RuntimeTypeSizes.int + RuntimeTypeSizes.short
3619 dataSize = Utility.alignUp(dataSize, RuntimeTypeSizes.int)
3622 raise ProfileInconsistencyError()
3624 if ((index + rcdLen > len(bytesArr)) or ((rcdLen & 3) != 0)):
3625 raise ProfileInconsistencyError()
3627 return rcdTyp, rcdLen
3631 def createFromBytes(bytesArr):
3632 if (bytesArr is None or not issubclass(type(bytesArr), list)):
3633 raise InternalError()
3636 header = HeaderRecord.createFromBytes(bytesArr[index:index+HeaderRecord.Size])
3637 index += HeaderRecord.Size
3640 moduleOrMethodInfo = []
3642 while (index <= len(bytesArr) - RuntimeTypeSizes.int):
3643 rcdTyp, rcdLen = MCJProfile._getRecordTypeAndLen(bytesArr, index)
3645 if (rcdTyp == RuntimeConstants.MULTICOREJIT_MODULE_RECORD_ID):
3646 modules.append(ModuleRecordExtended.createFromBytes(bytesArr[index:index+rcdLen]))
3647 elif (rcdTyp == RuntimeConstants.MULTICOREJIT_MODULEDEPENDENCY_RECORD_ID):
3648 moduleOrMethodInfo.append(InfoModuleDependency.createFromBytes(bytesArr[index:index+rcdLen]))
3649 elif (rcdTyp == RuntimeConstants.MULTICOREJIT_METHOD_RECORD_ID):
3650 moduleOrMethodInfo.append(InfoNonGenericMethod.createFromBytes(bytesArr[index:index+rcdLen]))
3651 elif (rcdTyp == RuntimeConstants.MULTICOREJIT_GENERICMETHOD_RECORD_ID):
3652 moduleOrMethodInfo.append(InfoGenericMethod.createFromBytes(bytesArr[index:index+rcdLen]))
3654 raise InternalError()
3658 if (index != len(bytesArr)):
3659 raise ProfileInconsistencyError()
3661 return MCJProfile.createByRef(header, modules, moduleOrMethodInfo)
3663 # Create from objects taking them by reference
3665 def createByRef(header, modules, moduleOrMethodInfo):
3666 profile = MCJProfile()
3668 profile._header = header # pylint: disable=protected-access
3669 profile._modules = modules # pylint: disable=protected-access
3670 profile._moduleOrMethodInfo = moduleOrMethodInfo # pylint: disable=protected-access
3675 # Create from objects taking them by copy
3677 def createByCopy(header, modules, moduleOrMethodInfo):
3680 newModules.append(i.copy())
3682 newModuleOrMethodInfo = []
3683 for i in moduleOrMethodInfo:
3684 newModuleOrMethodInfo.append(i.copy())
3686 return MCJProfile.createByRef(header.copy(), newModules, newModuleOrMethodInfo)
3690 return MCJProfile.createByCopy(self._header, self._modules, self._moduleOrMethodInfo)
3692 # Convert object to list of bytes
3693 def convertToBytes(self):
3696 bytesArr += self._header.convertToBytes()
3698 for module in self._modules:
3699 bytesArr += module.convertToBytes()
3701 for info in self._moduleOrMethodInfo:
3702 bytesArr += info.convertToBytes()
3706 # Split mcj profile in two: app-dependent (app) and app-independent (system)
3707 def split(self, systemModules): # pylint: disable=too-many-locals,too-many-statements,too-many-branches
3708 if (systemModules is None or not issubclass(type(systemModules), list)):
3709 raise InternalError()
3711 for i in systemModules:
3713 raise InternalError()
3714 if (not issubclass(type(i), str)):
3715 raise InternalError()
3720 # App header at [0], sys header at [1]
3721 header = [self._header.copy(), self._header.copy()]
3722 # App modules at [0], sys modules at [1]
3724 # App moduleOrMethodInfo at [0], sys moduleOrMethodInfo at [1]
3725 moduleOrMethodInfo = [[], []]
3726 # App methodCount at [0], sys methodCount at [1]
3727 methodCount = [0, 0]
3728 # App moduleDepCount at [0], sys moduleDepCount at [1]
3729 moduleDepCount = [0, 0]
3731 # Map from old module index to flag, whether module should be added to:
3732 # app profile at [0], system profile at [1]
3733 moduleMap = [[False] * len(self._modules), [False] * len(self._modules)]
3734 # Map from old method info index to flag, whether method info should be added to:
3735 # app profile (True) or to sys profile (False)
3736 methodInfoAppMap = [False] * len(self._moduleOrMethodInfo)
3737 # Map from old module index to new module index in:
3738 # app profile at [0], system profile at [1]
3739 moduleIndexMap = [[None] * len(self._modules), [None] * len(self._modules)]
3741 # I. ==== Create map of system modules ====
3743 # Map from system module name to flag True
3744 systemModulesMap = {}
3745 for sysmodule in systemModules:
3746 systemModulesMap[sysmodule] = True
3748 # II. ==== Go through all modules and mark system modules ====
3750 for index, module in enumerate(self._modules):
3751 moduleMap[cIdxSys][index] = module.getModuleName() in systemModulesMap
3753 # III. ==== Go through all method infos and create lists of module indexes for system and app profiles
3755 for index, value in enumerate(moduleMap[cIdxSys]):
3756 moduleMap[cIdxApp][index] = not value
3758 for index, info in enumerate(self._moduleOrMethodInfo):
3759 if (info.isMethodInfo()):
3760 indexes = info.getAllModuleIndexes()
3763 if (not moduleMap[cIdxSys][i]):
3764 methodInfoAppMap[index] = True
3767 if (methodInfoAppMap[index]):
3768 # mark all modules as requiremens for app profile
3770 moduleMap[cIdxApp][i] = True
3772 # IV. === Go through all modules again and add to profiles accordingly ====
3774 for index, module in enumerate(self._modules):
3778 # add to app and system profiles
3780 if (moduleMap[i][index]):
3781 newModule = module.copy()
3782 moduleIndexMap[i][index] = len(modules[i])
3783 modules[i].append(newModule)
3787 raise InternalError()
3789 # V. ==== Go through all infos again and add to profiles accordingly ====
3791 for index, info in enumerate(self._moduleOrMethodInfo):
3794 # add to app and system profiles
3796 doAddModule = info.isModuleInfo() and moduleMap[i][info.getModuleIndex()]
3797 doAddMethodApp = (i == cIdxApp) and methodInfoAppMap[index]
3798 doAddMethodSys = (i == cIdxSys) and not methodInfoAppMap[index]
3800 doAdd = doAddModule or (info.isMethodInfo() and (doAddMethodApp or doAddMethodSys))
3803 if (info.isMethodInfo() and isAdded):
3804 raise InternalError()
3806 newInfo = info.copy()
3807 newInfo.updateModuleIndex(moduleIndexMap[i])
3808 moduleOrMethodInfo[i].append(newInfo)
3810 if (info.isModuleInfo()):
3811 moduleDepCount[i] += 1
3812 elif (info.isMethodInfo()):
3815 raise InternalError()
3820 raise InternalError()
3822 # VI. ==== Recalculate jitMethodCount ====
3824 for index in range(2):
3825 for module in modules[index]:
3826 module.getModuleRecord().setJitMethodCount(0)
3828 for info in moduleOrMethodInfo[index]:
3829 if (info.isMethodInfo()):
3830 indexes = info.getAllModuleIndexes()
3832 moduleRecord = modules[index][i].getModuleRecord()
3833 count = moduleRecord.getJitMethodCount()
3834 moduleRecord.setJitMethodCount(count + 1)
3836 # VII. ==== Initialize new headers ====
3838 for index in range(2):
3839 header[index].setModuleCount(len(modules[index]))
3840 header[index].setMethodCount(methodCount[index])
3841 header[index].setModuleDepCount(moduleDepCount[index])
3842 header[index].dropGlobalUsageStats()
3844 # VIII. ==== Perform some consistency checks ====
3846 if (methodCount[0] + methodCount[1] != self._header.getMethodCount()):
3847 raise InternalError()
3849 # IX. ==== Create new profiles ====
3851 mcjProfileApp = MCJProfile.createByRef(header[0], modules[0], moduleOrMethodInfo[0])
3852 mcjProfileSys = MCJProfile.createByRef(header[1], modules[1], moduleOrMethodInfo[1])
3854 return mcjProfileApp, mcjProfileSys
3856 # Merge new mcj profile with existing one
3857 def merge(self, mcjProfile): # pylint: disable=too-many-locals,too-many-statements
3858 if (mcjProfile is None or not issubclass(type(mcjProfile), MCJProfile)):
3859 raise InternalError()
3861 # Map from module name in self to module index
3863 # Map from str method representation to info index
3865 # Map from old module index in mcjProfile to previous max module level in self (if existed, otherwise None)
3866 moduleLoadLevelMap = [None] * len(mcjProfile.getModules())
3867 # Map from old module index in mcjProfile to new module index in self profile
3868 moduleIndexMap = [None] * len(mcjProfile.getModules())
3870 # I. ==== Create map of existing module names ====
3872 for index, module in enumerate(self._modules):
3873 moduleNameMap[module.getModuleName()] = index
3875 # II. ==== Merge modules ====
3877 # Merge modules: add new modules if needed, update max load level for existing modules
3878 for index, newmodule in enumerate(mcjProfile.getModules()):
3879 # check if modules match by simple name, because module search is performed by it
3880 existingModuleIndex = moduleNameMap.get(newmodule.getModuleName())
3882 if (not existingModuleIndex is None):
3883 # exists, update max load level (if load levels do not match, use max one)
3884 existingModule = self._modules[existingModuleIndex]
3886 if (existingModule.getAssemblyName() != newmodule.getAssemblyName()):
3887 print("Can't merge profiles: two modules with same names but different assembly names!")
3888 raise UnsupportedError()
3889 if (existingModule.getModuleRecord().getVersion() != newmodule.getModuleRecord().getVersion()):
3890 print("Can't merge profiles: two modules with same names but different versions!")
3891 raise UnsupportedError()
3892 if (existingModule.getModuleRecord().getFlags() != newmodule.getModuleRecord().getFlags()):
3893 print("Can't merge profiles: two modules with same names but different flags!")
3894 raise UnsupportedError()
3896 existingModuleLoadLevel = existingModule.getModuleRecord().getLoadLevel()
3897 moduleLoadLevelMap[index] = existingModuleLoadLevel
3898 moduleIndexMap[index] = existingModuleIndex
3899 existingModule.getModuleRecord().setLoadLevel(max(newmodule.getModuleRecord().getLoadLevel(),
3900 existingModuleLoadLevel))
3902 # simple module names do not match, safe to add new module
3903 moduleLoadLevelMap[index] = None
3904 moduleIndexMap[index] = len(self._modules)
3905 newmoduleToAdd = newmodule.copy()
3906 self._modules.append(newmoduleToAdd)
3908 # III. ==== Fill method map ====
3910 for module in self._modules:
3911 methodMap.append({})
3913 # Prepare map from method str representation to index of info
3914 for index, info in enumerate(self._moduleOrMethodInfo):
3915 moduleIndex = info.getModuleIndex()
3917 if (info.isNonGenericMethodInfo()):
3918 methodMap[moduleIndex][str(info.getMethodToken())] = index
3919 elif (info.isGenericMethodInfo()):
3920 methodMap[moduleIndex][info.getMethodHandle().getStr(self._modules)] = index
3922 # IV. ==== Merge infos ====
3924 # Merge module and method info (existing part of self doesn't change, simply add mcjProfile after self)
3925 for newinfo in mcjProfile.getModuleOrMethodInfo():
3926 if (newinfo.isMethodInfo()):
3929 newModuleIndex = moduleIndexMap[newinfo.getModuleIndex()]
3931 if (newinfo.isNonGenericMethodInfo()):
3932 infoIndex = methodMap[newModuleIndex].get(str(newinfo.getMethodToken()))
3933 elif (newinfo.isGenericMethodInfo()):
3934 infoIndex = methodMap[newModuleIndex].get(newinfo.getMethodHandle().getStr(mcjProfile.getModules()))
3936 raise InternalError()
3938 if (infoIndex is None):
3939 newinfoToAdd = newinfo.copy()
3940 newinfoToAdd.updateModuleIndex(moduleIndexMap)
3941 self._moduleOrMethodInfo.append(newinfoToAdd)
3943 if (newinfo.getMethodFlags() != self._moduleOrMethodInfo[infoIndex].getMethodFlags()):
3944 print("Can't merge profiles: two methods with same token/signature but different flags!")
3945 raise UnsupportedError()
3947 oldExistingLoadLevel = moduleLoadLevelMap[newinfo.getModuleIndex()]
3950 if ((not oldExistingLoadLevel is None) and oldExistingLoadLevel >= newinfo.getModuleLoadLevel()):
3951 # nothing to do, don't add module dependency, already loaded at required level
3954 newinfoToAdd = newinfo.copy()
3955 newinfoToAdd.updateModuleIndex(moduleIndexMap)
3956 self._moduleOrMethodInfo.append(newinfoToAdd)
3958 # IV. ==== Set stats ====
3963 # Reset method count
3964 for module in self._modules:
3965 module.getModuleRecord().setJitMethodCount(0)
3967 # Update stats in modules
3968 for info in self._moduleOrMethodInfo:
3969 if (info.isMethodInfo()):
3972 indexes = info.getAllModuleIndexes()
3974 moduleRecord = self._modules[i].getModuleRecord()
3975 count = moduleRecord.getJitMethodCount()
3976 moduleRecord.setJitMethodCount(count + 1)
3980 # update stats in headers
3981 self._header.setModuleCount(len(self._modules))
3982 self._header.setMethodCount(methodCount)
3983 self._header.setModuleDepCount(moduleDepCount)
3984 # new profile was not used yet, so drop usage stats
3985 self._header.dropGlobalUsageStats()
3989 # Find module by name
3990 def findModuleByName(self, moduleName):
3991 if (moduleName is None or not issubclass(type(moduleName), str)):
3992 raise InternalError()
3993 for module in self._modules:
3994 if (moduleName == module.getModuleName()):
3998 # Find method by token
3999 def findMethodByToken(self, methodToken):
4000 if (methodToken is None or not issubclass(type(methodToken), int)):
4001 raise InternalError()
4002 for moduleOrMethodInfo in self._moduleOrMethodInfo:
4003 if (moduleOrMethodInfo.isMethodInfo() and moduleOrMethodInfo.getMethodToken() == methodToken):
4004 return moduleOrMethodInfo
4007 # Read MCJ profile from file
4009 def readFromFile(inputFile):
4010 file = open(inputFile, "rb")
4011 bytesArr = list(file.read())
4014 mcjProfile = MCJProfile.createFromBytes(bytesArr)
4018 # Write MCJ profile to file
4020 def writeToFile(outputFile, mcjProfile):
4021 file = open(outputFile, "wb")
4022 file.write(bytearray(mcjProfile.convertToBytes()))
4025 # ----------------------------------------------------------------------------------------------------------------------
4028 # Constructor with command line arguments
4029 def __init__(self, args):
4032 # Split mcj profiles in two: app-dependent (app) and app-independent (system)
4033 def commandSplit(self):
4034 systemModulesFile = open(self._args.system_modules_list, "r")
4035 systemModules = systemModulesFile.readlines()
4036 systemModulesFile.close()
4038 for i, module in enumerate(systemModules):
4039 systemModules[i] = module.rstrip("\n")
4041 for filepath in self._args.input:
4042 outFilepathApp = filepath + ".app"
4043 outFilepathSys = filepath + ".sys"
4045 mcjProfile = MCJProfile.readFromFile(filepath)
4046 mcjProfileApp, mcjProfileSys = mcjProfile.split(systemModules)
4048 MCJProfile.writeToFile(outFilepathApp, mcjProfileApp)
4049 MCJProfile.writeToFile(outFilepathSys, mcjProfileSys)
4051 print("MCJ profile " + filepath + " was split in:")
4052 print(" 1. app-dependent " + outFilepathApp)
4053 print(" 2. app-independent " + outFilepathSys)
4056 # Merge mcj profiles
4057 def commandMerge(self):
4058 mcjProfileBase = MCJProfile.readFromFile(self._args.input[0])
4060 for index in range(1, len(self._args.input)):
4061 mcjProfile = MCJProfile.readFromFile(self._args.input[index])
4062 mcjProfileBase.merge(mcjProfile)
4064 MCJProfile.writeToFile(self._args.output, mcjProfileBase)
4066 print("MCJ profiles " + str(self._args.input) + " were merged in: " + self._args.output)
4069 # Verify mcj profiles format consistency
4070 def commandVerify(self):
4071 for filepath in self._args.input:
4072 mcjProfile = MCJProfile.readFromFile(filepath) # pylint: disable=unused-variable
4073 print("MCJ profile " + filepath + " is correct!")
4075 # Find module or method in mcj profile
4076 def commandFind(self):
4077 for filepath in self._args.input:
4078 mcjProfile = MCJProfile.readFromFile(filepath)
4080 if (not self._args.module is None):
4081 for module in self._args.module:
4082 if (not mcjProfile.findModuleByName(module) is None):
4083 print("MCJ profile " + filepath + " contains module " + module)
4085 print("MCJ profile " + filepath + " does not contain module " + module)
4087 if (not self._args.method_token is None):
4088 for method in self._args.method_token:
4089 methodToken = int(method)
4090 if (not mcjProfile.findMethodByToken(methodToken) is None):
4091 print("MCJ profile " + filepath + " contains method with token " + method)
4093 print("MCJ profile " + filepath + " does not contain method with token " + method)
4095 # Compare multiple mcj profiles for equality
4096 def commandCompare(self):
4097 if (self._args.sha256):
4098 resBase = subprocess.run(["sha256sum", self._args.input[0]], check=True,
4099 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
4100 shaBase = resBase.stdout.decode("ascii").split(" ")[0]
4101 for index in range(1, len(self._args.input)):
4102 res = subprocess.run(["sha256sum", self._args.input[index]], check=True,
4103 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
4104 sha = res.stdout.decode("ascii").split(" ")[0]
4105 resultStr = " are equal by hash." if sha == shaBase else " are not equal by hash."
4106 print("MCJ profiles " + self._args.input[0] + " and " + self._args.input[index] + resultStr)
4108 mcjProfileBase = MCJProfile.readFromFile(self._args.input[0])
4109 for index in range(1, len(self._args.input)):
4110 mcjProfile = MCJProfile.readFromFile(self._args.input[index])
4111 resultStr = " are equal." if mcjProfile == mcjProfileBase else " are not equal."
4112 print("MCJ profiles " + self._args.input[0] + " and " + self._args.input[index] + resultStr)
4114 # Clean usage stats in profile
4115 def commandCleanStats(self):
4116 for filepath in self._args.input:
4117 outfilepath = filepath + ".cleaned"
4119 mcjProfile = MCJProfile.readFromFile(filepath)
4120 mcjProfile.getHeader().dropGlobalUsageStats()
4121 MCJProfile.writeToFile(outfilepath, mcjProfile)
4123 print("Cleaned usage stats: " + filepath + " is saved as " + outfilepath)
4126 def commandPrint(self):
4127 for filepath in self._args.input:
4128 print("============ MCJ profile " + filepath + " ============")
4129 mcjProfile = MCJProfile.readFromFile(filepath)
4131 doPrintModuleDeps = self._args.module_deps
4132 doPrintGenericMethods = self._args.methods or self._args.generics
4133 doPrintNonGenericMethods = self._args.methods or self._args.non_generics
4134 doPrintModuleOrMethodInfo = doPrintModuleDeps or doPrintGenericMethods or doPrintNonGenericMethods
4136 if (self._args.raw):
4137 # Print raw mcj profile
4138 if (self._args.header):
4139 mcjProfile.printRawHeader()
4140 if (self._args.modules):
4141 mcjProfile.printRawModules()
4142 if (doPrintModuleOrMethodInfo):
4143 mcjProfile.printRawModuleOrMethodInfo("", doPrintModuleDeps, doPrintGenericMethods,
4144 doPrintNonGenericMethods)
4145 if (not self._args.header and not self._args.modules and not doPrintModuleOrMethodInfo):
4146 mcjProfile.printRaw()
4148 # Pretty-print mcj profile
4149 if (self._args.header):
4150 mcjProfile.printHeader()
4151 if (self._args.modules):
4152 mcjProfile.printModules()
4153 if (doPrintModuleOrMethodInfo):
4154 mcjProfile.printModuleOrMethodInfo("", doPrintModuleDeps, doPrintGenericMethods,
4155 doPrintNonGenericMethods)
4156 if (not self._args.header and not self._args.modules and not doPrintModuleOrMethodInfo):
4159 # Show short summary on mcj profile format
4160 def commandHelp(self): # pylint: disable=no-self-use,too-many-statements
4161 print("! To show command options help use --help option !")
4164 if (self._args.mcj_format):
4165 print(">>> MCJ format help.")
4167 print("MCJ file is a binary file with next sections:")
4168 print("1. Header, i.e. 'HeaderRecord'")
4169 print("2. Modules, i.e. multiple 'ModuleRecord'")
4170 print("3. Methods and Module dependencies, i.e. multiple 'JitInfRecord':")
4171 print(" 'ModuleDependency', 'GenericMethod', 'NonGenericMethod'")
4175 print("Header contains:")
4176 print("1. MULTICOREJIT_HEADER_RECORD_ID tag")
4177 print("2. Version of profile, MULTICOREJIT_PROFILE_VERSION")
4178 print("3. Number of used modules, module dependencies and methods")
4179 print("4. Profile usage stats (0 if profile was not written after usage)")
4181 print("II. Modules.")
4183 print("These section contains multiple ModuleRecord, each ModuleRecord contains:")
4184 print("1. MULTICOREJIT_MODULE_RECORD_ID tag")
4185 print("2. Module version")
4186 print("3. Number of methods from module in profile")
4187 print("4. Final load level for module")
4188 print("5. Simple name of module")
4189 print("6. Assembly name")
4191 print("III. Modules and Methods dependencies")
4193 print("This section contains multiple JitInfRecord, each JitInfRecord can be:")
4194 print(" Module dependency, non-generic Method or generic Method.")
4196 print("Each Module dependency contains:")
4197 print("1. Module index")
4198 print("2. Current module load level")
4199 print("3. MULTICOREJIT_MODULEDEPENDENCY_RECORD_ID tag")
4201 print("Each non-generic Method contains:")
4202 print("1. Module index")
4203 print("2. Method flags")
4204 print("3. MULTICOREJIT_METHOD_RECORD_ID tag")
4205 print("4. Method token from dll")
4207 print("Each generic Method contains:")
4208 print("1. Module index")
4209 print("2. Method flags")
4210 print("3. MULTICOREJIT_GENERICMETHOD_RECORD_ID tag")
4211 print("4. Length of binary signature for method")
4212 print("5. Binary signature for method")
4213 elif (self._args.binary_signature_format):
4214 print(">>> Binary signature format help.")
4216 print("I. Value encoding")
4218 print("Binary signature for method (as well as binary signature for type) is a byte array.")
4220 print("Each value that is stored in this byte array is compacted (see _encodeValue) (except plain bytes):")
4221 print(" - values '<= 0x7f' are stored as 1 byte without changes")
4222 print(" - values '> 0x7f and <= 0x3fff' are stored as 2 bytes in big endian order (1st byte | 0x80)")
4223 print(" - values '> 0x3fff and <= 0x1fffffff' are stored as 4 bytes in big endian order (1st byte | 0xc0)")
4224 print("As a result of this 3 high bits of 1st byte determine length of value:")
4225 print(" - 0yz mean 1 byte")
4226 print(" - 10y mean 2 bytes")
4227 print(" - 110 mean 4 bytes")
4228 print("As mentioned above, sometimes plain bytes are saved (see _encodeByte).")
4230 print("Tokens (method, type, etc.) are stored as plain values (see above) or tokens (see _encodeToken):")
4231 print(" 1. rid and typ are obtained from token")
4232 print(" 2. rid is shifted left on 2 bits")
4233 print(" 3. rid is ORed with special 2bit constant determined by typ")
4234 print(" 4. resulting modified rid goes through value encoding procedure above")
4235 print("As a result of this typ of token is determined by 2 lowest bits of saved value.")
4237 print("II. Type signature encoding")
4239 print("Each type is encoded using logic mentioned in previous section.")
4241 print("This logic is pretty complex, but main building blocks of all types are:")
4242 print(" - other types")
4243 print(" - type tokens")
4244 print(" - calling convention")
4245 print(" - number of func args")
4246 print(" - number of generic args")
4247 print(" - array rank")
4248 print(" - module index <-- this is module index in array of modules that are processed by MCJ!")
4249 print("For more details see source code (see _encodeSignatureForTypeHandle).")
4251 print("III. Method signature encoding")
4253 print("Each method is encoded using logic mentioned in previous section.")
4255 print("Method encoding order:")
4256 print(" 1. Method flags")
4257 print(" 2. Type from which this method comes from")
4258 print(" 3. Method token")
4259 print(" 4*. Number of method instantion args (for generic methods)")
4260 print(" 5*. Types of all method instantion args (for generic methods)")
4261 print("For more details see source code (see encodeMethod).")
4263 print("! To show format help use --mcj-format or --binary-signature-format options !")
4265 # Perform various self testing
4266 def commandSelfTest(self): # pylint: disable=too-many-locals,too-many-statements
4268 # Read mcj profile, write it to file, read it back again and compare
4269 for filepath in self._args.input:
4270 outFilepath = filepath + ".__tmp"
4271 mcjProfileIn = MCJProfile.readFromFile(filepath)
4272 MCJProfile.writeToFile(outFilepath, mcjProfileIn)
4273 mcjProfileOut = MCJProfile.readFromFile(outFilepath)
4274 if (mcjProfileIn == mcjProfileOut):
4275 print("Read-write self test passed for " + filepath)
4277 print("Read-write self test failed for " + filepath)
4278 elif (self._args.rw_sha256):
4279 # Read mcj profile, write it to file, compare with sha256sum with original file
4280 for filepath in self._args.input:
4281 outFilepath = filepath + ".__tmp"
4282 mcjProfile = MCJProfile.readFromFile(filepath)
4283 MCJProfile.writeToFile(outFilepath, mcjProfile)
4285 inputRes = subprocess.run(["sha256sum", filepath], check=True,
4286 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
4287 outputRes = subprocess.run(["sha256sum", outFilepath], check=True,
4288 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
4290 inputSha = inputRes.stdout.decode("ascii").split(" ")[0]
4291 outputSha = outputRes.stdout.decode("ascii").split(" ")[0]
4293 if (inputSha == outputSha):
4294 print("Read-write sha256sum self test passed for " + filepath)
4296 print("Read-write sha256sum self test failed for " + filepath)
4297 elif (self._args.sm):
4298 # Split mcj profile, merge two resulting profiles, split again and compare
4299 systemModulesFile = open(self._args.system_modules_list, "r")
4300 systemModules = systemModulesFile.readlines()
4301 systemModulesFile.close()
4303 for i, moduleName in enumerate(systemModules):
4304 systemModules[i] = moduleName.rstrip("\n")
4306 for filepath in self._args.input:
4307 mcjProfile = MCJProfile.readFromFile(filepath)
4308 mcjProfileApp, mcjProfileSys = mcjProfile.split(systemModules)
4310 prevMergedAppFirst = mcjProfile
4311 prevMergedSysFirst = mcjProfile
4312 prevSplitAppFirstApp = mcjProfileApp
4313 prevSplitAppFirstSys = mcjProfileSys
4314 prevSplitSysFirstApp = mcjProfileApp
4315 prevSplitSysFirstSys = mcjProfileSys
4320 # Note: first split&merge won't match because order changes, but it stabilizes on 2nd merge
4321 for depth in range(1,5):
4322 # Merge two prev profiles
4323 mergedAppFirst = prevSplitAppFirstApp.copy()
4324 mergedAppFirst.merge(prevSplitAppFirstSys)
4326 mergedSysFirst = prevSplitSysFirstSys.copy()
4327 mergedSysFirst.merge(prevSplitSysFirstApp)
4329 if (depth > depthCheck
4330 and (mergedAppFirst != prevMergedAppFirst or mergedSysFirst != prevMergedSysFirst)):
4334 prevMergedAppFirst = mergedAppFirst
4335 prevMergedSysFirst = mergedSysFirst
4337 mergedAppFirst2 = mergedAppFirst.copy()
4338 mergedAppFirst2.merge(mergedSysFirst)
4340 mergedSysFirst2 = mergedSysFirst.copy()
4341 mergedSysFirst2.merge(mergedAppFirst)
4343 if (mergedAppFirst2 != mergedAppFirst or mergedSysFirst2 != mergedSysFirst):
4347 # Split cur profiles
4348 splitAppFirstApp, splitAppFirstSys = mergedAppFirst.split(systemModules)
4349 splitSysFirstApp, splitSysFirstSys = mergedSysFirst.split(systemModules)
4351 if (depth > depthCheck
4352 and (splitAppFirstApp != prevSplitAppFirstApp or splitAppFirstSys != prevSplitAppFirstSys
4353 or splitSysFirstApp != prevSplitSysFirstApp or splitSysFirstSys != prevSplitSysFirstSys)):
4357 prevSplitAppFirstApp = splitAppFirstApp
4358 prevSplitAppFirstSys = splitAppFirstSys
4359 prevSplitSysFirstApp = splitSysFirstApp
4360 prevSplitSysFirstSys = splitSysFirstSys
4362 splitAppFirstApp2, splitAppFirstSys2 = splitAppFirstApp.split(systemModules)
4364 if (splitAppFirstApp2 != splitAppFirstApp):
4368 splitAppFirstApp2, splitAppFirstSys2 = splitAppFirstSys.split(systemModules)
4370 if (splitAppFirstSys2 != splitAppFirstSys):
4374 splitSysFirstApp2, splitSysFirstSys2 = splitSysFirstApp.split(systemModules)
4376 if (splitSysFirstApp2 != splitSysFirstApp):
4380 splitSysFirstApp2, splitSysFirstSys2 = splitSysFirstSys.split(systemModules)
4382 if (splitSysFirstSys2 != splitSysFirstSys):
4387 print("Split-merge self test passed for " + filepath)
4389 print("Split-merge self test failed for " + filepath)
4390 elif (self._args.unit):
4391 # TODO: add unit tests
4396 # ----------------------------------------------------------------------------------------------------------------------
4399 parser = argparse.ArgumentParser()
4401 commands = "split, merge, verify, find, compare, clean-stats, print, help, self-test"
4403 parser.add_argument("command", help="Command to execute: " + commands)
4406 parser.add_argument("-i", "--input", help="Input mcj profiles", action="append")
4409 parser.add_argument("--system-modules-list", help="[split], file with app-independent (i.e. system) module names")
4412 parser.add_argument("-o", "--output", help="[merge], output mcj profile")
4415 parser.add_argument("--module", help="[find], name of module to find in mcj profile", action="append")
4416 parser.add_argument("--method-token", help="[find], token of method to find in mcj profile", action="append")
4419 parser.add_argument("--sha256", help="[compare], compare mcj profiles using sha256sum", action="store_true")
4422 parser.add_argument("--raw", help="[print], print raw mcj profile", action="store_true")
4423 parser.add_argument("--header", help="[print], print header of mcj profile", action="store_true")
4424 parser.add_argument("--modules", help="[print], print modules in mcj profile", action="store_true")
4426 parser.add_argument("--methods", help="[print], print methods in mcj profile", action="store_true")
4427 parser.add_argument("--generics", help="[print], print generic methods in mcj profile", action="store_true")
4428 parser.add_argument("--non-generics", help="[print], print non-generic methods in mcj profile", action="store_true")
4429 parser.add_argument("--module-deps", help="[print], print module dependencies in mcj profile", action="store_true")
4432 parser.add_argument("--mcj-format", help="[help], show help on mcj format", action="store_true")
4433 parser.add_argument("--binary-signature-format", help="[help], show help on binary signature format",
4434 action="store_true")
4437 parser.add_argument("--rw", help="[self-test], perform read-write self-test", action="store_true")
4438 parser.add_argument("--rw-sha256",
4439 help="[self-test], perform read-write self-test using sha256sum", action="store_true")
4440 parser.add_argument("--sm", help="[self-test], perform split-merge self-test", action="store_true")
4441 parser.add_argument("--unit", help="TODO, [self-test], perform unit testing self-test", action="store_true")
4443 args = parser.parse_args()
4447 if (args.command == "split"):
4449 elif (args.command == "merge"):
4451 elif (args.command == "verify"):
4453 elif (args.command == "find"):
4455 elif (args.command == "compare"):
4456 cli.commandCompare()
4457 elif (args.command == "clean-stats"):
4458 cli.commandCleanStats()
4459 elif (args.command == "print"):
4461 elif (args.command == "help"):
4463 elif (args.command == "self-test"):
4464 cli.commandSelfTest()
4466 if __name__ == "__main__":