opstats.rs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. use cpu;
  2. use cpu::global_pointers;
  3. use wasmgen::wasm_builder::WasmBuilder;
  4. pub struct Instruction {
  5. pub prefixes: Vec<u8>,
  6. pub opcode: u8,
  7. pub fixed_g: u8,
  8. pub is_mem: bool,
  9. pub is_0f: bool,
  10. }
  11. pub fn decode(mut instruction: u32) -> Instruction {
  12. let mut is_0f = false;
  13. let mut prefixes = vec![];
  14. let mut final_opcode = 0;
  15. for _ in 0..4 {
  16. let opcode = (instruction & 0xFF) as u8;
  17. instruction >>= 8;
  18. // TODO:
  19. // - If the instruction uses 4 or more prefixes, only the prefixes will be counted
  20. if is_0f {
  21. final_opcode = opcode;
  22. break;
  23. }
  24. else {
  25. if opcode == 0x0F {
  26. is_0f = true;
  27. }
  28. else if opcode == 0x26
  29. || opcode == 0x2E
  30. || opcode == 0x36
  31. || opcode == 0x3E
  32. || opcode == 0x64
  33. || opcode == 0x65
  34. || opcode == 0x66
  35. || opcode == 0x67
  36. || opcode == 0xF0
  37. || opcode == 0xF2
  38. || opcode == 0xF3
  39. {
  40. prefixes.push(opcode);
  41. }
  42. else {
  43. final_opcode = opcode;
  44. break;
  45. }
  46. }
  47. }
  48. let has_modrm_byte = if is_0f {
  49. match final_opcode {
  50. 0x0 | 0x1 | 0x2 | 0x3 | 0x10 | 0x11 | 0x12 | 0x13 | 0x14 | 0x15 | 0x16 | 0x17
  51. | 0x18 | 0x19 | 0x20 | 0x21 | 0x22 | 0x23 | 0x28 | 0x29 | 0x40 | 0x41 | 0x42 | 0x43
  52. | 0x44 | 0x45 | 0x46 | 0x47 | 0x48 | 0x49 | 0x50 | 0x51 | 0x52 | 0x53 | 0x54 | 0x55
  53. | 0x56 | 0x57 | 0x58 | 0x59 | 0x60 | 0x61 | 0x62 | 0x63 | 0x64 | 0x65 | 0x66 | 0x67
  54. | 0x68 | 0x69 | 0x70 | 0x71 | 0x72 | 0x73 | 0x74 | 0x75 | 0x76 | 0x90 | 0x91 | 0x92
  55. | 0x93 | 0x94 | 0x95 | 0x96 | 0x97 | 0x98 | 0x99 | 0x1c | 0x1d | 0x1e | 0x1f | 0x2a
  56. | 0x2b | 0x2c | 0x2d | 0x2e | 0x2f | 0x4a | 0x4b | 0x4c | 0x4d | 0x4e | 0x4f | 0x5a
  57. | 0x5b | 0x5c | 0x5d | 0x5e | 0x5f | 0x6a | 0x6b | 0x6c | 0x6d | 0x6e | 0x6f | 0x7e
  58. | 0x7f | 0x9a | 0x9b | 0x9c | 0x9d | 0x9e | 0x9f | 0xa3 | 0xa4 | 0xa5 | 0xab | 0xac
  59. | 0xad | 0xae | 0xaf | 0xb0 | 0xb1 | 0xb2 | 0xb3 | 0xb4 | 0xb5 | 0xb6 | 0xb7 | 0xb8
  60. | 0xba | 0xbb | 0xbc | 0xbd | 0xbe | 0xbf | 0xc0 | 0xc1 | 0xc2 | 0xc3 | 0xc4 | 0xc5
  61. | 0xc6 | 0xc7 | 0xd1 | 0xd2 | 0xd3 | 0xd4 | 0xd5 | 0xd6 | 0xd7 | 0xd8 | 0xd9 | 0xda
  62. | 0xdb | 0xdc | 0xdd | 0xde | 0xdf | 0xe0 | 0xe1 | 0xe2 | 0xe3 | 0xe4 | 0xe5 | 0xe6
  63. | 0xe7 | 0xe8 | 0xe9 | 0xea | 0xeb | 0xec | 0xed | 0xee | 0xef | 0xf1 | 0xf2 | 0xf3
  64. | 0xf4 | 0xf5 | 0xf6 | 0xf7 | 0xf8 | 0xf9 | 0xfa | 0xfb | 0xfc | 0xfd | 0xfe => true,
  65. _ => false,
  66. }
  67. }
  68. else {
  69. match final_opcode {
  70. 0x0 | 0x1 | 0x2 | 0x3 | 0x8 | 0x9 | 0x10 | 0x11 | 0x12 | 0x13 | 0x18 | 0x19 | 0x20
  71. | 0x21 | 0x22 | 0x23 | 0x28 | 0x29 | 0x30 | 0x31 | 0x32 | 0x33 | 0x38 | 0x39 | 0x62
  72. | 0x63 | 0x69 | 0x80 | 0x81 | 0x82 | 0x83 | 0x84 | 0x85 | 0x86 | 0x87 | 0x88 | 0x89
  73. | 0xa | 0xb | 0x1a | 0x1b | 0x2a | 0x2b | 0x3a | 0x3b | 0x6b | 0x8a | 0x8b | 0x8c
  74. | 0x8d | 0x8e | 0x8f | 0xc0 | 0xc1 | 0xc4 | 0xc5 | 0xc6 | 0xc7 | 0xd0 | 0xd1 | 0xd2
  75. | 0xd3 | 0xd8 | 0xd9 | 0xda | 0xdb | 0xdc | 0xdd | 0xde | 0xdf | 0xf6 | 0xf7 | 0xfe
  76. | 0xff => true,
  77. _ => false,
  78. }
  79. };
  80. let has_fixed_g = if is_0f {
  81. final_opcode == 0x71
  82. || final_opcode == 0x72
  83. || final_opcode == 0x73
  84. || final_opcode == 0xAE
  85. || final_opcode == 0xBA
  86. || final_opcode == 0xC7
  87. }
  88. else {
  89. final_opcode >= 0x80 && final_opcode < 0x84
  90. || final_opcode >= 0xC0 && final_opcode < 0xC2
  91. || final_opcode >= 0xD0 && final_opcode < 0xD4
  92. || final_opcode >= 0xD8 && final_opcode < 0xE0
  93. || final_opcode >= 0xF6 && final_opcode < 0xF8
  94. || final_opcode == 0xFE
  95. || final_opcode == 0xFF
  96. };
  97. let mut is_mem = false;
  98. let mut fixed_g = 0;
  99. if has_fixed_g {
  100. dbg_assert!(has_modrm_byte);
  101. let modrm_byte = (instruction & 0xFF) as u8;
  102. fixed_g = modrm_byte >> 3 & 7;
  103. is_mem = modrm_byte < 0xC0
  104. }
  105. if has_modrm_byte {
  106. let modrm_byte = (instruction & 0xFF) as u8;
  107. is_mem = modrm_byte < 0xC0
  108. }
  109. Instruction {
  110. prefixes,
  111. opcode: final_opcode,
  112. is_mem,
  113. fixed_g,
  114. is_0f,
  115. }
  116. }
  117. pub fn gen_opstats(builder: &mut WasmBuilder, opcode: u32) {
  118. if !cfg!(feature = "profiler") {
  119. return;
  120. }
  121. let instruction = decode(opcode);
  122. for prefix in instruction.prefixes {
  123. let index = (prefix as u32) << 4;
  124. builder.increment_fixed_i32(global_pointers::opstats_buffer as u32 + 4 * index, 1);
  125. }
  126. let index = (instruction.is_0f as u32) << 12
  127. | (instruction.opcode as u32) << 4
  128. | (instruction.is_mem as u32) << 3
  129. | instruction.fixed_g as u32;
  130. builder.increment_fixed_i32(global_pointers::opstats_buffer as u32 + 4 * index, 1);
  131. }
  132. pub fn record_opstat_compiled(opcode: u32) {
  133. if !cfg!(feature = "profiler") {
  134. return;
  135. }
  136. let instruction = decode(opcode);
  137. for prefix in instruction.prefixes {
  138. let index = (prefix as u32) << 4;
  139. unsafe { *cpu::global_pointers::opstats_compiled_buffer.offset(index as isize) += 1 }
  140. }
  141. let index = (instruction.is_0f as u32) << 12
  142. | (instruction.opcode as u32) << 4
  143. | (instruction.is_mem as u32) << 3
  144. | instruction.fixed_g as u32;
  145. unsafe { *cpu::global_pointers::opstats_compiled_buffer.offset(index as isize) += 1 }
  146. }
  147. pub fn record_opstat_jit_exit(opcode: u32) {
  148. if !cfg!(feature = "profiler") {
  149. return;
  150. }
  151. let instruction = decode(opcode);
  152. for prefix in instruction.prefixes {
  153. let index = (prefix as u32) << 4;
  154. unsafe { *cpu::global_pointers::opstats_jit_exit_buffer.offset(index as isize) += 1 }
  155. }
  156. let index = (instruction.is_0f as u32) << 12
  157. | (instruction.opcode as u32) << 4
  158. | (instruction.is_mem as u32) << 3
  159. | instruction.fixed_g as u32;
  160. unsafe { *cpu::global_pointers::opstats_jit_exit_buffer.offset(index as isize) += 1 }
  161. }
  162. pub fn gen_opstat_unguarded_register(builder: &mut WasmBuilder, opcode: u32) {
  163. if !cfg!(feature = "profiler") {
  164. return;
  165. }
  166. let instruction = decode(opcode);
  167. for prefix in instruction.prefixes {
  168. let index = (prefix as u32) << 4;
  169. builder.increment_fixed_i32(
  170. global_pointers::opstats_unguarded_register_buffer as u32 + 4 * index,
  171. 1,
  172. );
  173. }
  174. let index = (instruction.is_0f as u32) << 12
  175. | (instruction.opcode as u32) << 4
  176. | (instruction.is_mem as u32) << 3
  177. | instruction.fixed_g as u32;
  178. builder.increment_fixed_i32(
  179. global_pointers::opstats_unguarded_register_buffer as u32 + 4 * index,
  180. 1,
  181. );
  182. }
  183. pub fn record_opstat_size_wasm(opcode: u32, size: u32) {
  184. if !cfg!(feature = "profiler") {
  185. return;
  186. }
  187. let instruction = decode(opcode);
  188. for prefix in instruction.prefixes {
  189. let index = (prefix as u32) << 4;
  190. unsafe { *cpu::global_pointers::opstats_wasm_size.offset(index as isize) += size }
  191. }
  192. let index = (instruction.is_0f as u32) << 12
  193. | (instruction.opcode as u32) << 4
  194. | (instruction.is_mem as u32) << 3
  195. | instruction.fixed_g as u32;
  196. unsafe { *cpu::global_pointers::opstats_wasm_size.offset(index as isize) += size }
  197. }