nbytecode.ml 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. (*
  2. * Neko Compiler
  3. * Copyright (c)2005 Motion-Twin
  4. *
  5. * This library is free software; you can redistribute it and/lor
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2.1 of the License, lor (at your option) any later version.
  9. *
  10. * This library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY lor FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Lesser General Public License lor the LICENSE file for more details.
  14. *)
  15. type opcode =
  16. (* getters *)
  17. | AccNull
  18. | AccTrue
  19. | AccFalse
  20. | AccThis
  21. | AccInt of int
  22. | AccStack of int
  23. | AccGlobal of int
  24. | AccEnv of int
  25. | AccField of string
  26. | AccArray
  27. | AccIndex of int
  28. | AccBuiltin of string
  29. (* setters *)
  30. | SetStack of int
  31. | SetGlobal of int
  32. | SetEnv of int
  33. | SetField of string
  34. | SetArray
  35. | SetIndex of int
  36. | SetThis
  37. (* stack ops *)
  38. | Push
  39. | Pop of int
  40. | Call of int
  41. | ObjCall of int
  42. | Jump of int
  43. | JumpIf of int
  44. | JumpIfNot of int
  45. | Trap of int
  46. | EndTrap
  47. | Ret of int
  48. | MakeEnv of int
  49. | MakeArray of int
  50. (* value ops *)
  51. | Bool
  52. | IsNull
  53. | IsNotNull
  54. | Add
  55. | Sub
  56. | Mult
  57. | Div
  58. | Mod
  59. | Shl
  60. | Shr
  61. | UShr
  62. | Or
  63. | And
  64. | Xor
  65. | Eq
  66. | Neq
  67. | Gt
  68. | Gte
  69. | Lt
  70. | Lte
  71. | Not
  72. (* extra ops *)
  73. | TypeOf
  74. | Compare
  75. | Hash
  76. | New
  77. | JumpTable of int
  78. | Apply of int
  79. | AccStack0
  80. | AccStack1
  81. | AccIndex0
  82. | AccIndex1
  83. | PhysCompare
  84. | TailCall of int * int
  85. | Loop
  86. (* ocaml-specific *)
  87. | AccInt32 of int32
  88. type global =
  89. | GlobalVar of string
  90. | GlobalFunction of int * int
  91. | GlobalString of string
  92. | GlobalFloat of string
  93. | GlobalDebug of string array * ((int * int) array)
  94. | GlobalVersion of int
  95. exception Invalid_file
  96. let error msg = failwith msg
  97. let trap_stack_delta = 6
  98. let hash_field f =
  99. let h = ref 0 in
  100. for i = 0 to String.length f - 1 do
  101. h := !h * 223 + int_of_char (String.unsafe_get f i);
  102. done;
  103. if Sys.word_size = 64 then Int32.to_int (Int32.shift_right (Int32.shift_left (Int32.of_int !h) 1) 1) else !h
  104. let op_param x =
  105. match x with
  106. | AccInt _
  107. | AccInt32 _
  108. | AccStack _
  109. | AccGlobal _
  110. | AccEnv _
  111. | AccField _
  112. | AccBuiltin _
  113. | SetStack _
  114. | SetGlobal _
  115. | SetEnv _
  116. | SetField _
  117. | Pop _
  118. | Call _
  119. | ObjCall _
  120. | Jump _
  121. | JumpIf _
  122. | JumpIfNot _
  123. | JumpTable _
  124. | Trap _
  125. | MakeEnv _
  126. | MakeArray _
  127. | Ret _
  128. | AccIndex _
  129. | SetIndex _
  130. | Apply _
  131. | TailCall _
  132. -> true
  133. | AccNull
  134. | AccTrue
  135. | AccFalse
  136. | AccThis
  137. | AccArray
  138. | SetArray
  139. | SetThis
  140. | Push
  141. | EndTrap
  142. | Bool
  143. | Add
  144. | Sub
  145. | Mult
  146. | Div
  147. | Mod
  148. | Shl
  149. | Shr
  150. | UShr
  151. | Or
  152. | And
  153. | Xor
  154. | Eq
  155. | Neq
  156. | Gt
  157. | Gte
  158. | Lt
  159. | Lte
  160. | IsNull
  161. | IsNotNull
  162. | Not
  163. | TypeOf
  164. | Compare
  165. | Hash
  166. | New
  167. | AccStack0
  168. | AccStack1
  169. | AccIndex0
  170. | AccIndex1
  171. | PhysCompare
  172. | Loop
  173. -> false
  174. let code_tables ops =
  175. let ids = Hashtbl.create 0 in
  176. let fids = DynArray.create() in
  177. Array.iter (fun x ->
  178. match x with
  179. | AccField s
  180. | SetField s
  181. | AccBuiltin s ->
  182. let id = hash_field s in
  183. (try
  184. let f = Hashtbl.find ids id in
  185. if f <> s then error("Field hashing conflict " ^ s ^ " and " ^ f);
  186. with Not_found ->
  187. Hashtbl.add ids id s;
  188. DynArray.add fids s
  189. )
  190. | _ -> ()
  191. ) ops;
  192. let p = ref 0 in
  193. let pos = Array.make (Array.length(ops) + 1) 0 in
  194. Array.iteri (fun i op ->
  195. pos.(i) <- !p;
  196. p := !p + (if op_param op then 2 else 1);
  197. ) ops;
  198. pos.(Array.length ops) <- !p;
  199. (DynArray.to_array fids , pos , !p)
  200. let write_debug_infos ch files inf =
  201. let nfiles = Array.length files in
  202. (*
  203. // the encoding of nfiles was set to keep
  204. // backward compatibility with 1.3 which
  205. // only allowed up to 127 filenames
  206. *)
  207. let lot_of_files = ref false in
  208. if nfiles < 0x80 then
  209. IO.write_byte ch nfiles
  210. else if nfiles < 0x8000 then begin
  211. lot_of_files := true;
  212. IO.write_byte ch ((nfiles lsr 8) lor 0x80);
  213. IO.write_byte ch (nfiles land 0xFF);
  214. end else
  215. assert false;
  216. Array.iter (fun s -> IO.write_string ch s) files;
  217. IO.write_i32 ch (Array.length inf);
  218. let curfile = ref 0 in
  219. let curpos = ref 0 in
  220. let rcount = ref 0 in
  221. let rec flush_repeat p =
  222. if !rcount > 0 then begin
  223. if !rcount > 15 then begin
  224. IO.write_byte ch ((15 lsl 2) lor 2);
  225. rcount := !rcount - 15;
  226. flush_repeat(p)
  227. end else begin
  228. let delta = p - !curpos in
  229. let delta = (if delta > 0 && delta < 4 then delta else 0) in
  230. IO.write_byte ch ((delta lsl 6) lor (!rcount lsl 2) lor 2);
  231. rcount := 0;
  232. curpos := !curpos + delta;
  233. end
  234. end
  235. in
  236. Array.iter (fun (f,p) ->
  237. if f <> !curfile then begin
  238. flush_repeat(p);
  239. curfile := f;
  240. if !lot_of_files then begin
  241. IO.write_byte ch ((f lsr 7) lor 1);
  242. IO.write_byte ch (f land 0xFF);
  243. end else
  244. IO.write_byte ch ((f lsl 1) lor 1);
  245. end;
  246. if p <> !curpos then flush_repeat(p);
  247. if p = !curpos then
  248. rcount := !rcount + 1
  249. else
  250. let delta = p - !curpos in
  251. if delta > 0 && delta < 32 then
  252. IO.write_byte ch ((delta lsl 3) lor 4)
  253. else begin
  254. IO.write_byte ch (p lsl 3);
  255. IO.write_byte ch (p lsr 5);
  256. IO.write_byte ch (p lsr 13);
  257. end;
  258. curpos := p;
  259. ) inf;
  260. flush_repeat(!curpos)
  261. let write ch (globals,ops) =
  262. IO.nwrite_string ch "NEKO";
  263. let ids , pos , csize = code_tables ops in
  264. IO.write_i32 ch (Array.length globals);
  265. IO.write_i32 ch (Array.length ids);
  266. IO.write_i32 ch csize;
  267. Array.iter (fun x ->
  268. match x with
  269. | GlobalVar s -> IO.write_byte ch 1; IO.write_string ch s
  270. | GlobalFunction (p,nargs) -> IO.write_byte ch 2; IO.write_i32 ch (pos.(p) lor (nargs lsl 24))
  271. | GlobalString s -> IO.write_byte ch 3; IO.write_ui16 ch (String.length s); IO.nwrite_string ch s
  272. | GlobalFloat s -> IO.write_byte ch 4; IO.write_string ch s
  273. | GlobalDebug (files,inf) -> IO.write_byte ch 5; write_debug_infos ch files inf;
  274. | GlobalVersion v -> IO.write_byte ch 6; IO.write_byte ch v
  275. ) globals;
  276. Array.iter (fun s ->
  277. IO.write_string ch s;
  278. ) ids;
  279. Array.iteri (fun i op ->
  280. let pop = ref None in
  281. let opid = (match op with
  282. | AccNull -> 0
  283. | AccTrue -> 1
  284. | AccFalse -> 2
  285. | AccThis -> 3
  286. | AccInt n -> pop := Some n; 4
  287. | AccInt32 n ->
  288. let opid = 4 in
  289. IO.write_byte ch ((opid lsl 2) lor 3);
  290. IO.write_real_i32 ch n;
  291. -1
  292. | AccStack n -> pop := Some (n - 2); 5
  293. | AccGlobal n -> pop := Some n; 6
  294. | AccEnv n -> pop := Some n; 7
  295. | AccField s -> pop := Some (hash_field s); 8
  296. | AccArray -> 9
  297. | AccIndex n -> pop := Some (n - 2); 10
  298. | AccBuiltin s -> pop := Some (hash_field s); 11
  299. | SetStack n -> pop := Some n; 12
  300. | SetGlobal n -> pop := Some n; 13
  301. | SetEnv n -> pop := Some n; 14
  302. | SetField s -> pop := Some (hash_field s); 15
  303. | SetArray -> 16
  304. | SetIndex n -> pop := Some n; 17
  305. | SetThis -> 18
  306. | Push -> 19
  307. | Pop n -> pop := Some n; 20
  308. | Call n -> pop := Some n; 21
  309. | ObjCall n -> pop := Some n; 22
  310. | Jump n -> pop := Some (pos.(i+n) - pos.(i)); 23
  311. | JumpIf n -> pop := Some (pos.(i+n) - pos.(i)); 24
  312. | JumpIfNot n -> pop := Some (pos.(i+n) - pos.(i)); 25
  313. | Trap n -> pop := Some (pos.(i+n) - pos.(i)); 26
  314. | EndTrap -> 27
  315. | Ret n -> pop := Some n; 28
  316. | MakeEnv n -> pop := Some n; 29
  317. | MakeArray n -> pop := Some n; 30
  318. | Bool -> 31
  319. | IsNull -> 32
  320. | IsNotNull -> 33
  321. | Add -> 34
  322. | Sub -> 35
  323. | Mult -> 36
  324. | Div -> 37
  325. | Mod -> 38
  326. | Shl -> 39
  327. | Shr -> 40
  328. | UShr -> 41
  329. | Or -> 42
  330. | And -> 43
  331. | Xor -> 44
  332. | Eq -> 45
  333. | Neq -> 46
  334. | Gt -> 47
  335. | Gte -> 48
  336. | Lt -> 49
  337. | Lte -> 50
  338. | Not -> 51
  339. | TypeOf -> 52
  340. | Compare -> 53
  341. | Hash -> 54
  342. | New -> 55
  343. | JumpTable n -> pop := Some n; 56
  344. | Apply n -> pop := Some n; 57
  345. | AccStack0 -> 58
  346. | AccStack1 -> 59
  347. | AccIndex0 -> 60
  348. | AccIndex1 -> 61
  349. | PhysCompare -> 62
  350. | TailCall (args,st) -> pop := Some (args lor (st lsl 3)); 63
  351. | Loop -> pop := Some 64; 0
  352. ) in
  353. match !pop with
  354. | None ->
  355. if opid >= 0 then IO.write_byte ch (opid lsl 2)
  356. | Some n ->
  357. if opid < 32 && (n = 0 || n = 1) then
  358. IO.write_byte ch ((opid lsl 3) lor (n lsl 2) lor 1)
  359. else if n >= 0 && n <= 0xFF then begin
  360. IO.write_byte ch ((opid lsl 2) lor 2);
  361. IO.write_byte ch n;
  362. end else begin
  363. IO.write_byte ch ((opid lsl 2) lor 3);
  364. IO.write_i32 ch n;
  365. end
  366. ) ops