codegen.rs 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861
  1. use cpu::cpu::{
  2. tlb_data, FLAG_CARRY, FLAG_OVERFLOW, FLAG_SIGN, FLAG_ZERO, TLB_GLOBAL, TLB_HAS_CODE,
  3. TLB_NO_USER, TLB_READONLY, TLB_VALID,
  4. };
  5. use cpu::global_pointers;
  6. use cpu::memory;
  7. use jit::JitContext;
  8. use modrm;
  9. use modrm::ModrmByte;
  10. use profiler;
  11. use regs;
  12. use wasmgen::wasm_builder::{WasmBuilder, WasmLocal, WasmLocalI64};
  13. pub fn gen_add_cs_offset(ctx: &mut JitContext) {
  14. ctx.builder
  15. .load_fixed_i32(global_pointers::get_seg_offset(regs::CS));
  16. ctx.builder.add_i32();
  17. }
  18. fn gen_get_eip(builder: &mut WasmBuilder) {
  19. builder.load_fixed_i32(global_pointers::instruction_pointer as u32);
  20. }
  21. pub fn gen_set_previous_eip_offset_from_eip(builder: &mut WasmBuilder, n: u32) {
  22. // previous_ip = instruction_pointer + n
  23. builder.const_i32(global_pointers::previous_ip as i32);
  24. gen_get_eip(builder);
  25. if n != 0 {
  26. builder.const_i32(n as i32);
  27. builder.add_i32();
  28. }
  29. builder.store_aligned_i32(0);
  30. }
  31. pub fn gen_set_eip_to_after_current_instruction(ctx: &mut JitContext) {
  32. ctx.builder
  33. .const_i32(global_pointers::instruction_pointer as i32);
  34. gen_get_eip(ctx.builder);
  35. ctx.builder.const_i32(!0xFFF);
  36. ctx.builder.and_i32();
  37. ctx.builder.const_i32(ctx.cpu.eip as i32 & 0xFFF);
  38. ctx.builder.or_i32();
  39. ctx.builder.store_aligned_i32(0);
  40. }
  41. pub fn gen_set_previous_eip_offset_from_eip_with_low_bits(
  42. builder: &mut WasmBuilder,
  43. low_bits: i32,
  44. ) {
  45. // previous_ip = instruction_pointer & ~0xFFF | low_bits;
  46. builder.const_i32(global_pointers::previous_ip as i32);
  47. gen_get_eip(builder);
  48. builder.const_i32(!0xFFF);
  49. builder.and_i32();
  50. builder.const_i32(low_bits);
  51. builder.or_i32();
  52. builder.store_aligned_i32(0);
  53. }
  54. pub fn gen_increment_instruction_pointer(builder: &mut WasmBuilder, n: u32) {
  55. builder.const_i32(global_pointers::instruction_pointer as i32);
  56. gen_get_eip(builder);
  57. builder.const_i32(n as i32);
  58. builder.add_i32();
  59. builder.store_aligned_i32(0);
  60. }
  61. pub fn gen_relative_jump(builder: &mut WasmBuilder, n: i32) {
  62. // add n to instruction_pointer (without setting the offset as above)
  63. builder.const_i32(global_pointers::instruction_pointer as i32);
  64. gen_get_eip(builder);
  65. builder.const_i32(n);
  66. builder.add_i32();
  67. builder.store_aligned_i32(0);
  68. }
  69. pub fn gen_page_switch_check(
  70. ctx: &mut JitContext,
  71. next_block_addr: u32,
  72. last_instruction_addr: u32,
  73. ) {
  74. // After switching a page while in jitted code, check if the page mapping still holds
  75. gen_get_eip(ctx.builder);
  76. let address_local = ctx.builder.set_new_local();
  77. gen_get_phys_eip(ctx, &address_local);
  78. ctx.builder.free_local(address_local);
  79. ctx.builder.const_i32(next_block_addr as i32);
  80. ctx.builder.ne_i32();
  81. ctx.builder.if_void();
  82. gen_profiler_stat_increment(ctx.builder, profiler::stat::FAILED_PAGE_CHANGE);
  83. gen_debug_track_jit_exit(ctx.builder, last_instruction_addr);
  84. ctx.builder.br(ctx.exit_label);
  85. ctx.builder.block_end();
  86. }
  87. pub fn gen_absolute_indirect_jump(ctx: &mut JitContext, new_eip: WasmLocal) {
  88. ctx.builder
  89. .const_i32(global_pointers::instruction_pointer as i32);
  90. ctx.builder.get_local(&new_eip);
  91. ctx.builder.store_aligned_i32(0);
  92. gen_get_phys_eip(ctx, &new_eip);
  93. ctx.builder.free_local(new_eip);
  94. ctx.builder
  95. .const_i32(ctx.our_wasm_table_index.to_u16() as i32);
  96. ctx.builder.const_i32(ctx.state_flags.to_u32() as i32);
  97. ctx.builder.call_fn3_ret("jit_find_cache_entry_in_page");
  98. let new_basic_block_index = ctx.builder.tee_new_local();
  99. ctx.builder.const_i32(0);
  100. ctx.builder.ge_i32();
  101. ctx.builder.if_void();
  102. ctx.builder.get_local(&new_basic_block_index);
  103. ctx.builder.set_local(ctx.basic_block_index_local);
  104. ctx.builder.br(ctx.main_loop_label);
  105. ctx.builder.block_end();
  106. ctx.builder.free_local(new_basic_block_index);
  107. }
  108. pub fn gen_increment_timestamp_counter(builder: &mut WasmBuilder, n: i32) {
  109. builder.increment_fixed_i32(global_pointers::timestamp_counter as u32, n)
  110. }
  111. pub fn gen_get_reg8(ctx: &mut JitContext, r: u32) {
  112. match r {
  113. regs::AL | regs::CL | regs::DL | regs::BL => {
  114. ctx.builder.get_local(&ctx.register_locals[r as usize]);
  115. ctx.builder.const_i32(0xFF);
  116. ctx.builder.and_i32();
  117. },
  118. regs::AH | regs::CH | regs::DH | regs::BH => {
  119. ctx.builder
  120. .get_local(&ctx.register_locals[(r - 4) as usize]);
  121. ctx.builder.const_i32(8);
  122. ctx.builder.shr_u_i32();
  123. ctx.builder.const_i32(0xFF);
  124. ctx.builder.and_i32();
  125. },
  126. _ => assert!(false),
  127. }
  128. }
  129. /// Return a new local referencing one of the 8 bit registers or a direct reference to one of the
  130. /// register locals. Higher bits might be garbage (suitable for gen_cmp8 etc.). Must be freed with
  131. /// gen_free_reg8_or_alias.
  132. pub fn gen_get_reg8_or_alias_to_reg32(ctx: &mut JitContext, r: u32) -> WasmLocal {
  133. match r {
  134. regs::AL | regs::CL | regs::DL | regs::BL => ctx.register_locals[r as usize].unsafe_clone(),
  135. regs::AH | regs::CH | regs::DH | regs::BH => {
  136. ctx.builder
  137. .get_local(&ctx.register_locals[(r - 4) as usize]);
  138. ctx.builder.const_i32(8);
  139. ctx.builder.shr_u_i32();
  140. ctx.builder.set_new_local()
  141. },
  142. _ => panic!(),
  143. }
  144. }
  145. pub fn gen_free_reg8_or_alias(ctx: &mut JitContext, r: u32, local: WasmLocal) {
  146. match r {
  147. regs::AL | regs::CL | regs::DL | regs::BL => {},
  148. regs::AH | regs::CH | regs::DH | regs::BH => ctx.builder.free_local(local),
  149. _ => panic!(),
  150. }
  151. }
  152. pub fn gen_get_reg16(ctx: &mut JitContext, r: u32) {
  153. ctx.builder.get_local(&ctx.register_locals[r as usize]);
  154. ctx.builder.const_i32(0xFFFF);
  155. ctx.builder.and_i32();
  156. }
  157. pub fn gen_get_reg32(ctx: &mut JitContext, r: u32) {
  158. ctx.builder.get_local(&ctx.register_locals[r as usize]);
  159. }
  160. pub fn gen_set_reg8(ctx: &mut JitContext, r: u32) {
  161. match r {
  162. regs::AL | regs::CL | regs::DL | regs::BL => {
  163. // reg32[r] = stack_value & 0xFF | reg32[r] & ~0xFF
  164. ctx.builder.const_i32(0xFF);
  165. ctx.builder.and_i32();
  166. ctx.builder.get_local(&ctx.register_locals[r as usize]);
  167. ctx.builder.const_i32(!0xFF);
  168. ctx.builder.and_i32();
  169. ctx.builder.or_i32();
  170. ctx.builder.set_local(&ctx.register_locals[r as usize]);
  171. },
  172. regs::AH | regs::CH | regs::DH | regs::BH => {
  173. // reg32[r] = stack_value << 8 & 0xFF00 | reg32[r] & ~0xFF00
  174. ctx.builder.const_i32(8);
  175. ctx.builder.shl_i32();
  176. ctx.builder.const_i32(0xFF00);
  177. ctx.builder.and_i32();
  178. ctx.builder
  179. .get_local(&ctx.register_locals[(r - 4) as usize]);
  180. ctx.builder.const_i32(!0xFF00);
  181. ctx.builder.and_i32();
  182. ctx.builder.or_i32();
  183. ctx.builder
  184. .set_local(&ctx.register_locals[(r - 4) as usize]);
  185. },
  186. _ => assert!(false),
  187. }
  188. }
  189. pub fn gen_set_reg16(ctx: &mut JitContext, r: u32) {
  190. gen_set_reg16_local(ctx.builder, &ctx.register_locals[r as usize]);
  191. }
  192. pub fn gen_set_reg16_local(builder: &mut WasmBuilder, local: &WasmLocal) {
  193. // reg32[r] = v & 0xFFFF | reg32[r] & ~0xFFFF
  194. builder.const_i32(0xFFFF);
  195. builder.and_i32();
  196. builder.get_local(local);
  197. builder.const_i32(!0xFFFF);
  198. builder.and_i32();
  199. builder.or_i32();
  200. builder.set_local(local);
  201. }
  202. pub fn gen_set_reg32(ctx: &mut JitContext, r: u32) {
  203. ctx.builder.set_local(&ctx.register_locals[r as usize]);
  204. }
  205. pub fn decr_exc_asize(ctx: &mut JitContext) {
  206. gen_get_reg32(ctx, regs::ECX);
  207. ctx.builder.const_i32(1);
  208. ctx.builder.sub_i32();
  209. if ctx.cpu.asize_32() {
  210. gen_set_reg32(ctx, regs::ECX);
  211. }
  212. else {
  213. gen_set_reg16(ctx, regs::CX);
  214. }
  215. }
  216. pub fn gen_read_reg_xmm128_into_scratch(ctx: &mut JitContext, r: u32) {
  217. ctx.builder
  218. .const_i32(global_pointers::sse_scratch_register as i32);
  219. let dest = global_pointers::get_reg_xmm_offset(r);
  220. ctx.builder.const_i32(dest as i32);
  221. ctx.builder.load_aligned_i64(0);
  222. ctx.builder.store_aligned_i64(0);
  223. ctx.builder
  224. .const_i32(global_pointers::sse_scratch_register as i32 + 8);
  225. let dest = global_pointers::get_reg_xmm_offset(r) + 8;
  226. ctx.builder.const_i32(dest as i32);
  227. ctx.builder.load_aligned_i64(0);
  228. ctx.builder.store_aligned_i64(0);
  229. }
  230. pub fn gen_get_sreg(ctx: &mut JitContext, r: u32) {
  231. ctx.builder
  232. .load_fixed_u16(global_pointers::get_sreg_offset(r))
  233. }
  234. pub fn gen_get_ss_offset(ctx: &mut JitContext) {
  235. ctx.builder
  236. .load_fixed_i32(global_pointers::get_seg_offset(regs::SS));
  237. }
  238. pub fn gen_get_flags(builder: &mut WasmBuilder) {
  239. builder.load_fixed_i32(global_pointers::flags as u32);
  240. }
  241. pub fn gen_get_flags_changed(builder: &mut WasmBuilder) {
  242. builder.load_fixed_i32(global_pointers::flags_changed as u32);
  243. }
  244. pub fn gen_get_last_result(builder: &mut WasmBuilder) {
  245. builder.load_fixed_i32(global_pointers::last_result as u32);
  246. }
  247. pub fn gen_get_last_op_size(builder: &mut WasmBuilder) {
  248. builder.load_fixed_i32(global_pointers::last_op_size as u32);
  249. }
  250. pub fn gen_get_last_op1(builder: &mut WasmBuilder) {
  251. builder.load_fixed_i32(global_pointers::last_op1 as u32);
  252. }
  253. pub fn gen_get_page_fault(builder: &mut WasmBuilder) {
  254. builder.load_fixed_u8(global_pointers::page_fault as u32);
  255. }
  256. /// sign-extend a byte value on the stack and leave it on the stack
  257. pub fn sign_extend_i8(builder: &mut WasmBuilder) {
  258. builder.const_i32(24);
  259. builder.shl_i32();
  260. builder.const_i32(24);
  261. builder.shr_s_i32();
  262. }
  263. /// sign-extend a two byte value on the stack and leave it on the stack
  264. pub fn sign_extend_i16(builder: &mut WasmBuilder) {
  265. builder.const_i32(16);
  266. builder.shl_i32();
  267. builder.const_i32(16);
  268. builder.shr_s_i32();
  269. }
  270. pub fn gen_fn0_const(builder: &mut WasmBuilder, name: &str) { builder.call_fn0(name) }
  271. pub fn gen_fn1_const(builder: &mut WasmBuilder, name: &str, arg0: u32) {
  272. builder.const_i32(arg0 as i32);
  273. builder.call_fn1(name);
  274. }
  275. pub fn gen_fn2_const(builder: &mut WasmBuilder, name: &str, arg0: u32, arg1: u32) {
  276. builder.const_i32(arg0 as i32);
  277. builder.const_i32(arg1 as i32);
  278. builder.call_fn2(name);
  279. }
  280. pub fn gen_fn3_const(builder: &mut WasmBuilder, name: &str, arg0: u32, arg1: u32, arg2: u32) {
  281. builder.const_i32(arg0 as i32);
  282. builder.const_i32(arg1 as i32);
  283. builder.const_i32(arg2 as i32);
  284. builder.call_fn3(name);
  285. }
  286. // helper functions for gen/generate_jit.js
  287. pub fn gen_modrm_fn0(builder: &mut WasmBuilder, name: &str) {
  288. // generates: fn( _ )
  289. builder.call_fn1(name);
  290. }
  291. pub fn gen_modrm_fn1(builder: &mut WasmBuilder, name: &str, arg0: u32) {
  292. // generates: fn( _, arg0 )
  293. builder.const_i32(arg0 as i32);
  294. builder.call_fn2(name);
  295. }
  296. pub fn gen_modrm_fn2(builder: &mut WasmBuilder, name: &str, arg0: u32, arg1: u32) {
  297. // generates: fn( _, arg0, arg1 )
  298. builder.const_i32(arg0 as i32);
  299. builder.const_i32(arg1 as i32);
  300. builder.call_fn3(name);
  301. }
  302. pub fn gen_modrm_resolve(ctx: &mut JitContext, modrm_byte: ModrmByte) {
  303. modrm::gen(ctx, modrm_byte)
  304. }
  305. pub fn gen_set_reg8_r(ctx: &mut JitContext, dest: u32, src: u32) {
  306. // generates: reg8[r_dest] = reg8[r_src]
  307. gen_get_reg8(ctx, src);
  308. gen_set_reg8(ctx, dest);
  309. }
  310. pub fn gen_set_reg16_r(ctx: &mut JitContext, dest: u32, src: u32) {
  311. // generates: reg16[r_dest] = reg16[r_src]
  312. gen_get_reg16(ctx, src);
  313. gen_set_reg16(ctx, dest);
  314. }
  315. pub fn gen_set_reg32_r(ctx: &mut JitContext, dest: u32, src: u32) {
  316. // generates: reg32[r_dest] = reg32[r_src]
  317. gen_get_reg32(ctx, src);
  318. gen_set_reg32(ctx, dest);
  319. }
  320. pub fn gen_modrm_resolve_safe_read8(ctx: &mut JitContext, modrm_byte: ModrmByte) {
  321. gen_modrm_resolve(ctx, modrm_byte);
  322. let address_local = ctx.builder.set_new_local();
  323. gen_safe_read8(ctx, &address_local);
  324. ctx.builder.free_local(address_local);
  325. }
  326. pub fn gen_modrm_resolve_safe_read16(ctx: &mut JitContext, modrm_byte: ModrmByte) {
  327. gen_modrm_resolve(ctx, modrm_byte);
  328. let address_local = ctx.builder.set_new_local();
  329. gen_safe_read16(ctx, &address_local);
  330. ctx.builder.free_local(address_local);
  331. }
  332. pub fn gen_modrm_resolve_safe_read32(ctx: &mut JitContext, modrm_byte: ModrmByte) {
  333. gen_modrm_resolve(ctx, modrm_byte);
  334. let address_local = ctx.builder.set_new_local();
  335. gen_safe_read32(ctx, &address_local);
  336. ctx.builder.free_local(address_local);
  337. }
  338. pub fn gen_modrm_resolve_safe_read64(ctx: &mut JitContext, modrm_byte: ModrmByte) {
  339. gen_modrm_resolve(ctx, modrm_byte);
  340. let address_local = ctx.builder.set_new_local();
  341. gen_safe_read64(ctx, &address_local);
  342. ctx.builder.free_local(address_local);
  343. }
  344. pub fn gen_modrm_resolve_safe_read128(
  345. ctx: &mut JitContext,
  346. modrm_byte: ModrmByte,
  347. where_to_write: u32,
  348. ) {
  349. gen_modrm_resolve(ctx, modrm_byte);
  350. let address_local = ctx.builder.set_new_local();
  351. gen_safe_read128(ctx, &address_local, where_to_write);
  352. ctx.builder.free_local(address_local);
  353. }
  354. pub fn gen_safe_read8(ctx: &mut JitContext, address_local: &WasmLocal) {
  355. gen_safe_read(ctx, BitSize::BYTE, address_local, None);
  356. }
  357. pub fn gen_safe_read16(ctx: &mut JitContext, address_local: &WasmLocal) {
  358. gen_safe_read(ctx, BitSize::WORD, address_local, None);
  359. }
  360. pub fn gen_safe_read32(ctx: &mut JitContext, address_local: &WasmLocal) {
  361. gen_safe_read(ctx, BitSize::DWORD, address_local, None);
  362. }
  363. pub fn gen_safe_read64(ctx: &mut JitContext, address_local: &WasmLocal) {
  364. gen_safe_read(ctx, BitSize::QWORD, &address_local, None);
  365. }
  366. pub fn gen_safe_read128(ctx: &mut JitContext, address_local: &WasmLocal, where_to_write: u32) {
  367. gen_safe_read(ctx, BitSize::DQWORD, &address_local, Some(where_to_write));
  368. }
  369. // only used internally for gen_safe_write
  370. enum GenSafeWriteValue<'a> {
  371. I32(&'a WasmLocal),
  372. I64(&'a WasmLocalI64),
  373. TwoI64s(&'a WasmLocalI64, &'a WasmLocalI64),
  374. }
  375. enum GenSafeReadWriteValue {
  376. I32(WasmLocal),
  377. I64(WasmLocalI64),
  378. }
  379. #[derive(Copy, Clone, Eq, PartialEq)]
  380. pub enum BitSize {
  381. BYTE,
  382. WORD,
  383. DWORD,
  384. QWORD,
  385. DQWORD,
  386. }
  387. impl BitSize {
  388. pub fn bytes(&self) -> u32 {
  389. match self {
  390. BitSize::BYTE => 1,
  391. BitSize::WORD => 2,
  392. BitSize::DWORD => 4,
  393. BitSize::QWORD => 8,
  394. BitSize::DQWORD => 16,
  395. }
  396. }
  397. }
  398. pub fn gen_safe_write8(ctx: &mut JitContext, address_local: &WasmLocal, value_local: &WasmLocal) {
  399. gen_safe_write(
  400. ctx,
  401. BitSize::BYTE,
  402. address_local,
  403. GenSafeWriteValue::I32(value_local),
  404. )
  405. }
  406. pub fn gen_safe_write16(ctx: &mut JitContext, address_local: &WasmLocal, value_local: &WasmLocal) {
  407. gen_safe_write(
  408. ctx,
  409. BitSize::WORD,
  410. address_local,
  411. GenSafeWriteValue::I32(value_local),
  412. )
  413. }
  414. pub fn gen_safe_write32(ctx: &mut JitContext, address_local: &WasmLocal, value_local: &WasmLocal) {
  415. gen_safe_write(
  416. ctx,
  417. BitSize::DWORD,
  418. address_local,
  419. GenSafeWriteValue::I32(value_local),
  420. )
  421. }
  422. pub fn gen_safe_write64(
  423. ctx: &mut JitContext,
  424. address_local: &WasmLocal,
  425. value_local: &WasmLocalI64,
  426. ) {
  427. gen_safe_write(
  428. ctx,
  429. BitSize::QWORD,
  430. address_local,
  431. GenSafeWriteValue::I64(value_local),
  432. )
  433. }
  434. pub fn gen_safe_write128(
  435. ctx: &mut JitContext,
  436. address_local: &WasmLocal,
  437. value_local_low: &WasmLocalI64,
  438. value_local_high: &WasmLocalI64,
  439. ) {
  440. gen_safe_write(
  441. ctx,
  442. BitSize::DQWORD,
  443. address_local,
  444. GenSafeWriteValue::TwoI64s(value_local_low, value_local_high),
  445. )
  446. }
  447. fn gen_safe_read(
  448. ctx: &mut JitContext,
  449. bits: BitSize,
  450. address_local: &WasmLocal,
  451. where_to_write: Option<u32>,
  452. ) {
  453. // Execute a virtual memory read. All slow paths (memory-mapped IO, tlb miss, page fault and
  454. // read across page boundary are handled in safe_read_jit_slow
  455. // entry <- tlb_data[addr >> 12 << 2]
  456. // if entry & MASK == TLB_VALID && (addr & 0xFFF) <= 0x1000 - bytes: goto fast
  457. // entry <- safe_read_jit_slow(addr, instruction_pointer)
  458. // if page_fault: goto exit-with-pagefault
  459. // fast: mem[(entry & ~0xFFF) ^ addr]
  460. let cont = ctx.builder.block_void();
  461. ctx.builder.get_local(&address_local);
  462. ctx.builder.const_i32(12);
  463. ctx.builder.shr_u_i32();
  464. ctx.builder.const_i32(2);
  465. ctx.builder.shl_i32();
  466. ctx.builder
  467. .load_aligned_i32(unsafe { &tlb_data[0] as *const i32 as u32 });
  468. let entry_local = ctx.builder.tee_new_local();
  469. ctx.builder.const_i32(
  470. (0xFFF
  471. & !TLB_READONLY
  472. & !TLB_GLOBAL
  473. & !TLB_HAS_CODE
  474. & !(if ctx.cpu.cpl3() { 0 } else { TLB_NO_USER })) as i32,
  475. );
  476. ctx.builder.and_i32();
  477. ctx.builder.const_i32(TLB_VALID as i32);
  478. ctx.builder.eq_i32();
  479. if bits != BitSize::BYTE {
  480. ctx.builder.get_local(&address_local);
  481. ctx.builder.const_i32(0xFFF);
  482. ctx.builder.and_i32();
  483. ctx.builder.const_i32(0x1000 - bits.bytes() as i32);
  484. ctx.builder.le_i32();
  485. ctx.builder.and_i32();
  486. }
  487. ctx.builder.br_if(cont);
  488. if cfg!(feature = "profiler") {
  489. ctx.builder.get_local(&address_local);
  490. ctx.builder.get_local(&entry_local);
  491. ctx.builder.call_fn2("report_safe_read_jit_slow");
  492. }
  493. ctx.builder.get_local(&address_local);
  494. ctx.builder
  495. .const_i32(ctx.start_of_current_instruction as i32 & 0xFFF);
  496. match bits {
  497. BitSize::BYTE => {
  498. ctx.builder.call_fn2_ret("safe_read8_slow_jit");
  499. },
  500. BitSize::WORD => {
  501. ctx.builder.call_fn2_ret("safe_read16_slow_jit");
  502. },
  503. BitSize::DWORD => {
  504. ctx.builder.call_fn2_ret("safe_read32s_slow_jit");
  505. },
  506. BitSize::QWORD => {
  507. ctx.builder.call_fn2_ret("safe_read64s_slow_jit");
  508. },
  509. BitSize::DQWORD => {
  510. ctx.builder.call_fn2_ret("safe_read128s_slow_jit");
  511. },
  512. }
  513. ctx.builder.tee_local(&entry_local);
  514. ctx.builder.const_i32(1);
  515. ctx.builder.and_i32();
  516. if cfg!(feature = "profiler") {
  517. ctx.builder.if_void();
  518. gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction);
  519. ctx.builder.block_end();
  520. ctx.builder.get_local(&entry_local);
  521. ctx.builder.const_i32(1);
  522. ctx.builder.and_i32();
  523. }
  524. ctx.builder.br_if(ctx.exit_with_fault_label);
  525. ctx.builder.block_end();
  526. gen_profiler_stat_increment(ctx.builder, profiler::stat::SAFE_READ_FAST); // XXX: Both fast and slow
  527. ctx.builder.get_local(&entry_local);
  528. ctx.builder.const_i32(!0xFFF);
  529. ctx.builder.and_i32();
  530. ctx.builder.get_local(&address_local);
  531. ctx.builder.xor_i32();
  532. // where_to_write is only used by dqword
  533. dbg_assert!((where_to_write != None) == (bits == BitSize::DQWORD));
  534. ctx.builder.const_i32(unsafe { memory::mem8 } as i32);
  535. ctx.builder.add_i32();
  536. match bits {
  537. BitSize::BYTE => {
  538. ctx.builder.load_u8(0);
  539. },
  540. BitSize::WORD => {
  541. ctx.builder.load_unaligned_u16(0);
  542. },
  543. BitSize::DWORD => {
  544. ctx.builder.load_unaligned_i32(0);
  545. },
  546. BitSize::QWORD => {
  547. ctx.builder.load_unaligned_i64(0);
  548. },
  549. BitSize::DQWORD => {
  550. let where_to_write = where_to_write.unwrap();
  551. let virt_address_local = ctx.builder.set_new_local();
  552. ctx.builder.const_i32(0);
  553. ctx.builder.get_local(&virt_address_local);
  554. ctx.builder.load_unaligned_i64(0);
  555. ctx.builder.store_unaligned_i64(where_to_write);
  556. ctx.builder.const_i32(0);
  557. ctx.builder.get_local(&virt_address_local);
  558. ctx.builder.load_unaligned_i64(8);
  559. ctx.builder.store_unaligned_i64(where_to_write + 8);
  560. ctx.builder.free_local(virt_address_local);
  561. },
  562. }
  563. ctx.builder.free_local(entry_local);
  564. }
  565. pub fn gen_get_phys_eip(ctx: &mut JitContext, address_local: &WasmLocal) {
  566. // Similar to gen_safe_read, but return the physical eip rather than reading from memory
  567. // Does not (need to) handle mapped memory
  568. // XXX: Currently does not use ctx.start_of_current_instruction, but rather assumes that eip is
  569. // already correct (pointing at the current instruction)
  570. let cont = ctx.builder.block_void();
  571. ctx.builder.get_local(&address_local);
  572. ctx.builder.const_i32(12);
  573. ctx.builder.shr_u_i32();
  574. ctx.builder.const_i32(2);
  575. ctx.builder.shl_i32();
  576. ctx.builder
  577. .load_aligned_i32(unsafe { &tlb_data[0] as *const i32 as u32 });
  578. let entry_local = ctx.builder.tee_new_local();
  579. ctx.builder.const_i32(
  580. (0xFFF
  581. & !TLB_READONLY
  582. & !TLB_GLOBAL
  583. & !TLB_HAS_CODE
  584. & !(if ctx.cpu.cpl3() { 0 } else { TLB_NO_USER })) as i32,
  585. );
  586. ctx.builder.and_i32();
  587. ctx.builder.const_i32(TLB_VALID as i32);
  588. ctx.builder.eq_i32();
  589. ctx.builder.br_if(cont);
  590. if cfg!(feature = "profiler") {
  591. ctx.builder.get_local(&address_local);
  592. ctx.builder.get_local(&entry_local);
  593. ctx.builder.call_fn2("report_safe_read_jit_slow");
  594. }
  595. ctx.builder.get_local(&address_local);
  596. ctx.builder.call_fn1_ret("get_phys_eip_slow_jit");
  597. ctx.builder.tee_local(&entry_local);
  598. ctx.builder.const_i32(1);
  599. ctx.builder.and_i32();
  600. if cfg!(feature = "profiler") {
  601. ctx.builder.if_void();
  602. gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction); // XXX
  603. ctx.builder.block_end();
  604. ctx.builder.get_local(&entry_local);
  605. ctx.builder.const_i32(1);
  606. ctx.builder.and_i32();
  607. }
  608. ctx.builder.br_if(ctx.exit_with_fault_label);
  609. ctx.builder.block_end();
  610. gen_profiler_stat_increment(ctx.builder, profiler::stat::SAFE_READ_FAST); // XXX: Both fast and slow
  611. ctx.builder.get_local(&entry_local);
  612. ctx.builder.const_i32(!0xFFF);
  613. ctx.builder.and_i32();
  614. ctx.builder.get_local(&address_local);
  615. ctx.builder.xor_i32();
  616. ctx.builder.free_local(entry_local);
  617. }
  618. fn gen_safe_write(
  619. ctx: &mut JitContext,
  620. bits: BitSize,
  621. address_local: &WasmLocal,
  622. value_local: GenSafeWriteValue,
  623. ) {
  624. // Execute a virtual memory write. All slow paths (memory-mapped IO, tlb miss, page fault,
  625. // write across page boundary and page containing jitted code are handled in safe_write_jit_slow
  626. // entry <- tlb_data[addr >> 12 << 2]
  627. // if entry & MASK == TLB_VALID && (addr & 0xFFF) <= 0x1000 - bytes: goto fast
  628. // entry <- safe_write_jit_slow(addr, value, instruction_pointer)
  629. // if page_fault: goto exit-with-pagefault
  630. // fast: mem[(entry & ~0xFFF) ^ addr] <- value
  631. let cont = ctx.builder.block_void();
  632. ctx.builder.get_local(&address_local);
  633. ctx.builder.const_i32(12);
  634. ctx.builder.shr_u_i32();
  635. ctx.builder.const_i32(2);
  636. ctx.builder.shl_i32();
  637. ctx.builder
  638. .load_aligned_i32(unsafe { &tlb_data[0] as *const i32 as u32 });
  639. let entry_local = ctx.builder.tee_new_local();
  640. ctx.builder
  641. .const_i32((0xFFF & !TLB_GLOBAL & !(if ctx.cpu.cpl3() { 0 } else { TLB_NO_USER })) as i32);
  642. ctx.builder.and_i32();
  643. ctx.builder.const_i32(TLB_VALID as i32);
  644. ctx.builder.eq_i32();
  645. if bits != BitSize::BYTE {
  646. ctx.builder.get_local(&address_local);
  647. ctx.builder.const_i32(0xFFF);
  648. ctx.builder.and_i32();
  649. ctx.builder.const_i32(0x1000 - bits.bytes() as i32);
  650. ctx.builder.le_i32();
  651. ctx.builder.and_i32();
  652. }
  653. ctx.builder.br_if(cont);
  654. if cfg!(feature = "profiler") {
  655. ctx.builder.get_local(&address_local);
  656. ctx.builder.get_local(&entry_local);
  657. ctx.builder.call_fn2("report_safe_write_jit_slow");
  658. }
  659. ctx.builder.get_local(&address_local);
  660. match value_local {
  661. GenSafeWriteValue::I32(local) => ctx.builder.get_local(local),
  662. GenSafeWriteValue::I64(local) => ctx.builder.get_local_i64(local),
  663. GenSafeWriteValue::TwoI64s(local1, local2) => {
  664. ctx.builder.get_local_i64(local1);
  665. ctx.builder.get_local_i64(local2)
  666. },
  667. }
  668. ctx.builder
  669. .const_i32(ctx.start_of_current_instruction as i32 & 0xFFF);
  670. match bits {
  671. BitSize::BYTE => {
  672. ctx.builder.call_fn3_ret("safe_write8_slow_jit");
  673. },
  674. BitSize::WORD => {
  675. ctx.builder.call_fn3_ret("safe_write16_slow_jit");
  676. },
  677. BitSize::DWORD => {
  678. ctx.builder.call_fn3_ret("safe_write32_slow_jit");
  679. },
  680. BitSize::QWORD => {
  681. ctx.builder
  682. .call_fn3_i32_i64_i32_ret("safe_write64_slow_jit");
  683. },
  684. BitSize::DQWORD => {
  685. ctx.builder
  686. .call_fn4_i32_i64_i64_i32_ret("safe_write128_slow_jit");
  687. },
  688. }
  689. ctx.builder.tee_local(&entry_local);
  690. ctx.builder.const_i32(1);
  691. ctx.builder.and_i32();
  692. if cfg!(feature = "profiler") {
  693. ctx.builder.if_void();
  694. gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction);
  695. ctx.builder.block_end();
  696. ctx.builder.get_local(&entry_local);
  697. ctx.builder.const_i32(1);
  698. ctx.builder.and_i32();
  699. }
  700. ctx.builder.br_if(ctx.exit_with_fault_label);
  701. ctx.builder.block_end();
  702. gen_profiler_stat_increment(ctx.builder, profiler::stat::SAFE_WRITE_FAST); // XXX: Both fast and slow
  703. ctx.builder.get_local(&entry_local);
  704. ctx.builder.const_i32(!0xFFF);
  705. ctx.builder.and_i32();
  706. ctx.builder.get_local(&address_local);
  707. ctx.builder.xor_i32();
  708. ctx.builder.const_i32(unsafe { memory::mem8 } as i32);
  709. ctx.builder.add_i32();
  710. match value_local {
  711. GenSafeWriteValue::I32(local) => ctx.builder.get_local(local),
  712. GenSafeWriteValue::I64(local) => ctx.builder.get_local_i64(local),
  713. GenSafeWriteValue::TwoI64s(local1, local2) => {
  714. assert!(bits == BitSize::DQWORD);
  715. let virt_address_local = ctx.builder.tee_new_local();
  716. ctx.builder.get_local_i64(local1);
  717. ctx.builder.store_unaligned_i64(0);
  718. ctx.builder.get_local(&virt_address_local);
  719. ctx.builder.get_local_i64(local2);
  720. ctx.builder.store_unaligned_i64(8);
  721. ctx.builder.free_local(virt_address_local);
  722. },
  723. }
  724. match bits {
  725. BitSize::BYTE => {
  726. ctx.builder.store_u8(0);
  727. },
  728. BitSize::WORD => {
  729. ctx.builder.store_unaligned_u16(0);
  730. },
  731. BitSize::DWORD => {
  732. ctx.builder.store_unaligned_i32(0);
  733. },
  734. BitSize::QWORD => {
  735. ctx.builder.store_unaligned_i64(0);
  736. },
  737. BitSize::DQWORD => {}, // handled above
  738. }
  739. ctx.builder.free_local(entry_local);
  740. }
  741. pub fn gen_safe_read_write(
  742. ctx: &mut JitContext,
  743. bits: BitSize,
  744. address_local: &WasmLocal,
  745. f: &dyn Fn(&mut JitContext),
  746. ) {
  747. // Execute a virtual memory read+write. All slow paths (memory-mapped IO, tlb miss, page fault,
  748. // write across page boundary and page containing jitted code are handled in
  749. // safe_read_write_jit_slow
  750. // entry <- tlb_data[addr >> 12 << 2]
  751. // can_use_fast_path <- entry & MASK == TLB_VALID && (addr & 0xFFF) <= 0x1000 - bytes
  752. // if can_use_fast_path: goto fast
  753. // entry <- safe_read_write_jit_slow(addr, instruction_pointer)
  754. // if page_fault: goto exit-with-pagefault
  755. // fast: value <- f(mem[(entry & ~0xFFF) ^ addr])
  756. // if !can_use_fast_path { safe_write_jit_slow(addr, value, instruction_pointer) }
  757. // mem[(entry & ~0xFFF) ^ addr] <- value
  758. let cont = ctx.builder.block_void();
  759. ctx.builder.get_local(address_local);
  760. ctx.builder.const_i32(12);
  761. ctx.builder.shr_u_i32();
  762. ctx.builder.const_i32(2);
  763. ctx.builder.shl_i32();
  764. ctx.builder
  765. .load_aligned_i32(unsafe { &tlb_data[0] as *const i32 as u32 });
  766. let entry_local = ctx.builder.tee_new_local();
  767. ctx.builder
  768. .const_i32((0xFFF & !TLB_GLOBAL & !(if ctx.cpu.cpl3() { 0 } else { TLB_NO_USER })) as i32);
  769. ctx.builder.and_i32();
  770. ctx.builder.const_i32(TLB_VALID as i32);
  771. ctx.builder.eq_i32();
  772. if bits != BitSize::BYTE {
  773. ctx.builder.get_local(&address_local);
  774. ctx.builder.const_i32(0xFFF);
  775. ctx.builder.and_i32();
  776. ctx.builder.const_i32(0x1000 - bits.bytes() as i32);
  777. ctx.builder.le_i32();
  778. ctx.builder.and_i32();
  779. }
  780. let can_use_fast_path_local = ctx.builder.tee_new_local();
  781. ctx.builder.br_if(cont);
  782. if cfg!(feature = "profiler") {
  783. ctx.builder.get_local(&address_local);
  784. ctx.builder.get_local(&entry_local);
  785. ctx.builder.call_fn2("report_safe_read_write_jit_slow");
  786. }
  787. ctx.builder.get_local(&address_local);
  788. ctx.builder
  789. .const_i32(ctx.start_of_current_instruction as i32 & 0xFFF);
  790. match bits {
  791. BitSize::BYTE => {
  792. ctx.builder.call_fn2_ret("safe_read_write8_slow_jit");
  793. },
  794. BitSize::WORD => {
  795. ctx.builder.call_fn2_ret("safe_read_write16_slow_jit");
  796. },
  797. BitSize::DWORD => {
  798. ctx.builder.call_fn2_ret("safe_read_write32s_slow_jit");
  799. },
  800. BitSize::QWORD => {
  801. ctx.builder.call_fn2_ret("safe_read_write64_slow_jit");
  802. },
  803. BitSize::DQWORD => dbg_assert!(false),
  804. }
  805. ctx.builder.tee_local(&entry_local);
  806. ctx.builder.const_i32(1);
  807. ctx.builder.and_i32();
  808. if cfg!(feature = "profiler") {
  809. ctx.builder.if_void();
  810. gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction);
  811. ctx.builder.block_end();
  812. ctx.builder.get_local(&entry_local);
  813. ctx.builder.const_i32(1);
  814. ctx.builder.and_i32();
  815. }
  816. ctx.builder.br_if(ctx.exit_with_fault_label);
  817. ctx.builder.block_end();
  818. gen_profiler_stat_increment(ctx.builder, profiler::stat::SAFE_READ_WRITE_FAST); // XXX: Also slow
  819. ctx.builder.get_local(&entry_local);
  820. ctx.builder.const_i32(!0xFFF);
  821. ctx.builder.and_i32();
  822. ctx.builder.get_local(&address_local);
  823. ctx.builder.xor_i32();
  824. ctx.builder.const_i32(unsafe { memory::mem8 } as i32);
  825. ctx.builder.add_i32();
  826. ctx.builder.free_local(entry_local);
  827. let phys_addr_local = ctx.builder.tee_new_local();
  828. match bits {
  829. BitSize::BYTE => {
  830. ctx.builder.load_u8(0);
  831. },
  832. BitSize::WORD => {
  833. ctx.builder.load_unaligned_u16(0);
  834. },
  835. BitSize::DWORD => {
  836. ctx.builder.load_unaligned_i32(0);
  837. },
  838. BitSize::QWORD => {
  839. ctx.builder.load_unaligned_i64(0);
  840. },
  841. BitSize::DQWORD => assert!(false), // not used
  842. }
  843. // value is now on stack
  844. f(ctx);
  845. // TODO: Could get rid of this local by returning one from f
  846. let value_local = if bits == BitSize::QWORD {
  847. GenSafeReadWriteValue::I64(ctx.builder.set_new_local_i64())
  848. }
  849. else {
  850. GenSafeReadWriteValue::I32(ctx.builder.set_new_local())
  851. };
  852. ctx.builder.get_local(&can_use_fast_path_local);
  853. ctx.builder.eqz_i32();
  854. ctx.builder.if_void();
  855. {
  856. ctx.builder.get_local(&address_local);
  857. match &value_local {
  858. GenSafeReadWriteValue::I32(l) => ctx.builder.get_local(l),
  859. GenSafeReadWriteValue::I64(l) => ctx.builder.get_local_i64(l),
  860. }
  861. ctx.builder
  862. .const_i32(ctx.start_of_current_instruction as i32);
  863. match bits {
  864. BitSize::BYTE => {
  865. ctx.builder.call_fn3_ret("safe_write8_slow_jit");
  866. },
  867. BitSize::WORD => {
  868. ctx.builder.call_fn3_ret("safe_write16_slow_jit");
  869. },
  870. BitSize::DWORD => {
  871. ctx.builder.call_fn3_ret("safe_write32_slow_jit");
  872. },
  873. BitSize::QWORD => {
  874. ctx.builder
  875. .call_fn3_i32_i64_i32_ret("safe_write64_slow_jit");
  876. },
  877. BitSize::DQWORD => dbg_assert!(false),
  878. }
  879. ctx.builder.const_i32(1);
  880. ctx.builder.and_i32();
  881. ctx.builder.if_void();
  882. {
  883. // handled above
  884. if cfg!(debug_assertions) {
  885. ctx.builder.const_i32(match bits {
  886. BitSize::BYTE => 8,
  887. BitSize::WORD => 16,
  888. BitSize::DWORD => 32,
  889. BitSize::QWORD => 64,
  890. _ => {
  891. dbg_assert!(false);
  892. 0
  893. },
  894. });
  895. ctx.builder.get_local(&address_local);
  896. ctx.builder.call_fn2("bug_gen_safe_read_write_page_fault");
  897. }
  898. else {
  899. ctx.builder.unreachable();
  900. }
  901. }
  902. ctx.builder.block_end();
  903. }
  904. ctx.builder.block_end();
  905. ctx.builder.get_local(&phys_addr_local);
  906. match &value_local {
  907. GenSafeReadWriteValue::I32(l) => ctx.builder.get_local(l),
  908. GenSafeReadWriteValue::I64(l) => ctx.builder.get_local_i64(l),
  909. }
  910. match bits {
  911. BitSize::BYTE => {
  912. ctx.builder.store_u8(0);
  913. },
  914. BitSize::WORD => {
  915. ctx.builder.store_unaligned_u16(0);
  916. },
  917. BitSize::DWORD => {
  918. ctx.builder.store_unaligned_i32(0);
  919. },
  920. BitSize::QWORD => {
  921. ctx.builder.store_unaligned_i64(0);
  922. },
  923. BitSize::DQWORD => dbg_assert!(false),
  924. }
  925. match value_local {
  926. GenSafeReadWriteValue::I32(l) => ctx.builder.free_local(l),
  927. GenSafeReadWriteValue::I64(l) => ctx.builder.free_local_i64(l),
  928. }
  929. ctx.builder.free_local(can_use_fast_path_local);
  930. ctx.builder.free_local(phys_addr_local);
  931. }
  932. #[cfg(debug_assertions)]
  933. #[no_mangle]
  934. pub fn bug_gen_safe_read_write_page_fault(bits: i32, addr: u32) {
  935. dbg_log!("bug: gen_safe_read_write_page_fault {} {:x}", bits, addr);
  936. dbg_assert!(false);
  937. }
  938. pub fn gen_jmp_rel16(builder: &mut WasmBuilder, rel16: u16) {
  939. let cs_offset_addr = global_pointers::get_seg_offset(regs::CS);
  940. builder.load_fixed_i32(cs_offset_addr);
  941. let local = builder.set_new_local();
  942. // generate:
  943. // *instruction_pointer = cs_offset + ((*instruction_pointer - cs_offset + rel16) & 0xFFFF);
  944. {
  945. builder.const_i32(global_pointers::instruction_pointer as i32);
  946. gen_get_eip(builder);
  947. builder.get_local(&local);
  948. builder.sub_i32();
  949. builder.const_i32(rel16 as i32);
  950. builder.add_i32();
  951. builder.const_i32(0xFFFF);
  952. builder.and_i32();
  953. builder.get_local(&local);
  954. builder.add_i32();
  955. builder.store_aligned_i32(0);
  956. }
  957. builder.free_local(local);
  958. }
  959. pub fn gen_pop16_ss16(ctx: &mut JitContext) {
  960. // sp = segment_offsets[SS] + reg16[SP] (or just reg16[SP] if has_flat_segmentation)
  961. gen_get_reg16(ctx, regs::SP);
  962. if !ctx.cpu.has_flat_segmentation() {
  963. gen_get_ss_offset(ctx);
  964. ctx.builder.add_i32();
  965. }
  966. // result = safe_read16(sp)
  967. let address_local = ctx.builder.set_new_local();
  968. gen_safe_read16(ctx, &address_local);
  969. ctx.builder.free_local(address_local);
  970. // reg16[SP] += 2;
  971. gen_get_reg16(ctx, regs::SP);
  972. ctx.builder.const_i32(2);
  973. ctx.builder.add_i32();
  974. gen_set_reg16(ctx, regs::SP);
  975. // return value is already on stack
  976. }
  977. pub fn gen_pop16_ss32(ctx: &mut JitContext) {
  978. // esp = segment_offsets[SS] + reg32[ESP] (or just reg32[ESP] if has_flat_segmentation)
  979. gen_get_reg32(ctx, regs::ESP);
  980. if !ctx.cpu.has_flat_segmentation() {
  981. gen_get_ss_offset(ctx);
  982. ctx.builder.add_i32();
  983. }
  984. // result = safe_read16(esp)
  985. let address_local = ctx.builder.set_new_local();
  986. gen_safe_read16(ctx, &address_local);
  987. ctx.builder.free_local(address_local);
  988. // reg32[ESP] += 2;
  989. gen_get_reg32(ctx, regs::ESP);
  990. ctx.builder.const_i32(2);
  991. ctx.builder.add_i32();
  992. gen_set_reg32(ctx, regs::ESP);
  993. // return value is already on stack
  994. }
  995. pub fn gen_pop16(ctx: &mut JitContext) {
  996. if ctx.cpu.ssize_32() {
  997. gen_pop16_ss32(ctx);
  998. }
  999. else {
  1000. gen_pop16_ss16(ctx);
  1001. }
  1002. }
  1003. pub fn gen_pop32s_ss16(ctx: &mut JitContext) {
  1004. // sp = reg16[SP]
  1005. gen_get_reg16(ctx, regs::SP);
  1006. // result = safe_read32s(segment_offsets[SS] + sp) (or just sp if has_flat_segmentation)
  1007. if !ctx.cpu.has_flat_segmentation() {
  1008. gen_get_ss_offset(ctx);
  1009. ctx.builder.add_i32();
  1010. }
  1011. let address_local = ctx.builder.set_new_local();
  1012. gen_safe_read32(ctx, &address_local);
  1013. ctx.builder.free_local(address_local);
  1014. // reg16[SP] = sp + 4;
  1015. gen_get_reg16(ctx, regs::SP);
  1016. ctx.builder.const_i32(4);
  1017. ctx.builder.add_i32();
  1018. gen_set_reg16(ctx, regs::SP);
  1019. // return value is already on stack
  1020. }
  1021. pub fn gen_pop32s_ss32(ctx: &mut JitContext) {
  1022. if !ctx.cpu.has_flat_segmentation() {
  1023. gen_get_reg32(ctx, regs::ESP);
  1024. gen_get_ss_offset(ctx);
  1025. ctx.builder.add_i32();
  1026. let address_local = ctx.builder.set_new_local();
  1027. gen_safe_read32(ctx, &address_local);
  1028. ctx.builder.free_local(address_local);
  1029. }
  1030. else {
  1031. let reg = ctx.register_locals[regs::ESP as usize].unsafe_clone();
  1032. gen_safe_read32(ctx, &reg);
  1033. }
  1034. gen_get_reg32(ctx, regs::ESP);
  1035. ctx.builder.const_i32(4);
  1036. ctx.builder.add_i32();
  1037. gen_set_reg32(ctx, regs::ESP);
  1038. // return value is already on stack
  1039. }
  1040. pub fn gen_pop32s(ctx: &mut JitContext) {
  1041. if ctx.cpu.ssize_32() {
  1042. gen_pop32s_ss32(ctx);
  1043. }
  1044. else {
  1045. gen_pop32s_ss16(ctx);
  1046. }
  1047. }
  1048. pub fn gen_adjust_stack_reg(ctx: &mut JitContext, offset: u32) {
  1049. if ctx.cpu.ssize_32() {
  1050. gen_get_reg32(ctx, regs::ESP);
  1051. ctx.builder.const_i32(offset as i32);
  1052. ctx.builder.add_i32();
  1053. gen_set_reg32(ctx, regs::ESP);
  1054. }
  1055. else {
  1056. gen_get_reg16(ctx, regs::SP);
  1057. ctx.builder.const_i32(offset as i32);
  1058. ctx.builder.add_i32();
  1059. gen_set_reg16(ctx, regs::SP);
  1060. }
  1061. }
  1062. pub fn gen_leave(ctx: &mut JitContext, os32: bool) {
  1063. // [e]bp = safe_read{16,32}([e]bp)
  1064. if ctx.cpu.ssize_32() {
  1065. gen_get_reg32(ctx, regs::EBP);
  1066. }
  1067. else {
  1068. gen_get_reg16(ctx, regs::BP);
  1069. }
  1070. let old_vbp = ctx.builder.tee_new_local();
  1071. if !ctx.cpu.has_flat_segmentation() {
  1072. gen_get_ss_offset(ctx);
  1073. ctx.builder.add_i32();
  1074. }
  1075. if os32 {
  1076. let address_local = ctx.builder.set_new_local();
  1077. gen_safe_read32(ctx, &address_local);
  1078. ctx.builder.free_local(address_local);
  1079. gen_set_reg32(ctx, regs::EBP);
  1080. }
  1081. else {
  1082. let address_local = ctx.builder.set_new_local();
  1083. gen_safe_read16(ctx, &address_local);
  1084. ctx.builder.free_local(address_local);
  1085. gen_set_reg16(ctx, regs::BP);
  1086. }
  1087. // [e]sp = [e]bp + (os32 ? 4 : 2)
  1088. if ctx.cpu.ssize_32() {
  1089. ctx.builder.get_local(&old_vbp);
  1090. ctx.builder.const_i32(if os32 { 4 } else { 2 });
  1091. ctx.builder.add_i32();
  1092. gen_set_reg32(ctx, regs::ESP);
  1093. }
  1094. else {
  1095. ctx.builder.get_local(&old_vbp);
  1096. ctx.builder.const_i32(if os32 { 4 } else { 2 });
  1097. ctx.builder.add_i32();
  1098. gen_set_reg16(ctx, regs::SP);
  1099. }
  1100. ctx.builder.free_local(old_vbp);
  1101. }
  1102. pub fn gen_task_switch_test(ctx: &mut JitContext) {
  1103. // generate if(cr[0] & (CR0_EM | CR0_TS)) { task_switch_test_jit(); goto exit_with_fault; }
  1104. let cr0_offset = global_pointers::get_creg_offset(0);
  1105. dbg_assert!(regs::CR0_EM | regs::CR0_TS <= 0xFF);
  1106. ctx.builder.load_fixed_u8(cr0_offset);
  1107. ctx.builder.const_i32((regs::CR0_EM | regs::CR0_TS) as i32);
  1108. ctx.builder.and_i32();
  1109. ctx.builder.if_void();
  1110. {
  1111. gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction);
  1112. gen_fn1_const(
  1113. ctx.builder,
  1114. "task_switch_test_jit",
  1115. ctx.start_of_current_instruction,
  1116. );
  1117. ctx.builder.br(ctx.exit_with_fault_label);
  1118. }
  1119. ctx.builder.block_end();
  1120. }
  1121. pub fn gen_task_switch_test_mmx(ctx: &mut JitContext) {
  1122. // generate if(cr[0] & (CR0_EM | CR0_TS)) { task_switch_test_mmx_jit(); goto exit_with_fault; }
  1123. let cr0_offset = global_pointers::get_creg_offset(0);
  1124. dbg_assert!(regs::CR0_EM | regs::CR0_TS <= 0xFF);
  1125. ctx.builder.load_fixed_u8(cr0_offset);
  1126. ctx.builder.const_i32((regs::CR0_EM | regs::CR0_TS) as i32);
  1127. ctx.builder.and_i32();
  1128. ctx.builder.if_void();
  1129. {
  1130. gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction);
  1131. gen_fn1_const(
  1132. ctx.builder,
  1133. "task_switch_test_mmx_jit",
  1134. ctx.start_of_current_instruction,
  1135. );
  1136. ctx.builder.br(ctx.exit_with_fault_label);
  1137. }
  1138. ctx.builder.block_end();
  1139. }
  1140. pub fn gen_push16(ctx: &mut JitContext, value_local: &WasmLocal) {
  1141. if ctx.cpu.ssize_32() {
  1142. gen_get_reg32(ctx, regs::ESP);
  1143. }
  1144. else {
  1145. gen_get_reg16(ctx, regs::SP);
  1146. };
  1147. ctx.builder.const_i32(2);
  1148. ctx.builder.sub_i32();
  1149. let reg_updated_local = if !ctx.cpu.ssize_32() || !ctx.cpu.has_flat_segmentation() {
  1150. let reg_updated_local = ctx.builder.tee_new_local();
  1151. if !ctx.cpu.ssize_32() {
  1152. ctx.builder.const_i32(0xFFFF);
  1153. ctx.builder.and_i32();
  1154. }
  1155. if !ctx.cpu.has_flat_segmentation() {
  1156. gen_get_ss_offset(ctx);
  1157. ctx.builder.add_i32();
  1158. }
  1159. let sp_local = ctx.builder.set_new_local();
  1160. gen_safe_write16(ctx, &sp_local, &value_local);
  1161. ctx.builder.free_local(sp_local);
  1162. ctx.builder.get_local(&reg_updated_local);
  1163. reg_updated_local
  1164. }
  1165. else {
  1166. // short path: The address written to is equal to ESP/SP minus two
  1167. let reg_updated_local = ctx.builder.tee_new_local();
  1168. gen_safe_write16(ctx, &reg_updated_local, &value_local);
  1169. reg_updated_local
  1170. };
  1171. if ctx.cpu.ssize_32() {
  1172. gen_set_reg32(ctx, regs::ESP);
  1173. }
  1174. else {
  1175. gen_set_reg16(ctx, regs::SP);
  1176. };
  1177. ctx.builder.free_local(reg_updated_local);
  1178. }
  1179. pub fn gen_push32(ctx: &mut JitContext, value_local: &WasmLocal) {
  1180. if ctx.cpu.ssize_32() {
  1181. gen_get_reg32(ctx, regs::ESP);
  1182. }
  1183. else {
  1184. gen_get_reg16(ctx, regs::SP);
  1185. };
  1186. ctx.builder.const_i32(4);
  1187. ctx.builder.sub_i32();
  1188. let new_sp_local = if !ctx.cpu.ssize_32() || !ctx.cpu.has_flat_segmentation() {
  1189. let new_sp_local = ctx.builder.tee_new_local();
  1190. if !ctx.cpu.ssize_32() {
  1191. ctx.builder.const_i32(0xFFFF);
  1192. ctx.builder.and_i32();
  1193. }
  1194. if !ctx.cpu.has_flat_segmentation() {
  1195. gen_get_ss_offset(ctx);
  1196. ctx.builder.add_i32();
  1197. }
  1198. let sp_local = ctx.builder.set_new_local();
  1199. gen_safe_write32(ctx, &sp_local, &value_local);
  1200. ctx.builder.free_local(sp_local);
  1201. ctx.builder.get_local(&new_sp_local);
  1202. new_sp_local
  1203. }
  1204. else {
  1205. // short path: The address written to is equal to ESP/SP minus four
  1206. let new_sp_local = ctx.builder.tee_new_local();
  1207. gen_safe_write32(ctx, &new_sp_local, &value_local);
  1208. new_sp_local
  1209. };
  1210. if ctx.cpu.ssize_32() {
  1211. gen_set_reg32(ctx, regs::ESP);
  1212. }
  1213. else {
  1214. gen_set_reg16(ctx, regs::SP);
  1215. };
  1216. ctx.builder.free_local(new_sp_local);
  1217. }
  1218. pub fn gen_get_real_eip(ctx: &mut JitContext) {
  1219. gen_get_eip(ctx.builder);
  1220. ctx.builder
  1221. .load_fixed_i32(global_pointers::get_seg_offset(regs::CS));
  1222. ctx.builder.sub_i32();
  1223. }
  1224. pub fn gen_set_last_op1(builder: &mut WasmBuilder, source: &WasmLocal) {
  1225. builder.const_i32(global_pointers::last_op1 as i32);
  1226. builder.get_local(&source);
  1227. builder.store_aligned_i32(0);
  1228. }
  1229. pub fn gen_set_last_result(builder: &mut WasmBuilder, source: &WasmLocal) {
  1230. builder.const_i32(global_pointers::last_result as i32);
  1231. builder.get_local(&source);
  1232. builder.store_aligned_i32(0);
  1233. }
  1234. pub fn gen_set_last_op_size(builder: &mut WasmBuilder, value: i32) {
  1235. builder.const_i32(global_pointers::last_op_size as i32);
  1236. builder.const_i32(value);
  1237. builder.store_aligned_i32(0);
  1238. }
  1239. pub fn gen_set_flags_changed(builder: &mut WasmBuilder, value: i32) {
  1240. builder.const_i32(global_pointers::flags_changed as i32);
  1241. builder.const_i32(value);
  1242. builder.store_aligned_i32(0);
  1243. }
  1244. pub fn gen_clear_flags_changed_bits(builder: &mut WasmBuilder, bits_to_clear: i32) {
  1245. builder.const_i32(global_pointers::flags_changed as i32);
  1246. gen_get_flags_changed(builder);
  1247. builder.const_i32(!bits_to_clear);
  1248. builder.and_i32();
  1249. builder.store_aligned_i32(0);
  1250. }
  1251. pub fn gen_set_flags_bits(builder: &mut WasmBuilder, bits_to_set: i32) {
  1252. builder.const_i32(global_pointers::flags as i32);
  1253. gen_get_flags(builder);
  1254. builder.const_i32(bits_to_set);
  1255. builder.or_i32();
  1256. builder.store_aligned_i32(0);
  1257. }
  1258. pub fn gen_clear_flags_bits(builder: &mut WasmBuilder, bits_to_clear: i32) {
  1259. builder.const_i32(global_pointers::flags as i32);
  1260. gen_get_flags(builder);
  1261. builder.const_i32(!bits_to_clear);
  1262. builder.and_i32();
  1263. builder.store_aligned_i32(0);
  1264. }
  1265. pub fn gen_getzf(builder: &mut WasmBuilder) {
  1266. gen_get_flags_changed(builder);
  1267. builder.const_i32(FLAG_ZERO);
  1268. builder.and_i32();
  1269. builder.if_i32();
  1270. gen_get_last_result(builder);
  1271. let last_result = builder.tee_new_local();
  1272. builder.const_i32(-1);
  1273. builder.xor_i32();
  1274. builder.get_local(&last_result);
  1275. builder.free_local(last_result);
  1276. builder.const_i32(1);
  1277. builder.sub_i32();
  1278. builder.and_i32();
  1279. gen_get_last_op_size(builder);
  1280. builder.shr_u_i32();
  1281. builder.const_i32(1);
  1282. builder.and_i32();
  1283. builder.else_();
  1284. gen_get_flags(builder);
  1285. builder.const_i32(FLAG_ZERO);
  1286. builder.and_i32();
  1287. builder.block_end();
  1288. }
  1289. pub fn gen_getcf(builder: &mut WasmBuilder) {
  1290. gen_get_flags_changed(builder);
  1291. let flags_changed = builder.tee_new_local();
  1292. builder.const_i32(FLAG_CARRY);
  1293. builder.and_i32();
  1294. builder.if_i32();
  1295. builder.get_local(&flags_changed);
  1296. builder.const_i32(31);
  1297. builder.shr_s_i32();
  1298. builder.free_local(flags_changed);
  1299. let sub_mask = builder.set_new_local();
  1300. gen_get_last_result(builder);
  1301. builder.get_local(&sub_mask);
  1302. builder.xor_i32();
  1303. gen_get_last_op1(builder);
  1304. builder.get_local(&sub_mask);
  1305. builder.xor_i32();
  1306. builder.ltu_i32();
  1307. builder.else_();
  1308. gen_get_flags(builder);
  1309. builder.const_i32(FLAG_CARRY);
  1310. builder.and_i32();
  1311. builder.block_end();
  1312. builder.free_local(sub_mask);
  1313. }
  1314. pub fn gen_getsf(builder: &mut WasmBuilder) {
  1315. gen_get_flags_changed(builder);
  1316. builder.const_i32(FLAG_SIGN);
  1317. builder.and_i32();
  1318. builder.if_i32();
  1319. {
  1320. gen_get_last_result(builder);
  1321. gen_get_last_op_size(builder);
  1322. builder.shr_u_i32();
  1323. builder.const_i32(1);
  1324. builder.and_i32();
  1325. }
  1326. builder.else_();
  1327. {
  1328. gen_get_flags(builder);
  1329. builder.const_i32(FLAG_SIGN);
  1330. builder.and_i32();
  1331. }
  1332. builder.block_end();
  1333. }
  1334. pub fn gen_getof(builder: &mut WasmBuilder) {
  1335. gen_get_flags_changed(builder);
  1336. let flags_changed = builder.tee_new_local();
  1337. builder.const_i32(FLAG_OVERFLOW);
  1338. builder.and_i32();
  1339. builder.if_i32();
  1340. {
  1341. gen_get_last_op1(builder);
  1342. let last_op1 = builder.tee_new_local();
  1343. gen_get_last_result(builder);
  1344. let last_result = builder.tee_new_local();
  1345. builder.xor_i32();
  1346. builder.get_local(&last_result);
  1347. builder.get_local(&last_op1);
  1348. builder.sub_i32();
  1349. gen_get_flags_changed(builder);
  1350. builder.const_i32(31);
  1351. builder.shr_u_i32();
  1352. builder.sub_i32();
  1353. builder.get_local(&last_result);
  1354. builder.xor_i32();
  1355. builder.and_i32();
  1356. gen_get_last_op_size(builder);
  1357. builder.shr_u_i32();
  1358. builder.const_i32(1);
  1359. builder.and_i32();
  1360. builder.free_local(last_op1);
  1361. builder.free_local(last_result);
  1362. }
  1363. builder.else_();
  1364. {
  1365. gen_get_flags(builder);
  1366. builder.const_i32(FLAG_OVERFLOW);
  1367. builder.and_i32();
  1368. }
  1369. builder.block_end();
  1370. builder.free_local(flags_changed);
  1371. }
  1372. pub fn gen_test_be(builder: &mut WasmBuilder) {
  1373. // TODO: A more efficient implementation is possible
  1374. gen_getcf(builder);
  1375. gen_getzf(builder);
  1376. builder.or_i32();
  1377. }
  1378. pub fn gen_test_l(builder: &mut WasmBuilder) {
  1379. // TODO: A more efficient implementation is possible
  1380. gen_getsf(builder);
  1381. builder.eqz_i32();
  1382. gen_getof(builder);
  1383. builder.eqz_i32();
  1384. builder.xor_i32();
  1385. }
  1386. pub fn gen_test_le(builder: &mut WasmBuilder) {
  1387. // TODO: A more efficient implementation is possible
  1388. gen_test_l(builder);
  1389. gen_getzf(builder);
  1390. builder.or_i32();
  1391. }
  1392. pub fn gen_test_loopnz(ctx: &mut JitContext, is_asize_32: bool) {
  1393. gen_test_loop(ctx, is_asize_32);
  1394. ctx.builder.eqz_i32();
  1395. gen_getzf(&mut ctx.builder);
  1396. ctx.builder.or_i32();
  1397. ctx.builder.eqz_i32();
  1398. }
  1399. pub fn gen_test_loopz(ctx: &mut JitContext, is_asize_32: bool) {
  1400. gen_test_loop(ctx, is_asize_32);
  1401. ctx.builder.eqz_i32();
  1402. gen_getzf(&mut ctx.builder);
  1403. ctx.builder.eqz_i32();
  1404. ctx.builder.or_i32();
  1405. ctx.builder.eqz_i32();
  1406. }
  1407. pub fn gen_test_loop(ctx: &mut JitContext, is_asize_32: bool) {
  1408. if is_asize_32 {
  1409. gen_get_reg32(ctx, regs::ECX);
  1410. }
  1411. else {
  1412. gen_get_reg16(ctx, regs::CX);
  1413. }
  1414. }
  1415. pub fn gen_test_jcxz(ctx: &mut JitContext, is_asize_32: bool) {
  1416. if is_asize_32 {
  1417. gen_get_reg32(ctx, regs::ECX);
  1418. }
  1419. else {
  1420. gen_get_reg16(ctx, regs::CX);
  1421. }
  1422. ctx.builder.eqz_i32();
  1423. }
  1424. pub fn gen_fpu_get_sti(ctx: &mut JitContext, i: u32) {
  1425. ctx.builder
  1426. .const_i32(global_pointers::sse_scratch_register as i32);
  1427. ctx.builder.const_i32(i as i32);
  1428. ctx.builder.call_fn2("fpu_get_sti");
  1429. ctx.builder
  1430. .load_fixed_i64(global_pointers::sse_scratch_register as u32);
  1431. ctx.builder
  1432. .load_fixed_u16(global_pointers::sse_scratch_register as u32 + 8);
  1433. }
  1434. pub fn gen_fpu_load_m32(ctx: &mut JitContext, modrm_byte: ModrmByte) {
  1435. ctx.builder
  1436. .const_i32(global_pointers::sse_scratch_register as i32);
  1437. gen_modrm_resolve_safe_read32(ctx, modrm_byte);
  1438. ctx.builder.call_fn2("f32_to_f80");
  1439. ctx.builder
  1440. .load_fixed_i64(global_pointers::sse_scratch_register as u32);
  1441. ctx.builder
  1442. .load_fixed_u16(global_pointers::sse_scratch_register as u32 + 8);
  1443. }
  1444. pub fn gen_fpu_load_m64(ctx: &mut JitContext, modrm_byte: ModrmByte) {
  1445. ctx.builder
  1446. .const_i32(global_pointers::sse_scratch_register as i32);
  1447. gen_modrm_resolve_safe_read64(ctx, modrm_byte);
  1448. ctx.builder.call_fn2_i32_i64("f64_to_f80");
  1449. ctx.builder
  1450. .load_fixed_i64(global_pointers::sse_scratch_register as u32);
  1451. ctx.builder
  1452. .load_fixed_u16(global_pointers::sse_scratch_register as u32 + 8);
  1453. }
  1454. pub fn gen_fpu_load_i16(ctx: &mut JitContext, modrm_byte: ModrmByte) {
  1455. ctx.builder
  1456. .const_i32(global_pointers::sse_scratch_register as i32);
  1457. gen_modrm_resolve_safe_read16(ctx, modrm_byte);
  1458. sign_extend_i16(ctx.builder);
  1459. ctx.builder.call_fn2("i32_to_f80");
  1460. ctx.builder
  1461. .load_fixed_i64(global_pointers::sse_scratch_register as u32);
  1462. ctx.builder
  1463. .load_fixed_u16(global_pointers::sse_scratch_register as u32 + 8);
  1464. }
  1465. pub fn gen_fpu_load_i32(ctx: &mut JitContext, modrm_byte: ModrmByte) {
  1466. ctx.builder
  1467. .const_i32(global_pointers::sse_scratch_register as i32);
  1468. gen_modrm_resolve_safe_read32(ctx, modrm_byte);
  1469. ctx.builder.call_fn2("i32_to_f80");
  1470. ctx.builder
  1471. .load_fixed_i64(global_pointers::sse_scratch_register as u32);
  1472. ctx.builder
  1473. .load_fixed_u16(global_pointers::sse_scratch_register as u32 + 8);
  1474. }
  1475. pub fn gen_fpu_load_i64(ctx: &mut JitContext, modrm_byte: ModrmByte) {
  1476. ctx.builder
  1477. .const_i32(global_pointers::sse_scratch_register as i32);
  1478. gen_modrm_resolve_safe_read64(ctx, modrm_byte);
  1479. ctx.builder.call_fn2_i32_i64("i64_to_f80");
  1480. ctx.builder
  1481. .load_fixed_i64(global_pointers::sse_scratch_register as u32);
  1482. ctx.builder
  1483. .load_fixed_u16(global_pointers::sse_scratch_register as u32 + 8);
  1484. }
  1485. pub fn gen_trigger_de(ctx: &mut JitContext) {
  1486. gen_fn1_const(
  1487. ctx.builder,
  1488. "trigger_de_jit",
  1489. ctx.start_of_current_instruction,
  1490. );
  1491. gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction);
  1492. ctx.builder.br(ctx.exit_with_fault_label);
  1493. }
  1494. pub fn gen_trigger_ud(ctx: &mut JitContext) {
  1495. gen_fn1_const(
  1496. ctx.builder,
  1497. "trigger_ud_jit",
  1498. ctx.start_of_current_instruction,
  1499. );
  1500. gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction);
  1501. ctx.builder.br(ctx.exit_with_fault_label);
  1502. }
  1503. pub fn gen_trigger_gp(ctx: &mut JitContext, error_code: u32) {
  1504. gen_fn2_const(
  1505. ctx.builder,
  1506. "trigger_gp_jit",
  1507. error_code,
  1508. ctx.start_of_current_instruction,
  1509. );
  1510. gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction);
  1511. ctx.builder.br(ctx.exit_with_fault_label);
  1512. }
  1513. pub fn gen_condition_fn(ctx: &mut JitContext, condition: u8) {
  1514. if condition & 0xF0 == 0x00 || condition & 0xF0 == 0x70 || condition & 0xF0 == 0x80 {
  1515. match condition & 0xF {
  1516. 0x0 => {
  1517. gen_getof(ctx.builder);
  1518. },
  1519. 0x1 => {
  1520. gen_getof(ctx.builder);
  1521. ctx.builder.eqz_i32();
  1522. },
  1523. 0x2 => {
  1524. gen_getcf(ctx.builder);
  1525. },
  1526. 0x3 => {
  1527. gen_getcf(ctx.builder);
  1528. ctx.builder.eqz_i32();
  1529. },
  1530. 0x4 => {
  1531. gen_getzf(ctx.builder);
  1532. },
  1533. 0x5 => {
  1534. gen_getzf(ctx.builder);
  1535. ctx.builder.eqz_i32();
  1536. },
  1537. 0x6 => {
  1538. gen_test_be(ctx.builder);
  1539. },
  1540. 0x7 => {
  1541. gen_test_be(ctx.builder);
  1542. ctx.builder.eqz_i32();
  1543. },
  1544. 0x8 => {
  1545. gen_getsf(ctx.builder);
  1546. },
  1547. 0x9 => {
  1548. gen_getsf(ctx.builder);
  1549. ctx.builder.eqz_i32();
  1550. },
  1551. 0xA => ctx.builder.call_fn0_ret("test_p"),
  1552. 0xB => ctx.builder.call_fn0_ret("test_np"),
  1553. 0xC => {
  1554. gen_test_l(ctx.builder);
  1555. },
  1556. 0xD => {
  1557. gen_test_l(ctx.builder);
  1558. ctx.builder.eqz_i32();
  1559. },
  1560. 0xE => {
  1561. gen_test_le(ctx.builder);
  1562. },
  1563. 0xF => {
  1564. gen_test_le(ctx.builder);
  1565. ctx.builder.eqz_i32();
  1566. },
  1567. _ => dbg_assert!(false),
  1568. }
  1569. }
  1570. else {
  1571. // loop, loopnz, loopz, jcxz
  1572. dbg_assert!(condition & !0x3 == 0xE0);
  1573. if condition == 0xE0 {
  1574. gen_test_loopnz(ctx, ctx.cpu.asize_32());
  1575. }
  1576. else if condition == 0xE1 {
  1577. gen_test_loopz(ctx, ctx.cpu.asize_32());
  1578. }
  1579. else if condition == 0xE2 {
  1580. gen_test_loop(ctx, ctx.cpu.asize_32());
  1581. }
  1582. else if condition == 0xE3 {
  1583. gen_test_jcxz(ctx, ctx.cpu.asize_32());
  1584. }
  1585. }
  1586. }
  1587. pub fn gen_move_registers_from_locals_to_memory(ctx: &mut JitContext) {
  1588. let instruction = memory::read32s(ctx.start_of_current_instruction) as u32;
  1589. ::opstats::gen_opstat_unguarded_register(ctx.builder, instruction);
  1590. for i in 0..8 {
  1591. ctx.builder
  1592. .const_i32(global_pointers::get_reg32_offset(i as u32) as i32);
  1593. ctx.builder.get_local(&ctx.register_locals[i]);
  1594. ctx.builder.store_aligned_i32(0);
  1595. }
  1596. }
  1597. pub fn gen_move_registers_from_memory_to_locals(ctx: &mut JitContext) {
  1598. let instruction = memory::read32s(ctx.start_of_current_instruction) as u32;
  1599. ::opstats::gen_opstat_unguarded_register(ctx.builder, instruction);
  1600. for i in 0..8 {
  1601. ctx.builder
  1602. .const_i32(global_pointers::get_reg32_offset(i as u32) as i32);
  1603. ctx.builder.load_aligned_i32(0);
  1604. ctx.builder.set_local(&ctx.register_locals[i]);
  1605. }
  1606. }
  1607. pub fn gen_profiler_stat_increment(builder: &mut WasmBuilder, stat: profiler::stat) {
  1608. if !cfg!(feature = "profiler") {
  1609. return;
  1610. }
  1611. let addr = unsafe { profiler::stat_array.as_mut_ptr().offset(stat as isize) } as u32;
  1612. builder.increment_fixed_i32(addr, 1)
  1613. }
  1614. pub fn gen_debug_track_jit_exit(builder: &mut WasmBuilder, address: u32) {
  1615. if cfg!(feature = "profiler") {
  1616. gen_fn1_const(builder, "track_jit_exit", address);
  1617. }
  1618. }