jit.rs 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746
  1. use std::collections::{BTreeMap, HashMap, HashSet};
  2. use std::iter::FromIterator;
  3. use std::mem;
  4. use std::ptr::NonNull;
  5. use analysis::AnalysisType;
  6. use codegen;
  7. use cpu::cpu;
  8. use cpu::memory;
  9. use cpu_context::CpuContext;
  10. use global_pointers;
  11. use jit_instructions;
  12. use page::Page;
  13. use profiler;
  14. use profiler::stat;
  15. use state_flags::CachedStateFlags;
  16. use util::SafeToU16;
  17. use wasmgen::wasm_builder::{WasmBuilder, WasmLocal};
  18. mod unsafe_jit {
  19. extern "C" {
  20. pub fn codegen_finalize(
  21. wasm_table_index: u16,
  22. phys_addr: u32,
  23. end_addr: u32,
  24. first_opcode: u32,
  25. state_flags: u32,
  26. );
  27. pub fn jit_clear_func(wasm_table_index: u16);
  28. pub fn jit_clear_all_funcs();
  29. }
  30. }
  31. fn codegen_finalize(
  32. wasm_table_index: u16,
  33. phys_addr: u32,
  34. end_addr: u32,
  35. first_opcode: u32,
  36. state_flags: CachedStateFlags,
  37. ) {
  38. unsafe {
  39. unsafe_jit::codegen_finalize(
  40. wasm_table_index,
  41. phys_addr,
  42. end_addr,
  43. first_opcode,
  44. state_flags.to_u32(),
  45. )
  46. }
  47. }
  48. pub fn jit_clear_func(wasm_table_index: u16) {
  49. unsafe { unsafe_jit::jit_clear_func(wasm_table_index) }
  50. }
  51. pub fn jit_clear_all_funcs() { unsafe { unsafe_jit::jit_clear_all_funcs() } }
  52. pub const WASM_TABLE_SIZE: u32 = 900;
  53. pub const HASH_PRIME: u32 = 6151;
  54. pub const CHECK_JIT_CACHE_ARRAY_INVARIANTS: bool = false;
  55. pub const JIT_MAX_ITERATIONS_PER_FUNCTION: u32 = 10000;
  56. pub const JIT_ALWAYS_USE_LOOP_SAFETY: bool = true;
  57. pub const JIT_THRESHOLD: u32 = 200 * 1000;
  58. const CODE_CACHE_SEARCH_SIZE: u32 = 8;
  59. const MAX_INSTRUCTION_LENGTH: u32 = 16;
  60. #[allow(non_upper_case_globals)]
  61. static mut jit_state: NonNull<JitState> =
  62. unsafe { NonNull::new_unchecked(mem::align_of::<JitState>() as *mut _) };
  63. pub fn get_jit_state() -> &'static mut JitState { unsafe { jit_state.as_mut() } }
  64. #[no_mangle]
  65. pub fn rust_init() {
  66. let x = Box::new(JitState::create_and_initialise());
  67. unsafe {
  68. jit_state = NonNull::new(Box::into_raw(x)).unwrap()
  69. }
  70. use std::panic;
  71. panic::set_hook(Box::new(|panic_info| {
  72. console_log!("{}", panic_info.to_string());
  73. }));
  74. }
  75. mod jit_cache_array {
  76. use page::Page;
  77. use state_flags::CachedStateFlags;
  78. // Note: For performance reasons, this is global state. See jit_find_cache_entry
  79. const NO_NEXT_ENTRY: u32 = 0xffff_ffff;
  80. // When changing this, you also need to bump global-base
  81. pub const SIZE: u32 = 0x40000;
  82. pub const MASK: u32 = SIZE - 1;
  83. #[derive(Copy, Clone)]
  84. pub struct Entry {
  85. pub start_addr: u32,
  86. #[cfg(any(debug_assertions, feature = "profiler"))]
  87. pub len: u32,
  88. #[cfg(debug_assertions)]
  89. pub opcode: u32,
  90. // an index into jit_cache_array for the next code_cache entry within the same physical page
  91. next_index_same_page: u32,
  92. pub initial_state: u16,
  93. pub wasm_table_index: u16,
  94. pub state_flags: CachedStateFlags,
  95. pub pending: bool,
  96. }
  97. impl Entry {
  98. pub fn create(
  99. start_addr: u32,
  100. next_index_same_page: Option<u32>,
  101. wasm_table_index: u16,
  102. initial_state: u16,
  103. state_flags: CachedStateFlags,
  104. pending: bool,
  105. ) -> Entry {
  106. let next_index_same_page = next_index_same_page.unwrap_or(NO_NEXT_ENTRY);
  107. Entry {
  108. start_addr,
  109. next_index_same_page,
  110. wasm_table_index,
  111. initial_state,
  112. state_flags,
  113. pending,
  114. #[cfg(any(debug_assertions, feature = "profiler"))]
  115. len: 0,
  116. #[cfg(debug_assertions)]
  117. opcode: 0,
  118. }
  119. }
  120. pub fn next_index_same_page(&self) -> Option<u32> {
  121. if self.next_index_same_page == NO_NEXT_ENTRY {
  122. None
  123. }
  124. else {
  125. Some(self.next_index_same_page)
  126. }
  127. }
  128. pub fn set_next_index_same_page(&mut self, next_index: Option<u32>) {
  129. if let Some(i) = next_index {
  130. self.next_index_same_page = i
  131. }
  132. else {
  133. self.next_index_same_page = NO_NEXT_ENTRY
  134. }
  135. }
  136. }
  137. const DEFAULT_ENTRY: Entry = Entry {
  138. start_addr: 0,
  139. next_index_same_page: NO_NEXT_ENTRY,
  140. wasm_table_index: 0,
  141. initial_state: 0,
  142. state_flags: CachedStateFlags::EMPTY,
  143. pending: false,
  144. #[cfg(any(debug_assertions, feature = "profiler"))]
  145. len: 0,
  146. #[cfg(debug_assertions)]
  147. opcode: 0,
  148. };
  149. #[allow(non_upper_case_globals)]
  150. pub const jit_cache_array: *mut Entry = ::global_pointers::JIT_CACHE_ARRAY as *mut Entry;
  151. #[allow(unreachable_code)]
  152. #[cfg(debug_assertions)]
  153. unsafe fn _static_assert() { std::mem::transmute::<Entry, [u8; 24]>(panic!()); }
  154. #[allow(unreachable_code)]
  155. #[cfg(all(not(debug_assertions), not(feature = "profiler")))]
  156. unsafe fn _static_assert() { std::mem::transmute::<Entry, [u8; 16]>(panic!()); }
  157. // XXX: Probably doesn't need to be statically allocated
  158. #[allow(non_upper_case_globals)]
  159. pub const page_first_entry: *mut u32 = ::global_pointers::JIT_PAGE_FIRST_ENTRY as *mut u32;
  160. pub fn get_page_index(page: Page) -> Option<u32> {
  161. let index = unsafe { *page_first_entry.offset(page.to_u32() as isize) };
  162. if index == NO_NEXT_ENTRY { None } else { Some(index) }
  163. }
  164. pub fn set_page_index(page: Page, index: Option<u32>) {
  165. let index = index.unwrap_or(NO_NEXT_ENTRY);
  166. unsafe { *page_first_entry.offset(page.to_u32() as isize) = index }
  167. }
  168. pub fn get(i: u32) -> &'static Entry { unsafe { &*jit_cache_array.offset(i as isize) } }
  169. pub fn get_mut(i: u32) -> &'static mut Entry {
  170. unsafe { &mut *jit_cache_array.offset(i as isize) }
  171. }
  172. fn set(i: u32, entry: Entry) {
  173. unsafe {
  174. *jit_cache_array.offset(i as isize) = entry
  175. };
  176. }
  177. pub fn insert(index: u32, mut entry: Entry) {
  178. let page = Page::page_of(entry.start_addr);
  179. let previous_entry_index = get_page_index(page);
  180. if let Some(previous_entry_index) = previous_entry_index {
  181. let previous_entry = get(previous_entry_index);
  182. if previous_entry.start_addr != 0 {
  183. dbg_assert!(
  184. Page::page_of(previous_entry.start_addr) == Page::page_of(entry.start_addr)
  185. );
  186. }
  187. }
  188. set_page_index(page, Some(index));
  189. entry.set_next_index_same_page(previous_entry_index);
  190. set(index, entry);
  191. }
  192. pub fn remove(index: u32) {
  193. let page = Page::page_of((get(index)).start_addr);
  194. let mut page_index = get_page_index(page);
  195. let mut did_remove = false;
  196. if page_index == Some(index) {
  197. set_page_index(page, (get(index)).next_index_same_page());
  198. did_remove = true;
  199. }
  200. else {
  201. while let Some(page_index_ok) = page_index {
  202. let next_index = (get(page_index_ok)).next_index_same_page();
  203. if next_index == Some(index) {
  204. (get_mut(page_index_ok))
  205. .set_next_index_same_page((get(index)).next_index_same_page());
  206. did_remove = true;
  207. break;
  208. }
  209. page_index = next_index;
  210. }
  211. }
  212. (get_mut(index)).set_next_index_same_page(None);
  213. dbg_assert!(did_remove);
  214. }
  215. pub fn clear() {
  216. unsafe {
  217. for i in 0..SIZE {
  218. *jit_cache_array.offset(i as isize) = DEFAULT_ENTRY;
  219. }
  220. for i in 0..0x100000 {
  221. *page_first_entry.offset(i) = NO_NEXT_ENTRY;
  222. }
  223. }
  224. }
  225. pub fn check_invariants() {
  226. if !::jit::CHECK_JIT_CACHE_ARRAY_INVARIANTS {
  227. return;
  228. }
  229. // there are no loops in the linked lists
  230. // https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_Tortoise_and_Hare
  231. for i in 0..(1 << 20) {
  232. let mut slow = get_page_index(Page::page_of(i << 12));
  233. let mut fast = slow;
  234. while let Some(fast_ok) = fast {
  235. fast = (get(fast_ok)).next_index_same_page();
  236. slow = (get(slow.unwrap())).next_index_same_page();
  237. if let Some(fast_ok) = fast {
  238. fast = (get(fast_ok)).next_index_same_page();
  239. }
  240. else {
  241. break;
  242. }
  243. dbg_assert!(slow != fast);
  244. }
  245. }
  246. let mut wasm_table_index_to_jit_cache_index = [0; ::jit::WASM_TABLE_SIZE as usize];
  247. for i in 0..SIZE {
  248. let entry = get(i);
  249. dbg_assert!(entry.next_index_same_page().map_or(true, |i| i < SIZE));
  250. if entry.pending {
  251. dbg_assert!(entry.start_addr != 0);
  252. dbg_assert!(entry.wasm_table_index != 0);
  253. }
  254. else {
  255. // an invalid entry has both its start_addr and wasm_table_index set to 0
  256. // neither start_addr nor wasm_table_index are 0 for any valid entry
  257. dbg_assert!((entry.start_addr == 0) == (entry.wasm_table_index == 0));
  258. }
  259. // having a next entry implies validity
  260. dbg_assert!(entry.next_index_same_page() == None || entry.start_addr != 0);
  261. // any valid wasm_table_index can only be used within a single page
  262. if entry.wasm_table_index != 0 {
  263. let j = wasm_table_index_to_jit_cache_index[entry.wasm_table_index as usize];
  264. if j != 0 {
  265. let other_entry = get(j);
  266. dbg_assert!(other_entry.wasm_table_index == entry.wasm_table_index);
  267. dbg_assert!(
  268. Page::page_of(other_entry.start_addr) == Page::page_of(entry.start_addr)
  269. );
  270. }
  271. else {
  272. wasm_table_index_to_jit_cache_index[entry.wasm_table_index as usize] = i as u32;
  273. }
  274. }
  275. if entry.start_addr != 0 {
  276. // valid entries can be reached from page_first_entry
  277. let mut reached = false;
  278. let page = Page::page_of(entry.start_addr);
  279. let mut cache_array_index = get_page_index(page);
  280. while let Some(index) = cache_array_index {
  281. let other_entry = get(index);
  282. if i as u32 == index {
  283. reached = true;
  284. break;
  285. }
  286. cache_array_index = other_entry.next_index_same_page();
  287. }
  288. dbg_assert!(reached);
  289. }
  290. }
  291. }
  292. }
  293. pub struct JitState {
  294. // as an alternative to HashSet, we could use a bitmap of 4096 bits here
  295. // (faster, but uses much more memory)
  296. // or a compressed bitmap (likely faster)
  297. hot_pages: [u32; HASH_PRIME as usize],
  298. wasm_table_index_free_list: Vec<u16>,
  299. wasm_table_index_pending_free: Vec<u16>,
  300. entry_points: HashMap<Page, HashSet<u16>>,
  301. wasm_builder: WasmBuilder,
  302. }
  303. impl JitState {
  304. pub fn create_and_initialise() -> JitState {
  305. jit_cache_array::clear();
  306. // don't assign 0 (XXX: Check)
  307. let wasm_table_indices = 1..=(WASM_TABLE_SIZE - 1) as u16;
  308. JitState {
  309. hot_pages: [0; HASH_PRIME as usize],
  310. wasm_table_index_free_list: Vec::from_iter(wasm_table_indices),
  311. wasm_table_index_pending_free: vec![],
  312. entry_points: HashMap::new(),
  313. wasm_builder: WasmBuilder::new(),
  314. }
  315. }
  316. }
  317. #[derive(PartialEq, Eq)]
  318. enum BasicBlockType {
  319. Normal {
  320. next_block_addr: u32,
  321. },
  322. ConditionalJump {
  323. next_block_addr: Option<u32>,
  324. next_block_branch_taken_addr: Option<u32>,
  325. condition: u8,
  326. jump_offset: i32,
  327. jump_offset_is_32: bool,
  328. },
  329. Exit,
  330. }
  331. struct BasicBlock {
  332. addr: u32,
  333. last_instruction_addr: u32,
  334. end_addr: u32,
  335. is_entry_block: bool,
  336. ty: BasicBlockType,
  337. has_sti: bool,
  338. number_of_instructions: u32,
  339. }
  340. #[repr(C)]
  341. #[derive(Copy, Clone, PartialEq)]
  342. pub struct cached_code {
  343. pub wasm_table_index: u16,
  344. pub initial_state: u16,
  345. }
  346. impl cached_code {
  347. pub const NONE: cached_code = cached_code {
  348. wasm_table_index: 0,
  349. initial_state: 0,
  350. };
  351. }
  352. pub struct JitContext<'a> {
  353. pub cpu: &'a mut CpuContext,
  354. pub builder: &'a mut WasmBuilder,
  355. pub register_locals: &'a mut Vec<WasmLocal>,
  356. pub start_of_current_instruction: u32,
  357. pub current_brtable_depth: u32,
  358. pub our_wasm_table_index: u16,
  359. pub basic_block_index_local: &'a WasmLocal,
  360. pub state_flags: CachedStateFlags,
  361. }
  362. pub const JIT_INSTR_BLOCK_BOUNDARY_FLAG: u32 = 1 << 0;
  363. fn jit_hot_hash_page(page: Page) -> u32 { page.to_u32() % HASH_PRIME }
  364. fn is_near_end_of_page(address: u32) -> bool { address & 0xFFF >= 0x1000 - MAX_INSTRUCTION_LENGTH }
  365. pub fn jit_find_cache_entry(phys_address: u32, state_flags: CachedStateFlags) -> cached_code {
  366. if is_near_end_of_page(phys_address) {
  367. profiler::stat_increment(stat::RUN_INTERPRETED_NEAR_END_OF_PAGE);
  368. }
  369. let mut run_interpreted_reason = None;
  370. for i in 0..CODE_CACHE_SEARCH_SIZE {
  371. let index = (phys_address + i) & jit_cache_array::MASK;
  372. let entry = jit_cache_array::get(index);
  373. if entry.start_addr == phys_address {
  374. if entry.pending {
  375. run_interpreted_reason = Some(stat::RUN_INTERPRETED_PENDING)
  376. }
  377. if entry.state_flags != state_flags {
  378. run_interpreted_reason = Some(stat::RUN_INTERPRETED_DIFFERENT_STATE)
  379. }
  380. }
  381. if is_near_end_of_page(phys_address) {
  382. dbg_assert!(entry.start_addr != phys_address);
  383. }
  384. if !entry.pending && entry.start_addr == phys_address && entry.state_flags == state_flags {
  385. #[cfg(debug_assertions)] // entry.opcode is not defined otherwise
  386. {
  387. dbg_assert!(memory::read32s(entry.start_addr) as u32 == entry.opcode);
  388. }
  389. return cached_code {
  390. wasm_table_index: entry.wasm_table_index,
  391. initial_state: entry.initial_state,
  392. };
  393. }
  394. }
  395. if let Some(reason) = run_interpreted_reason {
  396. profiler::stat_increment(reason);
  397. }
  398. cached_code::NONE
  399. }
  400. #[no_mangle]
  401. pub fn jit_find_cache_entry_in_page(
  402. virt_eip: i32,
  403. phys_eip: u32,
  404. wasm_table_index: u16,
  405. state_flags: u32,
  406. ) -> i32 {
  407. let state_flags = CachedStateFlags::of_u32(state_flags);
  408. let phys_address = virt_eip as u32 & 0xFFF | phys_eip & !0xFFF;
  409. for i in 0..CODE_CACHE_SEARCH_SIZE {
  410. let index = (phys_address + i) & jit_cache_array::MASK;
  411. let entry = jit_cache_array::get(index);
  412. if is_near_end_of_page(phys_address) {
  413. dbg_assert!(entry.start_addr != phys_address);
  414. }
  415. if !entry.pending
  416. && entry.start_addr == phys_address
  417. && entry.state_flags == state_flags
  418. && entry.wasm_table_index == wasm_table_index
  419. {
  420. #[cfg(debug_assertions)] // entry.opcode is not defined otherwise
  421. {
  422. dbg_assert!(memory::read32s(entry.start_addr) as u32 == entry.opcode);
  423. }
  424. if false {
  425. dbg_log!(
  426. "jit_find_cache_entry_in_page hit {:x} {:x}",
  427. virt_eip as u32,
  428. phys_eip,
  429. );
  430. }
  431. return entry.initial_state as i32;
  432. }
  433. }
  434. if false {
  435. dbg_log!(
  436. "jit_find_cache_entry_in_page miss {:x} {:x}",
  437. virt_eip as u32,
  438. phys_eip,
  439. );
  440. }
  441. return -1;
  442. }
  443. pub fn record_entry_point(phys_address: u32) {
  444. let ctx = get_jit_state();
  445. if is_near_end_of_page(phys_address) {
  446. return;
  447. }
  448. let page = Page::page_of(phys_address);
  449. let offset_in_page = phys_address as u16 & 0xFFF;
  450. let mut is_new = false;
  451. ctx.entry_points
  452. .entry(page)
  453. .or_insert_with(|| {
  454. is_new = true;
  455. HashSet::new()
  456. })
  457. .insert(offset_in_page);
  458. if is_new {
  459. cpu::tlb_set_has_code(page, true);
  460. }
  461. }
  462. fn jit_find_basic_blocks(
  463. page: Page,
  464. entry_points: &HashSet<u16>,
  465. cpu: CpuContext,
  466. ) -> (Vec<BasicBlock>, bool) {
  467. let mut to_visit_stack: Vec<u16> = entry_points.iter().cloned().collect();
  468. let mut marked_as_entry: HashSet<u16> = entry_points.clone();
  469. let page_high_bits = page.to_address();
  470. let mut basic_blocks: BTreeMap<u32, BasicBlock> = BTreeMap::new();
  471. let mut requires_loop_limit = false;
  472. while let Some(to_visit_offset) = to_visit_stack.pop() {
  473. let to_visit = to_visit_offset as u32 | page_high_bits;
  474. if basic_blocks.contains_key(&to_visit) {
  475. continue;
  476. }
  477. if is_near_end_of_page(to_visit) {
  478. // Empty basic block, don't insert
  479. profiler::stat_increment(stat::COMPILE_CUT_OFF_AT_END_OF_PAGE);
  480. continue;
  481. }
  482. let mut current_address = to_visit;
  483. let mut current_block = BasicBlock {
  484. addr: current_address,
  485. last_instruction_addr: 0,
  486. end_addr: 0,
  487. ty: BasicBlockType::Exit,
  488. is_entry_block: false,
  489. has_sti: false,
  490. number_of_instructions: 0,
  491. };
  492. loop {
  493. let addr_before_instruction = current_address;
  494. let mut ctx = &mut CpuContext {
  495. eip: current_address,
  496. ..cpu
  497. };
  498. let analysis = ::analysis::analyze_step(&mut ctx);
  499. current_block.number_of_instructions += 1;
  500. let has_next_instruction = !analysis.no_next_instruction;
  501. current_address = ctx.eip;
  502. match analysis.ty {
  503. AnalysisType::Normal | AnalysisType::STI => {
  504. dbg_assert!(has_next_instruction);
  505. if current_block.has_sti {
  506. // Convert next instruction after STI (i.e., the current instruction) into block boundary
  507. marked_as_entry.insert(current_address as u16 & 0xFFF);
  508. to_visit_stack.push(current_address as u16 & 0xFFF);
  509. current_block.last_instruction_addr = addr_before_instruction;
  510. current_block.end_addr = current_address;
  511. break;
  512. }
  513. if analysis.ty == AnalysisType::STI {
  514. current_block.has_sti = true;
  515. dbg_assert!(
  516. !is_near_end_of_page(current_address),
  517. "TODO: Handle STI instruction near end of page"
  518. );
  519. }
  520. else {
  521. // Only split non-STI blocks (one instruction needs to run after STI before
  522. // handle_irqs may be called)
  523. if basic_blocks.contains_key(&current_address) {
  524. current_block.last_instruction_addr = addr_before_instruction;
  525. current_block.end_addr = current_address;
  526. dbg_assert!(!is_near_end_of_page(current_address));
  527. current_block.ty = BasicBlockType::Normal {
  528. next_block_addr: current_address,
  529. };
  530. break;
  531. }
  532. }
  533. },
  534. AnalysisType::Jump {
  535. offset,
  536. is_32,
  537. condition: Some(condition),
  538. } => {
  539. // conditional jump: continue at next and continue at jump target
  540. let jump_target = if is_32 {
  541. current_address.wrapping_add(offset as u32)
  542. }
  543. else {
  544. ctx.cs_offset.wrapping_add(
  545. (current_address
  546. .wrapping_sub(ctx.cs_offset)
  547. .wrapping_add(offset as u32))
  548. & 0xFFFF,
  549. )
  550. };
  551. dbg_assert!(has_next_instruction);
  552. to_visit_stack.push(current_address as u16 & 0xFFF);
  553. let next_block_branch_taken_addr;
  554. if Page::page_of(jump_target) == page && !is_near_end_of_page(jump_target) {
  555. to_visit_stack.push(jump_target as u16 & 0xFFF);
  556. next_block_branch_taken_addr = Some(jump_target);
  557. // Very simple heuristic for "infinite loops": This
  558. // detects Linux's "calibrating delay loop"
  559. if jump_target == current_block.addr {
  560. dbg_log!("Basic block looping back to front");
  561. requires_loop_limit = true;
  562. }
  563. }
  564. else {
  565. next_block_branch_taken_addr = None;
  566. }
  567. let next_block_addr = if is_near_end_of_page(current_address) {
  568. None
  569. }
  570. else {
  571. Some(current_address)
  572. };
  573. current_block.ty = BasicBlockType::ConditionalJump {
  574. next_block_addr,
  575. next_block_branch_taken_addr,
  576. condition,
  577. jump_offset: offset,
  578. jump_offset_is_32: is_32,
  579. };
  580. current_block.last_instruction_addr = addr_before_instruction;
  581. current_block.end_addr = current_address;
  582. break;
  583. },
  584. AnalysisType::Jump {
  585. offset,
  586. is_32,
  587. condition: None,
  588. } => {
  589. // non-conditional jump: continue at jump target
  590. let jump_target = if is_32 {
  591. current_address.wrapping_add(offset as u32)
  592. }
  593. else {
  594. ctx.cs_offset.wrapping_add(
  595. (current_address
  596. .wrapping_sub(ctx.cs_offset)
  597. .wrapping_add(offset as u32))
  598. & 0xFFFF,
  599. )
  600. };
  601. if has_next_instruction {
  602. // Execution will eventually come back to the next instruction (CALL)
  603. marked_as_entry.insert(current_address as u16 & 0xFFF);
  604. to_visit_stack.push(current_address as u16 & 0xFFF);
  605. }
  606. if Page::page_of(jump_target) == page && !is_near_end_of_page(jump_target) {
  607. current_block.ty = BasicBlockType::Normal {
  608. next_block_addr: jump_target,
  609. };
  610. to_visit_stack.push(jump_target as u16 & 0xFFF);
  611. }
  612. else {
  613. current_block.ty = BasicBlockType::Exit;
  614. }
  615. current_block.last_instruction_addr = addr_before_instruction;
  616. current_block.end_addr = current_address;
  617. break;
  618. },
  619. AnalysisType::BlockBoundary => {
  620. // a block boundary but not a jump, get out
  621. if has_next_instruction {
  622. // block boundary, but execution will eventually come back
  623. // to the next instruction. Create a new basic block
  624. // starting at the next instruction and register it as an
  625. // entry point
  626. marked_as_entry.insert(current_address as u16 & 0xFFF);
  627. to_visit_stack.push(current_address as u16 & 0xFFF);
  628. }
  629. current_block.last_instruction_addr = addr_before_instruction;
  630. current_block.end_addr = current_address;
  631. break;
  632. },
  633. }
  634. if is_near_end_of_page(current_address) {
  635. current_block.last_instruction_addr = addr_before_instruction;
  636. current_block.end_addr = current_address;
  637. profiler::stat_increment(stat::COMPILE_CUT_OFF_AT_END_OF_PAGE);
  638. break;
  639. }
  640. }
  641. let previous_block = basic_blocks
  642. .range(..current_block.addr)
  643. .next_back()
  644. .filter(|(_, previous_block)| (!previous_block.has_sti))
  645. .map(|(_, previous_block)| (previous_block.addr, previous_block.end_addr));
  646. if let Some((start_addr, end_addr)) = previous_block {
  647. if current_block.addr < end_addr {
  648. // If this block overlaps with the previous block, re-analyze the previous block
  649. let old_block = basic_blocks.remove(&start_addr);
  650. dbg_assert!(old_block.is_some());
  651. to_visit_stack.push(start_addr as u16 & 0xFFF);
  652. // Note that this does not ensure the invariant that two consecutive blocks don't
  653. // overlay. For that, we also need to check the following block.
  654. }
  655. }
  656. dbg_assert!(current_block.addr < current_block.end_addr);
  657. dbg_assert!(current_block.addr <= current_block.last_instruction_addr);
  658. dbg_assert!(current_block.last_instruction_addr < current_block.end_addr);
  659. basic_blocks.insert(current_block.addr, current_block);
  660. }
  661. for block in basic_blocks.values_mut() {
  662. if marked_as_entry.contains(&(block.addr as u16 & 0xFFF)) {
  663. block.is_entry_block = true;
  664. }
  665. }
  666. let basic_blocks: Vec<BasicBlock> = basic_blocks.into_iter().map(|(_, block)| block).collect();
  667. for i in 0..basic_blocks.len() - 1 {
  668. let next_block_addr = basic_blocks[i + 1].addr;
  669. let next_block_end_addr = basic_blocks[i + 1].end_addr;
  670. let next_block_is_entry = basic_blocks[i + 1].is_entry_block;
  671. let block = &basic_blocks[i];
  672. dbg_assert!(block.addr < next_block_addr);
  673. if next_block_addr < block.end_addr {
  674. dbg_log!(
  675. "Overlapping first=[from={:x} to={:x} is_entry={}] second=[from={:x} to={:x} is_entry={}]",
  676. block.addr,
  677. block.end_addr,
  678. block.is_entry_block as u8,
  679. next_block_addr,
  680. next_block_end_addr,
  681. next_block_is_entry as u8
  682. );
  683. }
  684. }
  685. (basic_blocks, requires_loop_limit)
  686. }
  687. fn create_cache_entry(ctx: &mut JitState, entry: jit_cache_array::Entry) {
  688. let mut found_entry_index = None;
  689. let phys_addr = entry.start_addr;
  690. for i in 0..CODE_CACHE_SEARCH_SIZE {
  691. let addr_index = (phys_addr + i) & jit_cache_array::MASK;
  692. let existing_entry = jit_cache_array::get(addr_index);
  693. if existing_entry.start_addr == entry.start_addr
  694. && existing_entry.state_flags == entry.state_flags
  695. {
  696. profiler::stat_increment(stat::COMPILE_DUPLICATE_ENTRY);
  697. }
  698. if existing_entry.start_addr == 0 {
  699. found_entry_index = Some(addr_index);
  700. break;
  701. }
  702. }
  703. let found_entry_index = match found_entry_index {
  704. Some(i) => i,
  705. None => {
  706. profiler::stat_increment(stat::CACHE_MISMATCH);
  707. // no free slots, overwrite the first one
  708. let found_entry_index = phys_addr & jit_cache_array::MASK;
  709. let old_entry = jit_cache_array::get_mut(found_entry_index);
  710. // if we're here, we expect to overwrite a valid index
  711. dbg_assert!(old_entry.start_addr != 0);
  712. dbg_assert!(old_entry.wasm_table_index != 0);
  713. if old_entry.wasm_table_index == entry.wasm_table_index {
  714. profiler::stat_increment(stat::INVALIDATE_SINGLE_ENTRY_CACHE_FULL);
  715. dbg_assert!(old_entry.pending);
  716. dbg_assert!(Page::page_of(old_entry.start_addr) == Page::page_of(phys_addr));
  717. // The old entry belongs to the same wasm table index as this entry.
  718. // *Don't* free the wasm table index, instead just delete the old entry
  719. // and use its slot for this entry.
  720. // TODO: Optimally, we should pick another slot instead of dropping
  721. // an entry has just been created.
  722. jit_cache_array::remove(found_entry_index);
  723. dbg_assert!(old_entry.next_index_same_page() == None);
  724. old_entry.pending = false;
  725. old_entry.start_addr = 0;
  726. }
  727. else {
  728. profiler::stat_increment(stat::INVALIDATE_MODULE_CACHE_FULL);
  729. let old_wasm_table_index = old_entry.wasm_table_index;
  730. let old_page = Page::page_of(old_entry.start_addr);
  731. remove_jit_cache_wasm_index(ctx, old_page, old_wasm_table_index);
  732. //jit_cache_array::check_invariants();
  733. // old entry should be removed after calling remove_jit_cache_wasm_index
  734. dbg_assert!(!old_entry.pending);
  735. dbg_assert!(old_entry.start_addr == 0);
  736. dbg_assert!(old_entry.wasm_table_index == 0);
  737. dbg_assert!(old_entry.next_index_same_page() == None);
  738. }
  739. found_entry_index
  740. },
  741. };
  742. jit_cache_array::insert(found_entry_index, entry);
  743. }
  744. #[no_mangle]
  745. #[cfg(debug_assertions)]
  746. pub fn jit_force_generate_unsafe(phys_addr: u32) {
  747. let ctx = get_jit_state();
  748. record_entry_point(phys_addr);
  749. let cs_offset = cpu::get_seg_cs() as u32;
  750. let state_flags = cpu::pack_current_state_flags();
  751. jit_analyze_and_generate(ctx, Page::page_of(phys_addr), cs_offset, state_flags);
  752. }
  753. #[inline(never)]
  754. fn jit_analyze_and_generate(
  755. ctx: &mut JitState,
  756. page: Page,
  757. cs_offset: u32,
  758. state_flags: CachedStateFlags,
  759. ) {
  760. if jit_page_has_pending_code(ctx, page) {
  761. return;
  762. }
  763. let entry_points = ctx.entry_points.remove(&page);
  764. if let Some(entry_points) = entry_points {
  765. dbg_log!("Compile code for page at {:x}", page.to_address());
  766. profiler::stat_increment(stat::COMPILE);
  767. let cpu = CpuContext {
  768. eip: 0,
  769. prefixes: 0,
  770. cs_offset,
  771. state_flags,
  772. };
  773. let (basic_blocks, requires_loop_limit) =
  774. jit_find_basic_blocks(page, &entry_points, cpu.clone());
  775. //for b in basic_blocks.iter() {
  776. // dbg_log!(
  777. // "> Basic block from {:x} to {:x}, is_entry={}",
  778. // b.addr,
  779. // b.end_addr,
  780. // b.is_entry_block
  781. // );
  782. //}
  783. if ctx.wasm_table_index_free_list.is_empty() {
  784. dbg_log!(
  785. "wasm_table_index_free_list empty ({} pending_free), clearing cache",
  786. ctx.wasm_table_index_pending_free.len(),
  787. );
  788. // When no free slots are available, delete all cached modules. We could increase the
  789. // size of the table, but this way the initial size acts as an upper bound for the
  790. // number of wasm modules that we generate, which we want anyway to avoid getting our
  791. // tab killed by browsers due to memory constraints.
  792. jit_clear_cache(ctx);
  793. profiler::stat_increment(stat::INVALIDATE_ALL_MODULES_NO_FREE_WASM_INDICES);
  794. dbg_log!(
  795. "after jit_clear_cache: {} pending_free {} free",
  796. ctx.wasm_table_index_pending_free.len(),
  797. ctx.wasm_table_index_free_list.len(),
  798. );
  799. // This assertion can fail if all entries are pending (not possible unless
  800. // WASM_TABLE_SIZE is set very low)
  801. dbg_assert!(!ctx.wasm_table_index_free_list.is_empty());
  802. }
  803. // allocate an index in the wasm table
  804. let wasm_table_index = ctx
  805. .wasm_table_index_free_list
  806. .pop()
  807. .expect("allocate wasm table index");
  808. dbg_assert!(wasm_table_index != 0);
  809. jit_generate_module(
  810. &basic_blocks,
  811. requires_loop_limit,
  812. cpu.clone(),
  813. &mut ctx.wasm_builder,
  814. wasm_table_index,
  815. state_flags,
  816. );
  817. // create entries for each basic block that is marked as an entry point
  818. let mut entry_point_count = 0;
  819. for (i, block) in basic_blocks.iter().enumerate() {
  820. profiler::stat_increment(stat::COMPILE_BASIC_BLOCK);
  821. if block.is_entry_block && block.addr != block.end_addr {
  822. dbg_assert!(block.addr != 0);
  823. let initial_state = i.safe_to_u16();
  824. #[allow(unused_mut)]
  825. let mut entry = jit_cache_array::Entry::create(
  826. block.addr,
  827. None, // to be filled in by create_cache_entry
  828. wasm_table_index,
  829. initial_state,
  830. state_flags,
  831. true,
  832. );
  833. #[cfg(any(debug_assertions, feature = "profiler"))]
  834. {
  835. entry.len = block.end_addr - block.addr;
  836. }
  837. #[cfg(debug_assertions)]
  838. {
  839. entry.opcode = memory::read32s(block.addr) as u32;
  840. }
  841. create_cache_entry(ctx, entry);
  842. entry_point_count += 1;
  843. profiler::stat_increment(stat::COMPILE_ENTRY_POINT);
  844. }
  845. }
  846. profiler::stat_increment_by(stat::COMPILE_WASM_TOTAL_BYTES, jit_get_op_len() as u64);
  847. dbg_assert!(entry_point_count > 0);
  848. cpu::tlb_set_has_code(page, true);
  849. jit_cache_array::check_invariants();
  850. cpu::check_tlb_invariants();
  851. let end_addr = 0;
  852. let first_opcode = 0;
  853. let phys_addr = page.to_address();
  854. // will call codegen_finalize_finished asynchronously when finished
  855. codegen_finalize(
  856. wasm_table_index,
  857. phys_addr,
  858. end_addr,
  859. first_opcode,
  860. state_flags,
  861. );
  862. profiler::stat_increment(stat::COMPILE_SUCCESS);
  863. }
  864. else {
  865. //dbg_log("No basic blocks, not generating code");
  866. // Nothing to do
  867. }
  868. }
  869. #[no_mangle]
  870. pub fn codegen_finalize_finished(
  871. wasm_table_index: u16,
  872. phys_addr: u32,
  873. _end_addr: u32,
  874. _first_opcode: u32,
  875. _state_flags: CachedStateFlags,
  876. ) {
  877. let ctx = get_jit_state();
  878. dbg_assert!(wasm_table_index != 0);
  879. match ctx
  880. .wasm_table_index_pending_free
  881. .iter()
  882. .position(|i| *i == wasm_table_index)
  883. {
  884. Some(i) => {
  885. ctx.wasm_table_index_pending_free.swap_remove(i);
  886. free_wasm_table_index(ctx, wasm_table_index);
  887. },
  888. None => {
  889. let page = Page::page_of(phys_addr);
  890. let mut cache_array_index = jit_cache_array::get_page_index(page);
  891. while let Some(index) = cache_array_index {
  892. let mut entry = jit_cache_array::get_mut(index);
  893. if (*entry).wasm_table_index == wasm_table_index {
  894. dbg_assert!((*entry).pending);
  895. (*entry).pending = false;
  896. }
  897. cache_array_index = (*entry).next_index_same_page();
  898. }
  899. },
  900. }
  901. jit_cache_array::check_invariants();
  902. if CHECK_JIT_CACHE_ARRAY_INVARIANTS {
  903. // sanity check that the above iteration marked all entries as not pending
  904. for i in 0..jit_cache_array::SIZE {
  905. let entry = jit_cache_array::get(i);
  906. if entry.wasm_table_index == wasm_table_index {
  907. dbg_assert!(!entry.pending);
  908. }
  909. }
  910. }
  911. }
  912. fn jit_generate_module(
  913. basic_blocks: &Vec<BasicBlock>,
  914. requires_loop_limit: bool,
  915. mut cpu: CpuContext,
  916. builder: &mut WasmBuilder,
  917. wasm_table_index: u16,
  918. state_flags: CachedStateFlags,
  919. ) {
  920. builder.reset();
  921. let basic_block_indices: HashMap<u32, u32> = basic_blocks
  922. .iter()
  923. .enumerate()
  924. .map(|(index, block)| (block.addr, index as u32))
  925. .collect();
  926. // set state local variable to the initial state passed as the first argument
  927. builder.get_local(&builder.arg_local_initial_state.unsafe_clone());
  928. let gen_local_state = builder.set_new_local();
  929. // initialise max_iterations
  930. let gen_local_iteration_counter = if JIT_ALWAYS_USE_LOOP_SAFETY || requires_loop_limit {
  931. builder.const_i32(JIT_MAX_ITERATIONS_PER_FUNCTION as i32);
  932. Some(builder.set_new_local())
  933. }
  934. else {
  935. None
  936. };
  937. let mut register_locals = (0..8)
  938. .map(|i| {
  939. builder.const_i32(global_pointers::get_reg32_offset(i) as i32);
  940. builder.load_aligned_i32(0);
  941. let local = builder.set_new_local();
  942. local
  943. })
  944. .collect();
  945. let ctx = &mut JitContext {
  946. cpu: &mut cpu,
  947. builder,
  948. register_locals: &mut register_locals,
  949. start_of_current_instruction: 0,
  950. current_brtable_depth: 0,
  951. our_wasm_table_index: wasm_table_index,
  952. basic_block_index_local: &gen_local_state,
  953. state_flags,
  954. };
  955. // main state machine loop
  956. ctx.builder.loop_void();
  957. if let Some(gen_local_iteration_counter) = gen_local_iteration_counter.as_ref() {
  958. profiler::stat_increment(stat::COMPILE_WITH_LOOP_SAFETY);
  959. // decrement max_iterations
  960. ctx.builder.get_local(gen_local_iteration_counter);
  961. ctx.builder.const_i32(-1);
  962. ctx.builder.add_i32();
  963. ctx.builder.set_local(gen_local_iteration_counter);
  964. // if max_iterations == 0: return
  965. ctx.builder.get_local(gen_local_iteration_counter);
  966. ctx.builder.eqz_i32();
  967. ctx.builder.if_void();
  968. codegen::gen_debug_track_jit_exit(ctx.builder, 0);
  969. codegen::gen_move_registers_from_locals_to_memory(ctx);
  970. ctx.builder.return_();
  971. ctx.builder.block_end();
  972. }
  973. ctx.builder.block_void(); // for the default case
  974. ctx.builder.block_void(); // for the exit-with-pagefault case
  975. // generate the opening blocks for the cases
  976. for _ in 0..basic_blocks.len() {
  977. ctx.builder.block_void();
  978. }
  979. ctx.builder.get_local(&gen_local_state);
  980. ctx.builder.brtable_and_cases(basic_blocks.len() as u32 + 1); // plus one for the exit-with-pagefault case
  981. for (i, block) in basic_blocks.iter().enumerate() {
  982. // Case [i] will jump after the [i]th block, so we first generate the
  983. // block end opcode and then the code for that block
  984. ctx.builder.block_end();
  985. ctx.current_brtable_depth = basic_blocks.len() as u32 + 1 - i as u32;
  986. dbg_assert!(block.addr < block.end_addr);
  987. jit_generate_basic_block(ctx, block);
  988. let invalid_connection_to_next_block = block.end_addr != ctx.cpu.eip;
  989. dbg_assert!(!invalid_connection_to_next_block);
  990. if block.has_sti {
  991. match block.ty {
  992. BasicBlockType::ConditionalJump {
  993. condition,
  994. jump_offset,
  995. jump_offset_is_32,
  996. ..
  997. } => {
  998. codegen::gen_condition_fn(ctx, condition);
  999. ctx.builder.if_void();
  1000. if jump_offset_is_32 {
  1001. codegen::gen_relative_jump(ctx.builder, jump_offset);
  1002. }
  1003. else {
  1004. codegen::gen_jmp_rel16(ctx.builder, jump_offset as u16);
  1005. }
  1006. ctx.builder.block_end();
  1007. },
  1008. _ => {},
  1009. };
  1010. codegen::gen_debug_track_jit_exit(ctx.builder, block.last_instruction_addr);
  1011. codegen::gen_move_registers_from_locals_to_memory(ctx);
  1012. codegen::gen_fn0_const(ctx.builder, "handle_irqs");
  1013. ctx.builder.return_();
  1014. continue;
  1015. }
  1016. match &block.ty {
  1017. BasicBlockType::Exit => {
  1018. // Exit this function
  1019. codegen::gen_debug_track_jit_exit(ctx.builder, block.last_instruction_addr);
  1020. codegen::gen_move_registers_from_locals_to_memory(ctx);
  1021. ctx.builder.return_();
  1022. },
  1023. BasicBlockType::Normal { next_block_addr } => {
  1024. // Unconditional jump to next basic block
  1025. // - All instructions that don't change eip
  1026. // - Unconditional jump
  1027. let next_basic_block_index = *basic_block_indices
  1028. .get(&next_block_addr)
  1029. .expect("basic_block_indices.get (Normal)");
  1030. if next_basic_block_index == (i as u32) + 1 {
  1031. // fallthru
  1032. }
  1033. else {
  1034. // set state variable to next basic block
  1035. ctx.builder.const_i32(next_basic_block_index as i32);
  1036. ctx.builder.set_local(&gen_local_state);
  1037. ctx.builder.br(ctx.current_brtable_depth); // to the loop
  1038. }
  1039. },
  1040. &BasicBlockType::ConditionalJump {
  1041. next_block_addr,
  1042. next_block_branch_taken_addr,
  1043. condition,
  1044. jump_offset,
  1045. jump_offset_is_32,
  1046. } => {
  1047. // Conditional jump to next basic block
  1048. // - jnz, jc, loop, jcxz, etc.
  1049. codegen::gen_condition_fn(ctx, condition);
  1050. ctx.builder.if_void();
  1051. // Branch taken
  1052. if jump_offset_is_32 {
  1053. codegen::gen_relative_jump(ctx.builder, jump_offset);
  1054. }
  1055. else {
  1056. codegen::gen_jmp_rel16(ctx.builder, jump_offset as u16);
  1057. }
  1058. if let Some(next_block_branch_taken_addr) = next_block_branch_taken_addr {
  1059. let next_basic_block_branch_taken_index = *basic_block_indices
  1060. .get(&next_block_branch_taken_addr)
  1061. .expect("basic_block_indices.get (branch taken)");
  1062. ctx.builder
  1063. .const_i32(next_basic_block_branch_taken_index as i32);
  1064. ctx.builder.set_local(&gen_local_state);
  1065. ctx.builder.br(basic_blocks.len() as u32 + 2 - i as u32); // to the loop
  1066. }
  1067. else {
  1068. // Jump to different page
  1069. codegen::gen_debug_track_jit_exit(ctx.builder, block.last_instruction_addr);
  1070. codegen::gen_move_registers_from_locals_to_memory(ctx);
  1071. ctx.builder.return_();
  1072. }
  1073. if let Some(next_block_addr) = next_block_addr {
  1074. // Branch not taken
  1075. let next_basic_block_index = *basic_block_indices
  1076. .get(&next_block_addr)
  1077. .expect("basic_block_indices.get (branch not taken)");
  1078. if next_basic_block_index == (i as u32) + 1 {
  1079. // fallthru
  1080. ctx.builder.block_end();
  1081. }
  1082. else {
  1083. ctx.builder.else_();
  1084. ctx.builder.const_i32(next_basic_block_index as i32);
  1085. ctx.builder.set_local(&gen_local_state);
  1086. ctx.builder.br(basic_blocks.len() as u32 + 2 - i as u32); // to the loop
  1087. ctx.builder.block_end();
  1088. }
  1089. }
  1090. else {
  1091. ctx.builder.else_();
  1092. // End of this page
  1093. codegen::gen_debug_track_jit_exit(ctx.builder, block.last_instruction_addr);
  1094. codegen::gen_move_registers_from_locals_to_memory(ctx);
  1095. ctx.builder.return_();
  1096. ctx.builder.block_end();
  1097. }
  1098. },
  1099. }
  1100. }
  1101. {
  1102. // exit-with-pagefault case
  1103. ctx.builder.block_end();
  1104. codegen::gen_move_registers_from_locals_to_memory(ctx);
  1105. codegen::gen_fn0_const(ctx.builder, "trigger_pagefault_end_jit");
  1106. ctx.builder.return_();
  1107. }
  1108. ctx.builder.block_end(); // default case
  1109. ctx.builder.unreachable();
  1110. ctx.builder.block_end(); // loop
  1111. ctx.builder.free_local(gen_local_state.unsafe_clone());
  1112. if let Some(local) = gen_local_iteration_counter {
  1113. ctx.builder.free_local(local);
  1114. }
  1115. for local in ctx.register_locals.drain(..) {
  1116. ctx.builder.free_local(local);
  1117. }
  1118. ctx.builder.finish();
  1119. }
  1120. fn jit_generate_basic_block(ctx: &mut JitContext, block: &BasicBlock) {
  1121. let start_addr = block.addr;
  1122. let last_instruction_addr = block.last_instruction_addr;
  1123. let stop_addr = block.end_addr;
  1124. // First iteration of do-while assumes the caller confirms this condition
  1125. dbg_assert!(!is_near_end_of_page(start_addr));
  1126. codegen::gen_increment_timestamp_counter(ctx.builder, block.number_of_instructions as i32);
  1127. ctx.cpu.eip = start_addr;
  1128. loop {
  1129. let mut instruction = 0;
  1130. if cfg!(feature = "profiler") {
  1131. instruction = memory::read32s(ctx.cpu.eip) as u32;
  1132. ::opstats::gen_opstats(ctx.builder, instruction);
  1133. ::opstats::record_opstat_compiled(instruction);
  1134. }
  1135. if ctx.cpu.eip == last_instruction_addr {
  1136. // Before the last instruction:
  1137. // - Set eip to *after* the instruction
  1138. // - Set previous_eip to *before* the instruction
  1139. codegen::gen_set_previous_eip_offset_from_eip(
  1140. ctx.builder,
  1141. last_instruction_addr - start_addr,
  1142. );
  1143. codegen::gen_increment_instruction_pointer(ctx.builder, stop_addr - start_addr);
  1144. }
  1145. let wasm_length_before = ctx.builder.instruction_body_length();
  1146. ctx.start_of_current_instruction = ctx.cpu.eip;
  1147. let start_eip = ctx.cpu.eip;
  1148. let mut instruction_flags = 0;
  1149. jit_instructions::jit_instruction(ctx, &mut instruction_flags);
  1150. let end_eip = ctx.cpu.eip;
  1151. let instruction_length = end_eip - start_eip;
  1152. let was_block_boundary = instruction_flags & JIT_INSTR_BLOCK_BOUNDARY_FLAG != 0;
  1153. let wasm_length = ctx.builder.instruction_body_length() - wasm_length_before;
  1154. ::opstats::record_opstat_size_wasm(instruction, wasm_length as u32);
  1155. dbg_assert!((end_eip == stop_addr) == (start_eip == last_instruction_addr));
  1156. dbg_assert!(instruction_length < MAX_INSTRUCTION_LENGTH);
  1157. let end_addr = ctx.cpu.eip;
  1158. if end_addr == stop_addr {
  1159. // no page was crossed
  1160. dbg_assert!(Page::page_of(end_addr) == Page::page_of(start_addr));
  1161. break;
  1162. }
  1163. if was_block_boundary || is_near_end_of_page(end_addr) || end_addr > stop_addr {
  1164. dbg_log!(
  1165. "Overlapping basic blocks start={:x} expected_end={:x} end={:x} was_block_boundary={} near_end_of_page={}",
  1166. start_addr,
  1167. stop_addr,
  1168. end_addr,
  1169. was_block_boundary,
  1170. is_near_end_of_page(end_addr)
  1171. );
  1172. dbg_assert!(false);
  1173. break;
  1174. }
  1175. }
  1176. }
  1177. #[no_mangle]
  1178. pub fn jit_increase_hotness_and_maybe_compile(
  1179. phys_address: u32,
  1180. cs_offset: u32,
  1181. state_flags: CachedStateFlags,
  1182. hotness: u32,
  1183. ) {
  1184. let ctx = get_jit_state();
  1185. let page = Page::page_of(phys_address);
  1186. let address_hash = jit_hot_hash_page(page) as usize;
  1187. ctx.hot_pages[address_hash] += hotness;
  1188. if ctx.hot_pages[address_hash] >= JIT_THRESHOLD {
  1189. ctx.hot_pages[address_hash] = 0;
  1190. jit_analyze_and_generate(ctx, page, cs_offset, state_flags)
  1191. };
  1192. }
  1193. fn free_wasm_table_index(ctx: &mut JitState, wasm_table_index: u16) {
  1194. if CHECK_JIT_CACHE_ARRAY_INVARIANTS {
  1195. dbg_assert!(!ctx.wasm_table_index_free_list.contains(&wasm_table_index));
  1196. }
  1197. ctx.wasm_table_index_free_list.push(wasm_table_index);
  1198. // It is not strictly necessary to clear the function, but it will fail more predictably if we
  1199. // accidentally use the function and may garbage collect unused modules earlier
  1200. jit_clear_func(wasm_table_index);
  1201. }
  1202. /// Remove all entries with the given wasm_table_index in page
  1203. fn remove_jit_cache_wasm_index(ctx: &mut JitState, page: Page, wasm_table_index: u16) {
  1204. let mut cache_array_index = jit_cache_array::get_page_index(page).unwrap();
  1205. let mut pending = false;
  1206. loop {
  1207. let entry = jit_cache_array::get_mut(cache_array_index);
  1208. let next_cache_array_index = entry.next_index_same_page();
  1209. if entry.wasm_table_index == wasm_table_index {
  1210. // if one entry is pending, all must be pending
  1211. dbg_assert!(!pending || entry.pending);
  1212. pending = entry.pending;
  1213. jit_cache_array::remove(cache_array_index);
  1214. dbg_assert!(entry.next_index_same_page() == None);
  1215. entry.wasm_table_index = 0;
  1216. entry.start_addr = 0;
  1217. entry.pending = false;
  1218. }
  1219. if let Some(i) = next_cache_array_index {
  1220. cache_array_index = i;
  1221. }
  1222. else {
  1223. break;
  1224. }
  1225. }
  1226. if pending {
  1227. ctx.wasm_table_index_pending_free.push(wasm_table_index);
  1228. }
  1229. else {
  1230. free_wasm_table_index(ctx, wasm_table_index);
  1231. }
  1232. if !jit_page_has_code(page) {
  1233. cpu::tlb_set_has_code(page, false);
  1234. }
  1235. if CHECK_JIT_CACHE_ARRAY_INVARIANTS {
  1236. // sanity check that the above iteration deleted all entries
  1237. for i in 0..jit_cache_array::SIZE {
  1238. let entry = jit_cache_array::get(i);
  1239. dbg_assert!(entry.wasm_table_index != wasm_table_index);
  1240. }
  1241. }
  1242. }
  1243. /// Register a write in this page: Delete all present code
  1244. pub fn jit_dirty_page(ctx: &mut JitState, page: Page) {
  1245. let mut did_have_code = false;
  1246. if let Some(mut cache_array_index) = jit_cache_array::get_page_index(page) {
  1247. did_have_code = true;
  1248. let mut index_to_free = HashSet::new();
  1249. let mut index_to_pending_free = HashSet::new();
  1250. jit_cache_array::set_page_index(page, None);
  1251. profiler::stat_increment(stat::INVALIDATE_PAGE);
  1252. loop {
  1253. profiler::stat_increment(stat::INVALIDATE_CACHE_ENTRY);
  1254. let entry = jit_cache_array::get_mut(cache_array_index);
  1255. let wasm_table_index = entry.wasm_table_index;
  1256. dbg_assert!(page == Page::page_of(entry.start_addr));
  1257. let next_cache_array_index = entry.next_index_same_page();
  1258. entry.set_next_index_same_page(None);
  1259. entry.start_addr = 0;
  1260. entry.wasm_table_index = 0;
  1261. if entry.pending {
  1262. dbg_assert!(!index_to_free.contains(&wasm_table_index));
  1263. entry.pending = false;
  1264. index_to_pending_free.insert(wasm_table_index);
  1265. }
  1266. else {
  1267. dbg_assert!(!index_to_pending_free.contains(&wasm_table_index));
  1268. index_to_free.insert(wasm_table_index);
  1269. }
  1270. if let Some(i) = next_cache_array_index {
  1271. cache_array_index = i;
  1272. }
  1273. else {
  1274. break;
  1275. }
  1276. }
  1277. profiler::stat_increment_by(
  1278. stat::INVALIDATE_MODULE,
  1279. index_to_pending_free.len() as u64 + index_to_free.len() as u64,
  1280. );
  1281. for index in index_to_free.iter().cloned() {
  1282. free_wasm_table_index(ctx, index)
  1283. }
  1284. for index in index_to_pending_free {
  1285. ctx.wasm_table_index_pending_free.push(index);
  1286. }
  1287. }
  1288. match ctx.entry_points.remove(&page) {
  1289. None => {},
  1290. Some(_entry_points) => {
  1291. did_have_code = true;
  1292. // don't try to compile code in this page anymore until it's hot again
  1293. ctx.hot_pages[jit_hot_hash_page(page) as usize] = 0;
  1294. },
  1295. }
  1296. if did_have_code {
  1297. cpu::tlb_set_has_code(page, false);
  1298. }
  1299. }
  1300. #[no_mangle]
  1301. pub fn jit_dirty_cache(start_addr: u32, end_addr: u32) {
  1302. dbg_assert!(start_addr < end_addr);
  1303. let start_page = Page::page_of(start_addr);
  1304. let end_page = Page::page_of(end_addr - 1);
  1305. for page in start_page.to_u32()..end_page.to_u32() + 1 {
  1306. jit_dirty_page(get_jit_state(), Page::page_of(page << 12));
  1307. }
  1308. }
  1309. /// dirty pages in the range of start_addr and end_addr, which must span at most two pages
  1310. pub fn jit_dirty_cache_small(start_addr: u32, end_addr: u32) {
  1311. dbg_assert!(start_addr < end_addr);
  1312. let start_page = Page::page_of(start_addr);
  1313. let end_page = Page::page_of(end_addr - 1);
  1314. jit_dirty_page(get_jit_state(), start_page);
  1315. // Note: This can't happen when paging is enabled, as writes across
  1316. // boundaries are split up on two pages
  1317. if start_page != end_page {
  1318. dbg_assert!(start_page.to_u32() + 1 == end_page.to_u32());
  1319. jit_dirty_page(get_jit_state(), end_page);
  1320. }
  1321. }
  1322. #[no_mangle]
  1323. pub fn jit_clear_cache_js() { jit_clear_cache(get_jit_state()) }
  1324. pub fn jit_clear_cache(ctx: &mut JitState) {
  1325. ctx.entry_points.clear();
  1326. for page_index in 0..0x100000 {
  1327. jit_dirty_page(ctx, Page::page_of(page_index << 12))
  1328. }
  1329. jit_clear_all_funcs();
  1330. }
  1331. pub fn jit_page_has_code(page: Page) -> bool {
  1332. let ctx = get_jit_state();
  1333. // Does the page have compiled code
  1334. jit_cache_array::get_page_index(page) != None ||
  1335. // Or are there any entry points that need to be removed on write to the page
  1336. // (this function is used to mark the has_code bit in the tlb to optimise away calls jit_dirty_page)
  1337. ctx.entry_points.contains_key(&page)
  1338. }
  1339. pub fn jit_page_has_pending_code(_ctx: &JitState, page: Page) -> bool {
  1340. if let Some(mut cache_array_index) = jit_cache_array::get_page_index(page) {
  1341. loop {
  1342. let entry = jit_cache_array::get(cache_array_index);
  1343. dbg_assert!(page == Page::page_of(entry.start_addr));
  1344. if entry.pending {
  1345. return true;
  1346. }
  1347. if let Some(i) = entry.next_index_same_page() {
  1348. cache_array_index = i;
  1349. }
  1350. else {
  1351. break;
  1352. }
  1353. }
  1354. }
  1355. return false;
  1356. }
  1357. #[no_mangle]
  1358. pub fn jit_unused_cache_stat() -> u32 {
  1359. let mut count = 0;
  1360. if cfg!(debug_assertions) {
  1361. for i in 0..jit_cache_array::SIZE {
  1362. if (jit_cache_array::get(i)).start_addr == 0 {
  1363. count += 1
  1364. }
  1365. }
  1366. }
  1367. return count;
  1368. }
  1369. #[no_mangle]
  1370. pub fn jit_get_entry_length(i: u32) -> u32 {
  1371. #[allow(unused_variables)]
  1372. let entry = jit_cache_array::get(i);
  1373. #[cfg(debug_assertions)]
  1374. return entry.len;
  1375. #[cfg(not(debug_assertions))]
  1376. 0
  1377. }
  1378. #[no_mangle]
  1379. pub fn jit_get_entry_address(i: u32) -> u32 {
  1380. if cfg!(debug_assertions) { jit_cache_array::get(i).start_addr } else { 0 }
  1381. }
  1382. #[no_mangle]
  1383. pub fn jit_get_entry_pending(i: u32) -> bool {
  1384. if cfg!(debug_assertions) { jit_cache_array::get(i).pending } else { false }
  1385. }
  1386. #[no_mangle]
  1387. pub fn jit_get_wasm_table_index_free_list_count() -> u32 {
  1388. if cfg!(debug_assertions) {
  1389. get_jit_state().wasm_table_index_free_list.len() as u32
  1390. }
  1391. else {
  1392. 0
  1393. }
  1394. }
  1395. #[no_mangle]
  1396. pub fn jit_get_op_len() -> u32 { get_jit_state().wasm_builder.get_op_len() }
  1397. #[no_mangle]
  1398. pub fn jit_get_op_ptr() -> *const u8 { get_jit_state().wasm_builder.get_op_ptr() }
  1399. #[cfg(feature = "profiler")]
  1400. pub fn check_missed_entry_points(phys_address: u32, state_flags: CachedStateFlags) {
  1401. let page = Page::page_of(phys_address);
  1402. for i in page.to_address()..page.to_address() + 4096 {
  1403. // No need to check [CODE_CACHE_SEARCH_SIZE] entries here as we look at consecutive
  1404. // addresses anyway
  1405. let index = i & jit_cache_array::MASK;
  1406. let entry = jit_cache_array::get(index);
  1407. if !entry.pending
  1408. && entry.state_flags == state_flags
  1409. && phys_address >= entry.start_addr
  1410. && phys_address < entry.start_addr + entry.len
  1411. {
  1412. profiler::stat_increment(stat::RUN_INTERPRETED_MISSED_COMPILED_ENTRY_LOOKUP);
  1413. let last_jump_type = unsafe { cpu::debug_last_jump.name() };
  1414. let last_jump_addr = unsafe { cpu::debug_last_jump.phys_address() }.unwrap_or(0);
  1415. let last_jump_opcode =
  1416. if last_jump_addr != 0 { memory::read32s(last_jump_addr) } else { 0 };
  1417. let opcode = memory::read32s(phys_address);
  1418. dbg_log!(
  1419. "Compiled exists, but no entry point, \
  1420. start={:x} end={:x} phys_addr={:x} opcode={:02x} {:02x} {:02x} {:02x}. \
  1421. Last jump at {:x} ({}) opcode={:02x} {:02x} {:02x} {:02x}",
  1422. entry.start_addr,
  1423. entry.start_addr + entry.len,
  1424. phys_address,
  1425. opcode & 0xFF,
  1426. opcode >> 8 & 0xFF,
  1427. opcode >> 16 & 0xFF,
  1428. opcode >> 16 & 0xFF,
  1429. last_jump_addr,
  1430. last_jump_type,
  1431. last_jump_opcode & 0xFF,
  1432. last_jump_opcode >> 8 & 0xFF,
  1433. last_jump_opcode >> 16 & 0xFF,
  1434. last_jump_opcode >> 16 & 0xFF,
  1435. );
  1436. }
  1437. }
  1438. }