Nav apraksta
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

BurstDisassembler.Core.cs 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. #if UNITY_EDITOR || BURST_INTERNAL
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Runtime.CompilerServices;
  5. namespace Unity.Burst.Editor
  6. {
  7. internal partial class BurstDisassembler
  8. {
  9. /// <summary>
  10. /// Base class for providing extended information of an identifier
  11. /// </summary>
  12. private abstract class AsmTokenKindProvider
  13. {
  14. // Internally using string slice instead of string
  15. // to support faster lookup from AsmToken
  16. private readonly Dictionary<StringSlice, AsmTokenKind> _tokenKinds;
  17. private int _maximumLength;
  18. protected AsmTokenKindProvider(int capacity)
  19. {
  20. _tokenKinds = new Dictionary<StringSlice, AsmTokenKind>(capacity);
  21. }
  22. protected void AddTokenKind(string text, AsmTokenKind kind)
  23. {
  24. _tokenKinds.Add(new StringSlice(text), kind);
  25. if (text.Length > _maximumLength) _maximumLength = text.Length;
  26. }
  27. public AsmTokenKind FindTokenKind(StringSlice slice)
  28. {
  29. return slice.Length <= _maximumLength && _tokenKinds.TryGetValue(slice, out var tokenKind) ? tokenKind : AsmTokenKind.Identifier;
  30. }
  31. public virtual bool AcceptsCharAsIdentifierOrRegisterEnd(char c)
  32. {
  33. return false;
  34. }
  35. }
  36. /// <summary>
  37. /// The ASM tokenizer
  38. /// </summary>
  39. private struct AsmTokenizer
  40. {
  41. private readonly string _text;
  42. private readonly AsmKind _asmKind;
  43. private readonly AsmTokenKindProvider _tokenKindProvider;
  44. private int _position;
  45. private int _nextPosition;
  46. private char _c;
  47. private readonly char _commentStartChar;
  48. public AsmTokenizer(string text, AsmKind asmKind, AsmTokenKindProvider tokenKindProvider)
  49. {
  50. _text = text;
  51. _asmKind = asmKind;
  52. _tokenKindProvider = tokenKindProvider;
  53. _position = 0;
  54. _nextPosition = 0;
  55. _commentStartChar = (asmKind == AsmKind.Intel || asmKind == AsmKind.Wasm) ? '#' : ';';
  56. _c = (char)0;
  57. NextChar();
  58. }
  59. public bool TryGetNextToken(out AsmToken token)
  60. {
  61. token = new AsmToken();
  62. while (true)
  63. {
  64. var startPosition = _position;
  65. if (_c == 0)
  66. {
  67. return false;
  68. }
  69. if (_c == '.')
  70. {
  71. token = ParseDirective(startPosition);
  72. return true;
  73. }
  74. // Like everywhere else in this file, we are inlining the matching characters instead
  75. // of using helper functions, as Mono might not be enough good at inlining by itself
  76. if (_c >= 'a' && _c <= 'z' || _c >= 'A' && _c <= 'Z' || _c == '_' || _c == '@')
  77. {
  78. token = ParseInstructionOrIdentifierOrRegister(startPosition);
  79. return true;
  80. }
  81. if (_c >= '0' && _c <= '9' || _c == '-')
  82. {
  83. token = ParseNumber(startPosition);
  84. return true;
  85. }
  86. if (_c == '"')
  87. {
  88. token = ParseString(startPosition);
  89. return true;
  90. }
  91. if (_c == _commentStartChar)
  92. {
  93. token = ParseComment(startPosition);
  94. return true;
  95. }
  96. if (_c == '\r')
  97. {
  98. if (PreviewChar() == '\n')
  99. {
  100. NextChar(); // skip \r
  101. }
  102. token = ParseNewLine(startPosition);
  103. return true;
  104. }
  105. if (_c == '\n')
  106. {
  107. token = ParseNewLine(startPosition);
  108. return true;
  109. }
  110. token = ParseMisc(startPosition);
  111. return true;
  112. }
  113. }
  114. private AsmToken ParseNewLine(int startPosition)
  115. {
  116. var endPosition = _position;
  117. NextChar(); // Skip newline
  118. return new AsmToken(AsmTokenKind.NewLine, startPosition, endPosition - startPosition + 1);
  119. }
  120. private AsmToken ParseMisc(int startPosition)
  121. {
  122. var endPosition = _position;
  123. // Parse anything that is not a directive, instruction, number, string or comment
  124. while (!((_c == (char)0) || (_c == '\r') || (_c == '\n') || (_c == '.') || (_c >= 'a' && _c <= 'z' || _c >= 'A' && _c <= 'Z' || _c == '_' || _c == '@') || (_c >= '0' && _c <= '9' || _c == '-') || (_c == '"') || (_c == _commentStartChar)))
  125. {
  126. endPosition = _position;
  127. NextChar();
  128. }
  129. return new AsmToken(AsmTokenKind.Misc, startPosition, endPosition - startPosition + 1);
  130. }
  131. private AsmToken ParseDirective(int startPosition)
  132. {
  133. var endPosition = _position;
  134. while (_c >= 'a' && _c <= 'z' || _c >= 'A' && _c <= 'Z' || _c >= '0' && _c <= '9' || _c == '.' || _c == '_' || _c == '@')
  135. {
  136. endPosition = _position;
  137. NextChar();
  138. }
  139. return new AsmToken(AsmTokenKind.Directive, startPosition, endPosition - startPosition + 1);
  140. }
  141. private AsmToken ParseInstructionOrIdentifierOrRegister(int startPosition)
  142. {
  143. var endPosition = _position;
  144. while (_c >= 'a' && _c <= 'z' || _c >= 'A' && _c <= 'Z' || _c >= '0' && _c <= '9' || _c == '_' || _c == '@')
  145. {
  146. endPosition = _position;
  147. NextChar();
  148. }
  149. if (_tokenKindProvider.AcceptsCharAsIdentifierOrRegisterEnd(_c))
  150. {
  151. endPosition = _position;
  152. NextChar();
  153. }
  154. // Resolve token kind for identifier
  155. int length = endPosition - startPosition + 1;
  156. var tokenKind = _tokenKindProvider.FindTokenKind(new StringSlice(_text, startPosition, length));
  157. return new AsmToken(tokenKind, startPosition, endPosition - startPosition + 1);
  158. }
  159. private AsmToken ParseNumber(int startPosition)
  160. {
  161. var endPosition = _position;
  162. if (_c == '-')
  163. {
  164. NextChar();
  165. }
  166. while (_c >= '0' && _c <= '9' || _c >= 'a' && _c <= 'f' || _c >= 'A' && _c <= 'F' || _c == 'x' || _c == '.')
  167. {
  168. endPosition = _position;
  169. NextChar();
  170. }
  171. return new AsmToken(AsmTokenKind.Number, startPosition, endPosition - startPosition + 1);
  172. }
  173. private AsmToken ParseString(int startPosition)
  174. {
  175. var endPosition = _position;
  176. // Skip first "
  177. NextChar();
  178. while (_c != (char)0 && _c != '"')
  179. {
  180. // Skip escape \"
  181. if (_c == '\\' && PreviewChar() == '"')
  182. {
  183. NextChar();
  184. }
  185. endPosition = _position;
  186. NextChar();
  187. }
  188. endPosition = _position;
  189. NextChar(); // Skip trailing 0
  190. return new AsmToken(AsmTokenKind.String, startPosition, endPosition - startPosition + 1);
  191. }
  192. private AsmToken ParseComment(int startPosition)
  193. {
  194. var endPosition = _position;
  195. while (_c != (char)0 && (_c != '\n' && _c != '\r'))
  196. {
  197. endPosition = _position;
  198. NextChar();
  199. }
  200. return new AsmToken(AsmTokenKind.Comment, startPosition, endPosition - startPosition + 1);
  201. }
  202. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  203. private void NextChar()
  204. {
  205. if (_nextPosition < _text.Length)
  206. {
  207. _position = _nextPosition;
  208. _c = _text[_position];
  209. _nextPosition = _position + 1;
  210. }
  211. else
  212. {
  213. _c = (char)0;
  214. }
  215. }
  216. private char PreviewChar()
  217. {
  218. return _nextPosition < _text.Length ? _text[_nextPosition] : (char)0;
  219. }
  220. }
  221. /// <summary>
  222. /// A slice of a string from an original string.
  223. /// </summary>
  224. public struct StringSlice : IEquatable<StringSlice>
  225. {
  226. private readonly string _text;
  227. public readonly int Position;
  228. public readonly int Length;
  229. public StringSlice(string text)
  230. {
  231. _text = text ?? throw new ArgumentNullException(nameof(text));
  232. Position = 0;
  233. Length = text.Length;
  234. }
  235. public StringSlice(string text, int position, int length)
  236. {
  237. _text = text ?? throw new ArgumentNullException(nameof(text));
  238. Position = position;
  239. Length = length;
  240. }
  241. public char this[int index] => _text[Position + index];
  242. public bool Equals(StringSlice other)
  243. {
  244. if (Length != other.Length) return false;
  245. for (int i = 0; i < Length; i++)
  246. {
  247. if (this[i] != other[i])
  248. {
  249. return false;
  250. }
  251. }
  252. return true;
  253. }
  254. public override bool Equals(object obj)
  255. {
  256. return obj is StringSlice other && Equals(other);
  257. }
  258. public override int GetHashCode()
  259. {
  260. unchecked
  261. {
  262. var hashCode = Length;
  263. for (int i = 0; i < Length; i++)
  264. {
  265. hashCode = (hashCode * 397) ^ this[i];
  266. }
  267. return hashCode;
  268. }
  269. }
  270. public static bool operator ==(StringSlice left, StringSlice right)
  271. {
  272. return left.Equals(right);
  273. }
  274. public static bool operator !=(StringSlice left, StringSlice right)
  275. {
  276. return !left.Equals(right);
  277. }
  278. public override string ToString()
  279. {
  280. return _text.Substring(Position, Length);
  281. }
  282. }
  283. /// <summary>
  284. /// An ASM token. The token doesn't contain the string of the token, but provides method <see cref="Slice"/> and <see cref="ToString"/> to extract it.
  285. /// </summary>
  286. internal struct AsmToken
  287. {
  288. public AsmToken(AsmTokenKind kind, int position, int length)
  289. {
  290. Kind = kind;
  291. Position = position;
  292. Length = length;
  293. }
  294. public readonly AsmTokenKind Kind;
  295. public readonly int Position;
  296. public readonly int Length;
  297. public StringSlice Slice(string text) => new StringSlice(text, Position, Length);
  298. public string ToString(string text) => text.Substring(Position, Length);
  299. public string ToFriendlyText(string text)
  300. {
  301. return $"{text.Substring(Position, Length)} : {Kind}";
  302. }
  303. }
  304. /// <summary>
  305. /// Kind of an ASM token.
  306. /// </summary>
  307. internal enum AsmTokenKind
  308. {
  309. Eof,
  310. Directive,
  311. Identifier,
  312. Qualifier,
  313. Instruction,
  314. InstructionSIMD,
  315. Register,
  316. Number,
  317. String,
  318. Comment,
  319. NewLine,
  320. Misc
  321. }
  322. }
  323. }
  324. #endif