Instruction.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. using System.Runtime.CompilerServices;
  2. namespace Lua.Runtime;
  3. public struct Instruction : IEquatable<Instruction>
  4. {
  5. uint _value;
  6. public uint Value
  7. {
  8. get => _value;
  9. set => _value = value;
  10. }
  11. public OpCode OpCode
  12. {
  13. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  14. get => (OpCode)(byte)(_value & 0x3F); // 6 bits
  15. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  16. set => _value = (_value & 0xFFFFFFC0) | ((uint)value & 0x3F);
  17. }
  18. public byte A
  19. {
  20. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  21. get => (byte)((_value >> 6)); // 8 bits
  22. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  23. set => _value = (_value & 0xFFFFC03F) | (((uint)value & 0xFF) << 6);
  24. }
  25. public ushort B
  26. {
  27. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  28. get => (ushort)((_value >> 23) & 0x1FF); // 9 bits
  29. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  30. set => _value = (_value & 0xC07FFFFF) | (((uint)value & 0x1FF) << 23);
  31. }
  32. internal uint UIntB
  33. {
  34. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  35. get => (_value >> 23) & 0x1FF; // 9 bits
  36. }
  37. public ushort C
  38. {
  39. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  40. get => (ushort)((_value >> 14) & 0x1FF); // 9 bits
  41. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  42. set => _value = (_value & 0xFF803FFF) | (((uint)value & 0x1FF) << 14);
  43. }
  44. internal uint UIntC
  45. {
  46. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  47. get => (_value >> 14) & 0x1FF; // 9 bits
  48. }
  49. public uint Bx
  50. {
  51. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  52. get => (_value >> 14) & 0x3FFFF; // 18 bits (14-31)
  53. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  54. set => _value = (_value & 0x00003FFF) | ((value & 0x3FFFF) << 14);
  55. }
  56. public int SBx
  57. {
  58. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  59. get => (int)(Bx - 131071); // signed 18 bits
  60. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  61. set => Bx = (uint)(value + 131071);
  62. }
  63. public uint Ax
  64. {
  65. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  66. get => (_value >> 6) & 0x3FFFFFF; // 26 bits (6-31)
  67. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  68. set => _value = (_value & 0x0000003F) | ((value & 0x3FFFFFF) << 6);
  69. }
  70. public bool Equals(Instruction other)
  71. {
  72. return _value == other._value;
  73. }
  74. public override bool Equals(object? obj)
  75. {
  76. if (obj is Instruction instruction) return Equals(instruction);
  77. return false;
  78. }
  79. public override int GetHashCode()
  80. {
  81. return _value.GetHashCode();
  82. }
  83. public override string ToString()
  84. {
  85. return OpCode switch
  86. {
  87. OpCode.Move => $"MOVE {A} {B}",
  88. OpCode.LoadK => $"LOADK {A} {Bx}",
  89. OpCode.LoadKX => $"LOADKX {A}",
  90. OpCode.LoadBool => $"LOADBOOL {A} {B} {C}",
  91. OpCode.LoadNil => $"LOADNIL {A} {B}",
  92. OpCode.GetUpVal => $"GETUPVAL {A} {B}",
  93. OpCode.GetTabUp => $"GETTABUP {A} {B} {C}",
  94. OpCode.GetTable => $"GETTABLE {A} {B} {C}",
  95. OpCode.SetTabUp => $"SETTABUP {A} {B} {C}",
  96. OpCode.SetUpVal => $"SETUPVAL {A} {B}",
  97. OpCode.SetTable => $"SETTABLE {A} {B} {C}",
  98. OpCode.NewTable => $"NEWTABLE {A} {B} {C}",
  99. OpCode.Self => $"SELF {A} {B} {C}",
  100. OpCode.Add => $"ADD {A} {B} {C}",
  101. OpCode.Sub => $"SUB {A} {B} {C}",
  102. OpCode.Mul => $"MUL {A} {B} {C}",
  103. OpCode.Div => $"DIV {A} {B} {C}",
  104. OpCode.Mod => $"MOD {A} {B} {C}",
  105. OpCode.Pow => $"POW {A} {B} {C}",
  106. OpCode.Unm => $"UNM {A} {B}",
  107. OpCode.Not => $"NOT {A} {B}",
  108. OpCode.Len => $"LEN {A} {B}",
  109. OpCode.Concat => $"CONCAT {A} {B} {C}",
  110. OpCode.Jmp => $"JMP {A} {SBx}",
  111. OpCode.Eq => $"EQ {A} {B} {C}",
  112. OpCode.Lt => $"LT {A} {B} {C}",
  113. OpCode.Le => $"LE {A} {B} {C}",
  114. OpCode.Test => $"TEST {A} {C}",
  115. OpCode.TestSet => $"TESTSET {A} {B} {C}",
  116. OpCode.Call => $"CALL {A} {B} {C}",
  117. OpCode.TailCall => $"TAILCALL {A} {B} {C}",
  118. OpCode.Return => $"RETURN {A} {B}",
  119. OpCode.ForLoop => $"FORLOOP {A} {SBx}",
  120. OpCode.ForPrep => $"FORPREP {A} {SBx}",
  121. OpCode.TForCall => $"TFORCALL {A} {C}",
  122. OpCode.TForLoop => $"TFORLOOP {A} {SBx}",
  123. OpCode.SetList => $"SETLIST {A} {B} {C}",
  124. OpCode.Closure => $"CLOSURE {A} {SBx}",
  125. OpCode.VarArg => $"VARARG {A} {B}",
  126. OpCode.ExtraArg => $"EXTRAARG {Ax}",
  127. _ => "",
  128. };
  129. }
  130. public static bool operator ==(Instruction left, Instruction right)
  131. {
  132. return left.Equals(right);
  133. }
  134. public static bool operator !=(Instruction left, Instruction right)
  135. {
  136. return !(left == right);
  137. }
  138. /// <summary>
  139. /// R(A) := R(B)
  140. /// </summary>
  141. public static Instruction Move(byte a, ushort b)
  142. {
  143. return new()
  144. {
  145. OpCode = OpCode.Move,
  146. A = a,
  147. B = b,
  148. };
  149. }
  150. /// <summary>
  151. /// R(A) := Kst(Bx)
  152. /// </summary>
  153. public static Instruction LoadK(byte a, uint bx)
  154. {
  155. return new()
  156. {
  157. OpCode = OpCode.LoadK,
  158. A = a,
  159. Bx = bx,
  160. };
  161. }
  162. /// <summary>
  163. /// R(A) := Kst(extra arg)
  164. /// </summary>
  165. public static Instruction LoadKX(byte a)
  166. {
  167. return new()
  168. {
  169. OpCode = OpCode.LoadKX,
  170. A = a,
  171. };
  172. }
  173. /// <summary>
  174. /// <para>R(A) := (Bool)B</para>
  175. /// <para>if (C) pc++</para>
  176. /// </summary>
  177. public static Instruction LoadBool(byte a, ushort b, ushort c)
  178. {
  179. return new()
  180. {
  181. OpCode = OpCode.LoadBool,
  182. A = a,
  183. B = b,
  184. C = c,
  185. };
  186. }
  187. /// <summary>
  188. /// R(A), R(A+1), ..., R(A+B) := nil
  189. /// </summary>
  190. public static Instruction LoadNil(byte a, ushort b)
  191. {
  192. return new()
  193. {
  194. OpCode = OpCode.LoadNil,
  195. A = a,
  196. B = b,
  197. };
  198. }
  199. /// <summary>
  200. /// R(A) := UpValue[B]
  201. /// </summary>
  202. public static Instruction GetUpVal(byte a, ushort b)
  203. {
  204. return new()
  205. {
  206. OpCode = OpCode.GetUpVal,
  207. A = a,
  208. B = b,
  209. };
  210. }
  211. /// <summary>
  212. /// R(A) := UpValue[B][RK(C)]
  213. /// </summary>
  214. public static Instruction GetTabUp(byte a, ushort b, ushort c)
  215. {
  216. return new()
  217. {
  218. OpCode = OpCode.GetTabUp,
  219. A = a,
  220. B = b,
  221. C = c,
  222. };
  223. }
  224. /// <summary>
  225. /// R(A) := R(B)[RK(C)]
  226. /// </summary>
  227. public static Instruction GetTable(byte a, ushort b, ushort c)
  228. {
  229. return new()
  230. {
  231. OpCode = OpCode.GetTable,
  232. A = a,
  233. B = b,
  234. C = c,
  235. };
  236. }
  237. /// <summary>
  238. /// UpValue[B] := R(A)
  239. /// </summary>
  240. public static Instruction SetUpVal(byte a, ushort b)
  241. {
  242. return new()
  243. {
  244. OpCode = OpCode.SetUpVal,
  245. A = a,
  246. B = b,
  247. };
  248. }
  249. /// <summary>
  250. /// UpValue[A][RK(B)] := RK(C)
  251. /// </summary>
  252. public static Instruction SetTabUp(byte a, ushort b, ushort c)
  253. {
  254. return new()
  255. {
  256. OpCode = OpCode.SetTabUp,
  257. A = a,
  258. B = b,
  259. C = c,
  260. };
  261. }
  262. /// <summary>
  263. /// R(A)[RK(B)] := RK(C)
  264. /// </summary>
  265. public static Instruction SetTable(byte a, ushort b, ushort c)
  266. {
  267. return new()
  268. {
  269. OpCode = OpCode.SetTable,
  270. A = a,
  271. B = b,
  272. C = c,
  273. };
  274. }
  275. /// <summary>
  276. /// R(A) := {} (size = B,C)
  277. /// </summary>
  278. public static Instruction NewTable(byte a, ushort b, ushort c)
  279. {
  280. return new()
  281. {
  282. OpCode = OpCode.NewTable,
  283. A = a,
  284. B = b,
  285. C = c,
  286. };
  287. }
  288. /// <summary>
  289. /// R(A+1) := R(B); R(A) := R(B)[RK(C)]
  290. /// </summary>
  291. public static Instruction Self(byte a, ushort b, ushort c)
  292. {
  293. return new()
  294. {
  295. OpCode = OpCode.Self,
  296. A = a,
  297. B = b,
  298. C = c,
  299. };
  300. }
  301. /// <summary>
  302. /// R(A) := RK(B) + RK(C)
  303. /// </summary>
  304. public static Instruction Add(byte a, ushort b, ushort c)
  305. {
  306. return new()
  307. {
  308. OpCode = OpCode.Add,
  309. A = a,
  310. B = b,
  311. C = c,
  312. };
  313. }
  314. /// <summary>
  315. /// R(A) := RK(B) - RK(C)
  316. /// </summary>
  317. public static Instruction Sub(byte a, ushort b, ushort c)
  318. {
  319. return new()
  320. {
  321. OpCode = OpCode.Sub,
  322. A = a,
  323. B = b,
  324. C = c,
  325. };
  326. }
  327. /// <summary>
  328. /// R(A) := RK(B) * RK(C)
  329. /// </summary>
  330. public static Instruction Mul(byte a, ushort b, ushort c)
  331. {
  332. return new()
  333. {
  334. OpCode = OpCode.Mul,
  335. A = a,
  336. B = b,
  337. C = c,
  338. };
  339. }
  340. /// <summary>
  341. /// R(A) := RK(B) / RK(C)
  342. /// </summary>
  343. public static Instruction Div(byte a, ushort b, ushort c)
  344. {
  345. return new()
  346. {
  347. OpCode = OpCode.Div,
  348. A = a,
  349. B = b,
  350. C = c,
  351. };
  352. }
  353. /// <summary>
  354. /// R(A) := RK(B) % RK(C)
  355. /// </summary>
  356. public static Instruction Mod(byte a, ushort b, ushort c)
  357. {
  358. return new()
  359. {
  360. OpCode = OpCode.Mod,
  361. A = a,
  362. B = b,
  363. C = c,
  364. };
  365. }
  366. /// <summary>
  367. /// R(A) := RK(B) ^ RK(C)
  368. /// </summary>
  369. public static Instruction Pow(byte a, ushort b, ushort c)
  370. {
  371. return new()
  372. {
  373. OpCode = OpCode.Pow,
  374. A = a,
  375. B = b,
  376. C = c,
  377. };
  378. }
  379. /// <summary>
  380. /// R(A) := -R(B)
  381. /// </summary>
  382. public static Instruction Unm(byte a, ushort b)
  383. {
  384. return new()
  385. {
  386. OpCode = OpCode.Unm,
  387. A = a,
  388. B = b,
  389. };
  390. }
  391. /// <summary>
  392. /// R(A) := not R(B)
  393. /// </summary>
  394. public static Instruction Not(byte a, ushort b)
  395. {
  396. return new()
  397. {
  398. OpCode = OpCode.Not,
  399. A = a,
  400. B = b,
  401. };
  402. }
  403. /// <summary>
  404. /// R(A) := length of R(B)
  405. /// </summary>
  406. public static Instruction Len(byte a, ushort b)
  407. {
  408. return new()
  409. {
  410. OpCode = OpCode.Len,
  411. A = a,
  412. B = b,
  413. };
  414. }
  415. /// <summary>
  416. /// R(A) := R(B).. ... ..R(C)
  417. /// </summary>
  418. public static Instruction Concat(byte a, ushort b, ushort c)
  419. {
  420. return new()
  421. {
  422. OpCode = OpCode.Concat,
  423. A = a,
  424. B = b,
  425. C = c,
  426. };
  427. }
  428. /// <summary>
  429. /// <para>pc += sBx</para>
  430. /// <para>if (A) close all upvalues >= R(A - 1)</para>
  431. /// </summary>
  432. public static Instruction Jmp(byte a, int sBx)
  433. {
  434. return new()
  435. {
  436. OpCode = OpCode.Jmp,
  437. A = a,
  438. SBx = sBx,
  439. };
  440. }
  441. /// <summary>
  442. /// if ((RK(B) == RK(C)) ~= A) then pc++
  443. /// </summary>
  444. public static Instruction Eq(byte a, ushort b, ushort c)
  445. {
  446. return new()
  447. {
  448. OpCode = OpCode.Eq,
  449. A = a,
  450. B = b,
  451. C = c,
  452. };
  453. }
  454. /// <summary>
  455. /// if ((RK(B) &lt; RK(C)) ~= A) then pc++
  456. /// </summary>
  457. public static Instruction Lt(byte a, ushort b, ushort c)
  458. {
  459. return new()
  460. {
  461. OpCode = OpCode.Lt,
  462. A = a,
  463. B = b,
  464. C = c,
  465. };
  466. }
  467. /// <summary>
  468. /// if ((RK(B) &lt;= RK(C)) ~= A) then pc++
  469. /// </summary>
  470. public static Instruction Le(byte a, ushort b, ushort c)
  471. {
  472. return new()
  473. {
  474. OpCode = OpCode.Le,
  475. A = a,
  476. B = b,
  477. C = c,
  478. };
  479. }
  480. /// <summary>
  481. /// if not (R(A) &lt;=&gt; C) then pc++
  482. /// </summary>
  483. public static Instruction Test(byte a, ushort c)
  484. {
  485. return new()
  486. {
  487. OpCode = OpCode.Test,
  488. A = a,
  489. C = c,
  490. };
  491. }
  492. /// <summary>
  493. /// if (R(B) &lt;=&gt; C) then R(A) := R(B) else pc++
  494. /// </summary>
  495. public static Instruction TestSet(byte a, ushort b, ushort c)
  496. {
  497. return new()
  498. {
  499. OpCode = OpCode.TestSet,
  500. A = a,
  501. B = b,
  502. C = c,
  503. };
  504. }
  505. /// <summary>
  506. /// R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1))
  507. /// </summary>
  508. public static Instruction Call(byte a, ushort b, ushort c)
  509. {
  510. return new()
  511. {
  512. OpCode = OpCode.Call,
  513. A = a,
  514. B = b,
  515. C = c,
  516. };
  517. }
  518. /// <summary>
  519. /// return R(A)(R(A+1), ... ,R(A+B-1))
  520. /// </summary>
  521. public static Instruction TailCall(byte a, ushort b, ushort c)
  522. {
  523. return new()
  524. {
  525. OpCode = OpCode.TailCall,
  526. A = a,
  527. B = b,
  528. C = c,
  529. };
  530. }
  531. /// <summary>
  532. /// return R(A), ... ,R(A+B-2)
  533. /// </summary>
  534. public static Instruction Return(byte a, ushort b)
  535. {
  536. return new()
  537. {
  538. OpCode = OpCode.Return,
  539. A = a,
  540. B = b,
  541. };
  542. }
  543. /// <summary>
  544. /// <para>R(A) += R(A+2);</para>
  545. /// <para>if R(A) &lt;?= R(A+1) then { pc += sBx; R(A+3) = R(A) }</para>
  546. /// </summary>
  547. public static Instruction ForLoop(byte a, int sBx)
  548. {
  549. return new()
  550. {
  551. OpCode = OpCode.ForLoop,
  552. A = a,
  553. SBx = sBx,
  554. };
  555. }
  556. /// <summary>
  557. /// <para>R(A) -= R(A+2)</para>
  558. /// <para>pc += sBx</para>
  559. /// </summary>
  560. public static Instruction ForPrep(byte a, int sBx)
  561. {
  562. return new()
  563. {
  564. OpCode = OpCode.ForPrep,
  565. A = a,
  566. SBx = sBx,
  567. };
  568. }
  569. /// <summary>
  570. /// R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
  571. /// </summary>
  572. public static Instruction TForCall(byte a, ushort c)
  573. {
  574. return new()
  575. {
  576. OpCode = OpCode.TForCall,
  577. A = a,
  578. C = c,
  579. };
  580. }
  581. /// <summary>
  582. /// if R(A+1) ~= nil then { R(A) = R(A+1); pc += sBx }
  583. /// </summary>
  584. public static Instruction TForLoop(byte a, int sBx)
  585. {
  586. return new()
  587. {
  588. OpCode = OpCode.TForLoop,
  589. A = a,
  590. SBx = sBx,
  591. };
  592. }
  593. /// <summary>
  594. /// R(A)[(C-1) * FPF + i] := R(A+i), 1 &lt;= i &lt;= B
  595. /// </summary>
  596. public static Instruction SetList(byte a, ushort b, ushort c)
  597. {
  598. return new()
  599. {
  600. OpCode = OpCode.SetList,
  601. A = a,
  602. B = b,
  603. C = c,
  604. };
  605. }
  606. /// <summary>
  607. /// R(A) := closure(KPROTO[Bx])
  608. /// </summary>
  609. public static Instruction Closure(byte a, int sBx)
  610. {
  611. return new()
  612. {
  613. OpCode = OpCode.Closure,
  614. A = a,
  615. SBx = sBx,
  616. };
  617. }
  618. /// <summary>
  619. /// R(A), R(A+1), ..., R(A+B-2) = vararg
  620. /// </summary>
  621. public static Instruction VarArg(byte a, ushort b)
  622. {
  623. return new()
  624. {
  625. OpCode = OpCode.VarArg,
  626. A = a,
  627. B = b,
  628. };
  629. }
  630. /// <summary>
  631. /// extra (larger) argument for previous opcode
  632. /// </summary>
  633. public static Instruction ExtraArg(uint ax)
  634. {
  635. return new()
  636. {
  637. OpCode = OpCode.ExtraArg,
  638. Ax = ax,
  639. };
  640. }
  641. }