hl2c.ml 58 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789
  1. (*
  2. * Copyright (C)2005-2019 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. *)
  22. open Hlcode
  23. type comparison =
  24. | CEq
  25. | CNeq
  26. | CLt
  27. | CGt
  28. | CLte
  29. | CGte
  30. type output_options =
  31. | OOLabel
  32. | OOCase of int
  33. | OODefault
  34. | OOIncreaseIndent
  35. | OODecreaseIndent
  36. | OOBeginBlock
  37. | OOEndBlock
  38. | OOBreak
  39. type code_module = {
  40. m_name : string;
  41. mutable m_functions : function_entry list;
  42. mutable m_types : ttype list;
  43. }
  44. and function_entry = {
  45. fe_index : int;
  46. mutable fe_name : string;
  47. mutable fe_decl : fundecl option;
  48. mutable fe_args : ttype list;
  49. mutable fe_ret : ttype;
  50. mutable fe_module : code_module option;
  51. mutable fe_called_by : function_entry list;
  52. mutable fe_calling : function_entry list;
  53. }
  54. type context = {
  55. version : int;
  56. out : Buffer.t;
  57. mutable tabs : string;
  58. hash_cache : (int, int32) Hashtbl.t;
  59. hash_mem : (int32, bool) Hashtbl.t;
  60. mutable hash_cache_list : int list;
  61. hlcode : code;
  62. dir : string;
  63. mutable curfile : string;
  64. mutable cfiles : string list;
  65. ftable : function_entry array;
  66. htypes : (ttype, string) PMap.t;
  67. gnames : string array;
  68. bytes_names : string array;
  69. mutable defines : string list;
  70. defined_funs : (int, unit) Hashtbl.t;
  71. hdefines : (string, unit) Hashtbl.t;
  72. mutable defined_types : (ttype, unit) PMap.t;
  73. mutable file_prefix : string;
  74. mutable fun_index : int;
  75. mutable type_module : (ttype, code_module) PMap.t;
  76. }
  77. let sprintf = Printf.sprintf
  78. let keywords =
  79. let c_kwds = [
  80. "auto";"break";"case";"char";"const";"continue";"default";"do";"double";"else";"enum";"extern";"float";"for";"goto";
  81. "if";"int";"long";"register";"return";"short";"signed";"sizeof";"static";"struct";"switch";"typedef";"union";"unsigned";
  82. "void";"volatile";"while";
  83. (* Values *)
  84. "NULL";"true";"false";
  85. (* MS specific *)
  86. "__asm";"dllimport2";"__int8";"naked2";"__based1";"__except";"__int16";"__stdcall";"__cdecl";"__fastcall";"__int32";
  87. "thread2";"__declspec";"__finally";"__int64";"__try";"dllexport2";"__inline";"__leave";"asm";
  88. (* reserved by HLC *)
  89. "t";
  90. (* GCC *)
  91. "typeof";
  92. (* C11 *)
  93. "_Alignas";"_Alignof";"_Atomic";"_Bool";"_Complex";"_Generic";"_Imaginary";"_Noreturn";"_Static_assert";"_Thread_local";"_Pragma";
  94. "inline";"restrict"
  95. ] in
  96. let h = Hashtbl.create 0 in
  97. List.iter (fun i -> Hashtbl.add h i ()) c_kwds;
  98. h
  99. let ident i = if Hashtbl.mem keywords i then "_" ^ i else i
  100. let s_comp = function
  101. | CLt -> "<"
  102. | CGt -> ">"
  103. | CEq -> "=="
  104. | CLte -> "<="
  105. | CGte -> ">="
  106. | CNeq -> "!="
  107. let core_types =
  108. let vp = { vfields = [||]; vindex = PMap.empty } in
  109. let ep = { ename = ""; eid = 0; eglobal = None; efields = [||] } in
  110. [HVoid;HUI8;HUI16;HI32;HI64;HF32;HF64;HBool;HBytes;HDyn;HFun ([],HVoid);HObj null_proto;HArray;HType;HRef HVoid;HVirtual vp;HDynObj;HAbstract ("",0);HEnum ep;HNull HVoid;HMethod ([],HVoid);HStruct null_proto]
  111. let tname str =
  112. let n = String.concat "__" (ExtString.String.nsplit str ".") in
  113. if Hashtbl.mem keywords ("_" ^ n) then "__" ^ n else n
  114. let is_gc_ptr = function
  115. | HVoid | HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 | HBool | HType | HRef _ | HMethod _ -> false
  116. | HBytes | HDyn | HFun _ | HObj _ | HArray | HVirtual _ | HDynObj | HAbstract _ | HEnum _ | HNull _ | HStruct _ -> true
  117. let is_ptr = function
  118. | HVoid | HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 | HBool -> false
  119. | _ -> true
  120. let rec ctype_no_ptr = function
  121. | HVoid -> "void",0
  122. | HUI8 -> "unsigned char",0
  123. | HUI16 -> "unsigned short",0
  124. | HI32 -> "int",0
  125. | HI64 -> "int64",0
  126. | HF32 -> "float",0
  127. | HF64 -> "double",0
  128. | HBool -> "bool",0
  129. | HBytes -> "vbyte",1
  130. | HDyn -> "vdynamic",1
  131. | HFun _ -> "vclosure",1
  132. | HObj p | HStruct p -> tname p.pname,0
  133. | HArray -> "varray",1
  134. | HType -> "hl_type",1
  135. | HRef t -> let s,i = ctype_no_ptr t in s,i + 1
  136. | HVirtual _ -> "vvirtual",1
  137. | HDynObj -> "vdynobj",1
  138. | HAbstract (name,_) -> name,1
  139. | HEnum _ -> "venum",1
  140. | HNull _ -> "vdynamic",1
  141. | HMethod _ -> "void",1
  142. let ctype t =
  143. let t, nptr = ctype_no_ptr t in
  144. if nptr = 0 then t else t ^ String.make nptr '*'
  145. let args_repr args =
  146. if args = [] then "void" else String.concat "," (List.map ctype args)
  147. let cast_fun s args t =
  148. sprintf "((%s (*)(%s))%s)" (ctype t) (args_repr args) s
  149. let dyn_value_field t =
  150. "->v." ^ match t with
  151. | HUI8 -> "ui8"
  152. | HUI16 -> "ui16"
  153. | HI32 -> "i"
  154. | HI64 -> "i64"
  155. | HF32 -> "f"
  156. | HF64 -> "d"
  157. | HBool -> "b"
  158. | _ -> "ptr"
  159. let type_id t =
  160. match t with
  161. | HVoid -> "HVOID"
  162. | HUI8 -> "HUI8"
  163. | HUI16 -> "HUI16"
  164. | HI32 -> "HI32"
  165. | HI64 -> "HI64"
  166. | HF32 -> "HF32"
  167. | HF64 -> "HF64"
  168. | HBool -> "HBOOL"
  169. | HBytes -> "HBYTES"
  170. | HDyn -> "HDYN"
  171. | HFun _ -> "HFUN"
  172. | HObj _ -> "HOBJ"
  173. | HArray -> "HARRAY"
  174. | HType -> "HTYPE"
  175. | HRef _ -> "HREF"
  176. | HVirtual _ -> "HVIRTUAL"
  177. | HDynObj -> "HDYNOBJ"
  178. | HAbstract _ -> "HABSTRACT"
  179. | HEnum _ -> "HENUM"
  180. | HNull _ -> "HNULL"
  181. | HMethod _ -> "HMETHOD"
  182. | HStruct _ -> "HSTRUCT"
  183. let var_type n t =
  184. ctype t ^ " " ^ ident n
  185. let block ctx =
  186. ctx.tabs <- ctx.tabs ^ "\t"
  187. let unblock ctx =
  188. ctx.tabs <- String.sub ctx.tabs 0 (String.length ctx.tabs - 1)
  189. let hash ctx sid =
  190. try
  191. Hashtbl.find ctx.hash_cache sid
  192. with Not_found ->
  193. let rec loop h =
  194. if Hashtbl.mem ctx.hash_mem h then loop (Int32.add h Int32.one) else h
  195. in
  196. let h = loop (hl_hash ctx.hlcode.strings.(sid)) in
  197. Hashtbl.add ctx.hash_cache sid h;
  198. Hashtbl.add ctx.hash_mem h true;
  199. ctx.hash_cache_list <- sid :: ctx.hash_cache_list;
  200. h
  201. let type_name ctx t =
  202. try PMap.find t ctx.htypes with Not_found -> Globals.die "" __LOC__
  203. let define ctx s =
  204. if not (Hashtbl.mem ctx.hdefines s) then begin
  205. ctx.defines <- s :: ctx.defines;
  206. Hashtbl.add ctx.hdefines s ();
  207. end
  208. let rec define_type ctx t =
  209. match t with
  210. | HVoid | HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 | HBool | HBytes | HDyn | HArray | HType | HDynObj | HNull _ | HRef _ -> ()
  211. | HAbstract _ ->
  212. define ctx "#include <hl/natives.h>";
  213. | HFun (args,ret) | HMethod (args,ret) ->
  214. List.iter (define_type ctx) args;
  215. define_type ctx ret
  216. | HEnum _ | HObj _ | HStruct _ when not (PMap.exists t ctx.defined_types) ->
  217. ctx.defined_types <- PMap.add t () ctx.defined_types;
  218. define ctx (sprintf "#include <%s.h>" (try PMap.find t ctx.type_module with Not_found -> Globals.die "" __LOC__).m_name)
  219. | HVirtual vp when not (PMap.exists t ctx.defined_types) ->
  220. ctx.defined_types <- PMap.add t () ctx.defined_types;
  221. Array.iter (fun (_,_,t) -> define_type ctx t) vp.vfields
  222. | HEnum _ | HObj _ | HStruct _ | HVirtual _ ->
  223. ()
  224. let type_value ctx t =
  225. let n = type_name ctx t in
  226. define ctx (sprintf "extern hl_type %s;" n);
  227. "&" ^ n
  228. let enum_constr_type ctx e i =
  229. define_type ctx (HEnum e);
  230. let cname,_, tl = e.efields.(i) in
  231. if Array.length tl = 0 then
  232. "venum"
  233. else
  234. let name = if e.eid = 0 then
  235. let name = (try PMap.find (HEnum e) ctx.htypes with Not_found -> Globals.die "" __LOC__) in
  236. "Enum" ^ name
  237. else
  238. String.concat "_" (ExtString.String.nsplit e.ename ".")
  239. in
  240. if cname = "" then
  241. name
  242. else
  243. name ^ "_" ^ cname
  244. let output ctx str =
  245. Buffer.add_string ctx.out str
  246. let output_char ctx c =
  247. Buffer.add_char ctx.out c
  248. let line ctx str =
  249. output ctx ctx.tabs;
  250. output ctx str;
  251. output_char ctx '\n'
  252. let expr ctx str =
  253. output ctx ctx.tabs;
  254. output ctx str;
  255. output ctx ";\n"
  256. let unamed_field fid = "f$" ^ string_of_int fid
  257. let obj_field fid name =
  258. if name = "" then unamed_field fid else ident name
  259. let close_file ctx =
  260. let str = Buffer.contents ctx.out in
  261. let defines = List.rev ctx.defines in
  262. let str = (match defines with [] -> str | l -> String.concat "\n" l ^ "\n\n" ^ str) in
  263. ctx.defines <- [];
  264. ctx.defined_types <- PMap.empty;
  265. Hashtbl.clear ctx.hdefines;
  266. Hashtbl.clear ctx.defined_funs;
  267. Buffer.reset ctx.out;
  268. let fpath = ctx.dir ^ "/" ^ ctx.curfile in
  269. if String.sub ctx.curfile (String.length ctx.curfile - 2) 2 = ".c" then ctx.cfiles <- ctx.curfile :: ctx.cfiles;
  270. ctx.curfile <- "";
  271. let fcontent = (try Std.input_file ~bin:true fpath with _ -> "") in
  272. if fcontent <> str then begin
  273. Path.mkdir_recursive "" (ExtString.String.nsplit (Filename.dirname fpath) "/");
  274. let ch = open_out_bin fpath in
  275. output_string ch str;
  276. close_out ch;
  277. end
  278. let bom = "\xEF\xBB\xBF"
  279. let define_global ctx g =
  280. let t = ctx.hlcode.globals.(g) in
  281. define_type ctx t;
  282. define ctx (sprintf "extern %s;" (var_type ctx.gnames.(g) t))
  283. let define_function ctx fid =
  284. let ft = ctx.ftable.(fid) in
  285. let fid = if ft.fe_decl = None then -1 else fid in
  286. if not (Hashtbl.mem ctx.defined_funs fid) then begin
  287. Hashtbl.add ctx.defined_funs fid ();
  288. (match ft.fe_decl with
  289. | None ->
  290. define ctx "#include <hl/natives.h>"
  291. | Some f ->
  292. define_type ctx f.ftype;
  293. ctx.defines <- sprintf "%s %s(%s);" (ctype ft.fe_ret) ft.fe_name (args_repr ft.fe_args) :: ctx.defines);
  294. end;
  295. ft.fe_name
  296. let short_digest str =
  297. String.sub (Digest.to_hex (Digest.string str)) 0 7
  298. let open_file ctx file =
  299. if ctx.curfile <> "" then close_file ctx;
  300. let version_major = ctx.version / 1000 in
  301. let version_minor = (ctx.version mod 1000) / 100 in
  302. let version_revision = (ctx.version mod 100) in
  303. if file <> "hlc.json" then define ctx (sprintf "%s// Generated by HLC %d.%d.%d (HL v%d)" bom version_major version_minor version_revision ctx.hlcode.version);
  304. ctx.curfile <- file;
  305. ctx.fun_index <- 0;
  306. ctx.file_prefix <- (short_digest file) ^ "_"
  307. let string_data_limit = 64
  308. let string ctx sid =
  309. let s = ctx.hlcode.strings.(sid) in
  310. if String.length s < string_data_limit then
  311. sprintf "USTR(\"%s\")" (StringHelper.s_escape s)
  312. else begin
  313. let id = short_digest s in
  314. define ctx (sprintf "extern vbyte string$%s[];" id);
  315. sprintf "string$%s" id
  316. end
  317. let generate_reflection ctx =
  318. let line = line ctx and expr = expr ctx in
  319. let sline fmt = Printf.ksprintf line fmt and sexpr fmt = Printf.ksprintf expr fmt in
  320. let funByArgs = Hashtbl.create 0 in
  321. let type_kind t =
  322. match t with
  323. | HVoid | HF32 | HF64 | HI64 -> t
  324. | HBool | HUI8 | HUI16 | HI32 -> HI32
  325. | _ -> HDyn
  326. in
  327. let type_kind_id t =
  328. match t with
  329. | HVoid -> 0
  330. | HBool | HUI8 | HUI16 | HI32 -> 1 (* same int representation *)
  331. | HF32 -> 2
  332. | HF64 -> 3
  333. | HI64 -> 4
  334. | _ -> 5
  335. in
  336. let add_fun args t =
  337. let nargs = List.length args in
  338. let kargs = List.map type_kind args in
  339. let kt = type_kind t in
  340. let h = try Hashtbl.find funByArgs nargs with Not_found -> let h = Hashtbl.create 0 in Hashtbl.add funByArgs nargs h; h in
  341. Hashtbl.replace h (kargs,kt) ()
  342. in
  343. Array.iter (fun f ->
  344. Array.iter (fun op ->
  345. match op with
  346. | OSafeCast (dst,_) | ODynGet (dst,_,_) ->
  347. (match f.regs.(dst) with
  348. | HFun (args, t) -> add_fun args t
  349. | _ -> ())
  350. | _ -> ()
  351. ) f.code
  352. ) ctx.hlcode.functions;
  353. Array.iter (fun f -> add_fun f.fe_args f.fe_ret) ctx.ftable;
  354. let argsCounts = List.sort compare (Hashtbl.fold (fun i _ acc -> i :: acc) funByArgs []) in
  355. sexpr "static int TKIND[] = {%s}" (String.concat "," (List.map (fun t -> string_of_int (type_kind_id (type_kind t))) core_types));
  356. line "";
  357. line "void *hlc_static_call( void *fun, hl_type *t, void **args, vdynamic *out ) {";
  358. block ctx;
  359. sexpr "int chk = TKIND[t->fun->ret->kind]";
  360. sexpr "vdynamic *d";
  361. line "switch( t->fun->nargs ) {";
  362. List.iter (fun nargs ->
  363. sline "case %d:" nargs;
  364. block ctx;
  365. if nargs > 9 then sexpr "hl_fatal(\"Too many arguments, TODO:use more bits\")" else begin
  366. for i = 0 to nargs-1 do
  367. sexpr "chk |= TKIND[t->fun->args[%d]->kind] << %d" i ((i + 1) * 3);
  368. done;
  369. line "switch( chk ) {";
  370. Hashtbl.iter (fun (args,t) _ ->
  371. let s = ref (-1) in
  372. let chk = List.fold_left (fun chk t -> incr s; chk lor ((type_kind_id t) lsl (!s * 3))) 0 (t :: args) in
  373. sline "case %d:" chk;
  374. block ctx;
  375. let idx = ref (-1) in
  376. let vargs = List.map (fun t ->
  377. incr idx;
  378. if is_ptr t then
  379. sprintf "(%s)args[%d]" (ctype t) !idx
  380. else
  381. sprintf "*(%s*)args[%d]" (ctype t) !idx
  382. ) args in
  383. let call = sprintf "%s(%s)" (cast_fun "fun" args t) (String.concat "," vargs) in
  384. if is_ptr t then
  385. sexpr "return %s" call
  386. else if t = HVoid then begin
  387. expr call;
  388. expr "return NULL";
  389. end else begin
  390. sexpr "out%s = %s" (dyn_value_field t) call;
  391. sexpr "return &out%s" (dyn_value_field t);
  392. end;
  393. unblock ctx;
  394. ) (Hashtbl.find funByArgs nargs);
  395. sline "}";
  396. expr "break";
  397. end;
  398. unblock ctx;
  399. ) argsCounts;
  400. line "}";
  401. sexpr "hl_fatal(\"Unsupported dynamic call\")";
  402. sexpr "return NULL";
  403. unblock ctx;
  404. line "}";
  405. line "";
  406. let wrap_char = function
  407. | HVoid -> "v"
  408. | HUI8 | HUI16 | HBool | HI32 -> "i"
  409. | HF32 -> "f"
  410. | HF64 -> "d"
  411. | HI64 -> "i64"
  412. | _ -> "p"
  413. in
  414. let make_wrap_name args t =
  415. String.concat "" (List.map wrap_char args) ^ "_" ^ wrap_char t
  416. in
  417. List.iter (fun nargs ->
  418. Hashtbl.iter (fun (args,t) _ ->
  419. let name = make_wrap_name args t in
  420. sline "static %s wrap_%s(void *value%s) {" (ctype t) name (String.concat "" (list_mapi (fun i t -> "," ^ var_type ("p" ^ string_of_int i) t) args));
  421. block ctx;
  422. if args <> [] then sexpr "void *args[] = {%s}" (String.concat "," (list_mapi (fun i t ->
  423. if not (is_ptr t) then
  424. sprintf "&p%d" i
  425. else
  426. sprintf "p%d" i
  427. ) args));
  428. let vargs = if args = [] then "NULL" else "args" in
  429. if t = HVoid then
  430. sexpr "hl_wrapper_call(value,%s,NULL)" vargs
  431. else if is_ptr t then
  432. sexpr "return hl_wrapper_call(value,%s,NULL)" vargs
  433. else begin
  434. expr "vdynamic ret";
  435. sexpr "hl_wrapper_call(value,%s,&ret)" vargs;
  436. sexpr "return ret.v.%s" (wrap_char t);
  437. end;
  438. unblock ctx;
  439. line "}";
  440. ) (Hashtbl.find funByArgs nargs);
  441. ) argsCounts;
  442. line "";
  443. line "void *hlc_get_wrapper( hl_type *t ) {";
  444. block ctx;
  445. sexpr "int chk = TKIND[t->fun->ret->kind]";
  446. line "switch( t->fun->nargs ) {";
  447. List.iter (fun nargs ->
  448. sline "case %d:" nargs;
  449. block ctx;
  450. if nargs > 9 then sexpr "hl_fatal(\"Too many arguments, TODO:use more bits\")" else begin
  451. for i = 0 to nargs-1 do
  452. sexpr "chk |= TKIND[t->fun->args[%d]->kind] << %d" i ((i + 1) * 3);
  453. done;
  454. line "switch( chk ) {";
  455. Hashtbl.iter (fun (args,t) _ ->
  456. let s = ref (-1) in
  457. let chk = List.fold_left (fun chk t -> incr s; chk lor ((type_kind_id t) lsl (!s * 3))) 0 (t :: args) in
  458. sexpr "case %d: return wrap_%s" chk (make_wrap_name args t);
  459. ) (Hashtbl.find funByArgs nargs);
  460. sline "}";
  461. expr "break";
  462. end;
  463. unblock ctx;
  464. ) argsCounts;
  465. line "}";
  466. sexpr "return NULL";
  467. unblock ctx;
  468. line "}";
  469. line ""
  470. let generate_function ctx f =
  471. let line = line ctx and expr = expr ctx in
  472. let sline fmt = Printf.ksprintf line fmt and sexpr fmt = Printf.ksprintf expr fmt in
  473. let define fmt = Printf.ksprintf (define ctx) fmt in
  474. let block() = block ctx and unblock() = unblock ctx in
  475. let type_value = type_value ctx in
  476. let code = ctx.hlcode in
  477. let rid = ref (-1) in
  478. let cl_id = ref 0 in
  479. let reg id = "r" ^ string_of_int id in
  480. let label p = sprintf "label$%s%d_%d" ctx.file_prefix ctx.fun_index p in
  481. ctx.fun_index <- ctx.fun_index + 1;
  482. Hashtbl.add ctx.defined_funs f.findex ();
  483. Array.iter (define_type ctx) f.regs;
  484. define_type ctx f.ftype;
  485. let rtype r = f.regs.(r) in
  486. let funname fid = define_function ctx fid in
  487. let rcast r t =
  488. if tsame (rtype r) t then (reg r)
  489. else Printf.sprintf "((%s)%s)" (ctype t) (reg r)
  490. in
  491. let rfun r args t =
  492. cast_fun (reg r ^ "->fun") args t
  493. in
  494. let rassign r t =
  495. let rt = rtype r in
  496. if t = HVoid then "" else
  497. let assign = reg r ^ " = " in
  498. if tsame t rt then assign else
  499. if not (safe_cast t rt) then Globals.die "" __LOC__
  500. else assign ^ "(" ^ ctype rt ^ ")"
  501. in
  502. let ocall r fid args =
  503. let ft = ctx.ftable.(fid) in
  504. let rstr = rassign r ft.fe_ret in
  505. sexpr "%s%s(%s)" rstr (funname fid) (String.concat "," (List.map2 rcast args ft.fe_args))
  506. in
  507. let dyn_prefix = function
  508. | HUI8 | HUI16 | HI32 | HBool -> "i"
  509. | HF32 -> "f"
  510. | HF64 -> "d"
  511. | HI64 -> "i64"
  512. | _ -> "p"
  513. in
  514. let type_value_opt t =
  515. match t with HF32 | HF64 -> "" | _ -> "," ^ type_value t
  516. in
  517. let dyn_call r f pl =
  518. line "{";
  519. block();
  520. if pl <> [] then sexpr "vdynamic *args[] = {%s}" (String.concat "," (List.map (fun p ->
  521. match rtype p with
  522. | HDyn ->
  523. reg p
  524. | t ->
  525. if is_dynamic t then
  526. sprintf "(vdynamic*)%s" (reg p)
  527. else
  528. sprintf "hl_make_dyn(&%s,%s)" (reg p) (type_value t)
  529. ) pl));
  530. let rt = rtype r in
  531. let ret = if rt = HVoid then "" else if is_dynamic rt then sprintf "%s = (%s)" (reg r) (ctype rt) else "vdynamic *ret = " in
  532. sexpr "%shl_dyn_call((vclosure*)%s,%s,%d)" ret (reg f) (if pl = [] then "NULL" else "args") (List.length pl);
  533. if rt <> HVoid && not (is_dynamic rt) then sexpr "%s = (%s)hl_dyn_cast%s(&ret,&hlt_dyn%s)" (reg r) (ctype rt) (dyn_prefix rt) (type_value_opt rt);
  534. unblock();
  535. line "}";
  536. in
  537. let mcall r fid = function
  538. | [] -> Globals.die "" __LOC__
  539. | o :: args ->
  540. match rtype o with
  541. | HObj _ | HStruct _ ->
  542. let vfun = cast_fun (sprintf "%s->$type->vobj_proto[%d]" (reg o) fid) (rtype o :: List.map rtype args) (rtype r) in
  543. sexpr "%s%s(%s)" (rassign r (rtype r)) vfun (String.concat "," (List.map reg (o::args)))
  544. | HVirtual vp ->
  545. let rt = rtype r in
  546. let meth = sprintf "hl_vfields(%s)[%d]" (reg o) fid in
  547. let meth = cast_fun meth (HDyn :: List.map rtype args) rt in
  548. sline "if( hl_vfields(%s)[%d] ) %s%s(%s); else {" (reg o) fid (rassign r rt) meth (String.concat "," ((reg o ^ "->value") :: List.map reg args));
  549. block();
  550. if args <> [] then sexpr "void *args[] = {%s}" (String.concat "," (List.map (fun p ->
  551. let t = rtype p in
  552. if is_ptr t then
  553. reg p
  554. else
  555. sprintf "&%s" (reg p)
  556. ) args));
  557. let rt = rtype r in
  558. let ret = if rt = HVoid then "" else if is_ptr rt then sprintf "%s = (%s)" (reg r) (ctype rt) else begin sexpr "vdynamic ret"; ""; end in
  559. let fname, fid, ft = vp.vfields.(fid) in
  560. sexpr "%shl_dyn_call_obj(%s->value,%s,%ld/*%s*/,%s,%s)" ret (reg o) (type_value ft) (hash ctx fid) fname (if args = [] then "NULL" else "args") (if is_ptr rt || rt == HVoid then "NULL" else "&ret");
  561. if rt <> HVoid && not (is_ptr rt) then sexpr "%s = (%s)ret.v.%s" (reg r) (ctype rt) (dyn_prefix rt);
  562. unblock();
  563. sline "}"
  564. | _ ->
  565. Globals.die "" __LOC__
  566. in
  567. let set_field obj fid v =
  568. match rtype obj with
  569. | HObj o | HStruct o ->
  570. let name, t = resolve_field o fid in
  571. sexpr "%s->%s = %s" (reg obj) (obj_field fid name) (rcast v t)
  572. | HVirtual vp ->
  573. let name, nid, t = vp.vfields.(fid) in
  574. let dset = sprintf "hl_dyn_set%s(%s->value,%ld/*%s*/%s,%s)" (dyn_prefix t) (reg obj) (hash ctx nid) name (type_value_opt (rtype v)) (reg v) in
  575. sexpr "if( hl_vfields(%s)[%d] ) *(%s*)(hl_vfields(%s)[%d]) = (%s)%s; else %s" (reg obj) fid (ctype t) (reg obj) fid (ctype t) (reg v) dset
  576. | _ ->
  577. Globals.die "" __LOC__
  578. in
  579. let get_field r obj fid =
  580. match rtype obj with
  581. | HObj o | HStruct o ->
  582. let name, t = resolve_field o fid in
  583. sexpr "%s%s->%s" (rassign r t) (reg obj) (obj_field fid name)
  584. | HVirtual v ->
  585. let name, nid, t = v.vfields.(fid) in
  586. let dget = sprintf "(%s)hl_dyn_get%s(%s->value,%ld/*%s*/%s)" (ctype t) (dyn_prefix t) (reg obj) (hash ctx nid) name (type_value_opt t) in
  587. sexpr "%shl_vfields(%s)[%d] ? (*(%s*)(hl_vfields(%s)[%d])) : %s" (rassign r t) (reg obj) fid (ctype t) (reg obj) fid dget
  588. | _ ->
  589. Globals.die "" __LOC__
  590. in
  591. let fret = (match f.ftype with
  592. | HFun (args,t) ->
  593. sline "%s %s(%s) {" (ctype t) (funname f.findex) (String.concat "," (List.map (fun t -> incr rid; var_type (reg !rid) t) args));
  594. t
  595. | _ ->
  596. Globals.die "" __LOC__
  597. ) in
  598. block();
  599. let var_map = Hashtbl.create 0 in
  600. Array.iteri (fun i t ->
  601. if i <= !rid || t = HVoid then ()
  602. else
  603. let key = ctype_no_ptr t in
  604. Hashtbl.replace var_map key (try (reg i) :: Hashtbl.find var_map key with Not_found -> [reg i])
  605. ) f.regs;
  606. Hashtbl.iter (fun (s,i) il ->
  607. let prefix = String.make i '*' in
  608. let il = List.rev_map (fun s -> prefix ^ s) il in
  609. sexpr "%s %s" s (String.concat ", " il)
  610. ) var_map;
  611. let output_options = Array.make (Array.length f.code + 1) [] in
  612. let output_at i oo = output_options.(i) <- oo :: output_options.(i) in
  613. let output_at2 i ool = List.iter (output_at i) ool in
  614. let has_label i = List.exists (function OOLabel -> true | _ -> false) output_options.(i) in
  615. let trap_depth = ref 0 in
  616. let max_trap_depth = ref 0 in
  617. Array.iter (fun op ->
  618. match op with
  619. | OTrap _ ->
  620. incr trap_depth;
  621. if !trap_depth > !max_trap_depth then max_trap_depth := !trap_depth
  622. | OEndTrap true ->
  623. decr trap_depth
  624. | OStaticClosure (_, fid) ->
  625. let ft = ctx.ftable.(fid) in
  626. sexpr "static vclosure cl$%d = { %s, %s, 0 }" (!cl_id) (type_value (HFun (ft.fe_args,ft.fe_ret))) (funname fid);
  627. incr cl_id;
  628. | _ ->
  629. ()
  630. ) f.code;
  631. for i = 0 to !max_trap_depth - 1 do
  632. sexpr "hl_trap_ctx trap$%d" i;
  633. done;
  634. cl_id := 0;
  635. let flush_options i =
  636. match output_options.(i) with
  637. | [] -> ()
  638. | opts ->
  639. (* put label after } *)
  640. let opts = if has_label i && List.mem OOEndBlock opts then OOLabel :: List.filter (fun i -> i <> OOLabel) opts else opts in
  641. let opts = List.rev opts in
  642. List.iter (function
  643. | OOLabel -> sline "%s:" (label i)
  644. | OOCase i -> sline "case %i:" i
  645. | OODefault -> line "default:"
  646. | OOBreak -> line "break;";
  647. | OOIncreaseIndent -> block()
  648. | OODecreaseIndent -> unblock()
  649. | OOBeginBlock -> line "{"
  650. | OOEndBlock -> line "}"
  651. ) opts
  652. in
  653. Array.iteri (fun i op ->
  654. flush_options i;
  655. let label delta =
  656. let addr = delta + i + 1 in
  657. let label = label addr in
  658. if not (has_label addr) then output_at addr OOLabel;
  659. label
  660. in
  661. let todo() =
  662. sexpr "hl_fatal(\"%s\")" (ostr (fun id -> "f" ^ string_of_int id) op)
  663. in
  664. let rec compare_op op a b d =
  665. let phys_compare() =
  666. sexpr "if( %s %s %s ) goto %s" (reg a) (s_comp op) (rcast b (rtype a)) (label d)
  667. in
  668. (*
  669. safe_cast is already checked
  670. two ways (same type) for eq
  671. one way for comparisons
  672. *)
  673. match rtype a, rtype b with
  674. | (HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool), (HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool) ->
  675. phys_compare()
  676. | HType, HType ->
  677. sexpr "if( hl_same_type(%s,%s) %s 0 ) {} else goto %s" (reg a) (reg b) (s_comp op) (label d)
  678. | HNull t, HNull _ ->
  679. let field = dyn_value_field t in
  680. let pcompare = sprintf "(%s%s %s %s%s)" (reg a) field (s_comp op) (reg b) field in
  681. if op = CEq then
  682. sexpr "if( %s == %s || (%s && %s && %s) ) goto %s" (reg a) (reg b) (reg a) (reg b) pcompare (label d)
  683. else if op = CNeq then
  684. sexpr "if( %s != %s && (!%s || !%s || %s) ) goto %s" (reg a) (reg b) (reg a) (reg b) pcompare (label d)
  685. else
  686. sexpr "if( %s && %s && %s ) goto %s" (reg a) (reg b) pcompare (label d)
  687. | (HDyn | HFun _), _ | _, (HDyn | HFun _) ->
  688. let inv = if op = CGt || op = CGte then "&& i != hl_invalid_comparison " else "" in
  689. sexpr "{ int i = hl_dyn_compare((vdynamic*)%s,(vdynamic*)%s); if( i %s 0 %s) goto %s; }" (reg a) (reg b) (s_comp op) inv (label d)
  690. | HObj oa, HObj _ ->
  691. (try
  692. let fid = PMap.find "__compare" oa.pfunctions in
  693. if op = CEq then
  694. sexpr "if( %s == %s || (%s && %s && %s(%s,(vdynamic*)%s) == 0) ) goto %s" (reg a) (reg b) (reg a) (reg b) (funname fid) (reg a) (reg b) (label d)
  695. else if op = CNeq then
  696. sexpr "if( %s != %s && (!%s || !%s || %s(%s,(vdynamic*)%s) != 0) ) goto %s" (reg a) (reg b) (reg a) (reg b) (funname fid) (reg a) (reg b) (label d)
  697. else
  698. sexpr "if( %s && %s && %s(%s,(vdynamic*)%s) %s 0 ) goto %s" (reg a) (reg b) (funname fid) (reg a) (reg b) (s_comp op) (label d)
  699. with Not_found ->
  700. phys_compare())
  701. | HStruct _, HStruct _ ->
  702. phys_compare()
  703. | HVirtual _, HVirtual _ ->
  704. if op = CEq then
  705. sexpr "if( %s == %s || (%s && %s && %s->value && %s->value && %s->value == %s->value) ) goto %s" (reg a) (reg b) (reg a) (reg b) (reg a) (reg b) (reg a) (reg b) (label d)
  706. else if op = CNeq then
  707. sexpr "if( %s != %s && (!%s || !%s || !%s->value || !%s->value || %s->value != %s->value) ) goto %s" (reg a) (reg b) (reg a) (reg b) (reg a) (reg b) (reg a) (reg b) (label d)
  708. else
  709. Globals.die "" __LOC__
  710. | HEnum _, HEnum _ | HDynObj, HDynObj | HAbstract _, HAbstract _ ->
  711. phys_compare()
  712. | HVirtual _, HObj _->
  713. if op = CEq then
  714. sexpr "if( %s ? (%s && %s->value == (vdynamic*)%s) : (%s == NULL) ) goto %s" (reg a) (reg b) (reg a) (reg b) (reg b) (label d)
  715. else if op = CNeq then
  716. sexpr "if( %s ? (%s == NULL || %s->value != (vdynamic*)%s) : (%s != NULL) ) goto %s" (reg a) (reg b) (reg a) (reg b) (reg b) (label d)
  717. else
  718. Globals.die "" __LOC__
  719. | HObj _, HVirtual _ ->
  720. compare_op op b a d
  721. | ta, tb ->
  722. failwith ("Don't know how to compare " ^ tstr ta ^ " and " ^ tstr tb ^ " (hlc)")
  723. in
  724. match op with
  725. | OMov (r,v) ->
  726. if rtype r <> HVoid then sexpr "%s = %s" (reg r) (rcast v (rtype r))
  727. | OInt (r,idx) ->
  728. if code.ints.(idx) = 0x80000000l then
  729. sexpr "%s = 0x80000000" (reg r)
  730. else
  731. sexpr "%s = %ld" (reg r) code.ints.(idx)
  732. | OFloat (r,idx) ->
  733. let fstr = sprintf "%.19g" code.floats.(idx) in
  734. sexpr "%s = %s" (reg r) (if String.contains fstr '.' || String.contains fstr 'e' then fstr else fstr ^ ".")
  735. | OBool (r,b) ->
  736. sexpr "%s = %s" (reg r) (if b then "true" else "false")
  737. | OBytes (r,idx) ->
  738. define "extern vbyte %s[];" ctx.bytes_names.(idx);
  739. sexpr "%s = %s" (reg r) ctx.bytes_names.(idx)
  740. | OString (r,idx) ->
  741. sexpr "%s = (vbyte*)%s" (reg r) (string ctx idx)
  742. | ONull r ->
  743. sexpr "%s = NULL" (reg r)
  744. | OAdd (r,a,b) ->
  745. sexpr "%s = %s + %s" (reg r) (reg a) (reg b)
  746. | OSub (r,a,b) ->
  747. sexpr "%s = %s - %s" (reg r) (reg a) (reg b)
  748. | OMul (r,a,b) ->
  749. sexpr "%s = %s * %s" (reg r) (reg a) (reg b)
  750. | OSDiv (r,a,b) ->
  751. (match rtype r with
  752. | HUI8 | HUI16 | HI32 ->
  753. sexpr "%s = %s == 0 ? 0 : %s / %s" (reg r) (reg b) (reg a) (reg b)
  754. | _ ->
  755. sexpr "%s = %s / %s" (reg r) (reg a) (reg b))
  756. | OUDiv (r,a,b) ->
  757. sexpr "%s = %s == 0 ? 0 : ((unsigned)%s) / ((unsigned)%s)" (reg r) (reg b) (reg a) (reg b)
  758. | OSMod (r,a,b) ->
  759. (match rtype r with
  760. | HUI8 | HUI16 | HI32 ->
  761. sexpr "%s = %s == 0 ? 0 : %s %% %s" (reg r) (reg b) (reg a) (reg b)
  762. | HF32 ->
  763. sexpr "%s = fmodf(%s,%s)" (reg r) (reg a) (reg b)
  764. | HF64 ->
  765. sexpr "%s = fmod(%s,%s)" (reg r) (reg a) (reg b)
  766. | _ ->
  767. Globals.die "" __LOC__)
  768. | OUMod (r,a,b) ->
  769. sexpr "%s = %s == 0 ? 0 : ((unsigned)%s) %% ((unsigned)%s)" (reg r) (reg b) (reg a) (reg b)
  770. | OShl (r,a,b) ->
  771. sexpr "%s = %s << %s" (reg r) (reg a) (reg b)
  772. | OSShr (r,a,b) ->
  773. sexpr "%s = %s >> %s" (reg r) (reg a) (reg b)
  774. | OUShr (r,a,b) ->
  775. sexpr "%s = ((unsigned)%s) >> %s" (reg r) (reg a) (reg b)
  776. | OAnd (r,a,b) ->
  777. sexpr "%s = %s & %s" (reg r) (reg a) (reg b)
  778. | OOr (r,a,b) ->
  779. sexpr "%s = %s | %s" (reg r) (reg a) (reg b)
  780. | OXor (r,a,b) ->
  781. sexpr "%s = %s ^ %s" (reg r) (reg a) (reg b)
  782. | ONeg (r,v) ->
  783. sexpr "%s = -%s" (reg r) (reg v)
  784. | ONot (r,v) ->
  785. sexpr "%s = !%s" (reg r) (reg v)
  786. | OIncr r ->
  787. sexpr "++%s" (reg r)
  788. | ODecr r ->
  789. sexpr "--%s" (reg r)
  790. | OCall0 (r,fid) ->
  791. ocall r fid []
  792. | OCall1 (r,fid,a) ->
  793. ocall r fid [a]
  794. | OCall2 (r,fid,a,b) ->
  795. ocall r fid [a;b]
  796. | OCall3 (r,fid,a,b,c) ->
  797. ocall r fid [a;b;c]
  798. | OCall4 (r,fid,a,b,c,d) ->
  799. ocall r fid [a;b;c;d]
  800. | OCallN (r,fid,rl) ->
  801. ocall r fid rl
  802. | OCallMethod (r,fid,pl) ->
  803. mcall r fid pl
  804. | OCallThis (r,fid,pl) ->
  805. mcall r fid (0 :: pl)
  806. | OCallClosure (r,cl,pl) ->
  807. (match rtype cl with
  808. | HDyn ->
  809. dyn_call r cl pl
  810. | HFun (args,ret) ->
  811. let sargs = String.concat "," (List.map2 rcast pl args) in
  812. sexpr "%s%s->hasValue ? %s((vdynamic*)%s->value%s) : %s(%s)" (rassign r ret) (reg cl) (rfun cl (HDyn :: args) ret) (reg cl) (if sargs = "" then "" else "," ^ sargs) (rfun cl args ret) sargs
  813. | _ ->
  814. Globals.die "" __LOC__)
  815. | OStaticClosure (r,fid) ->
  816. sexpr "%s = &cl$%d" (reg r) (!cl_id);
  817. incr cl_id
  818. | OInstanceClosure (r,fid,ptr) ->
  819. let ft = ctx.ftable.(fid) in
  820. sexpr "%s = hl_alloc_closure_ptr(%s,%s,%s)" (reg r) (type_value (HFun (ft.fe_args,ft.fe_ret))) (funname fid) (reg ptr)
  821. | OVirtualClosure (r,o,m) ->
  822. (match rtype o with
  823. | HObj p ->
  824. let ft = ctx.ftable.(p.pvirtuals.(m)) in
  825. let s = sprintf "%s->$type->vobj_proto[%d]" (reg o) m in
  826. sexpr "%s = hl_alloc_closure_ptr(%s,%s,%s)" (reg r) (type_value (HFun(ft.fe_args,ft.fe_ret))) s (reg o)
  827. | _ ->
  828. todo())
  829. | OGetGlobal (r,g) ->
  830. define_global ctx g;
  831. sexpr "%s = (%s)%s" (reg r) (ctype (rtype r)) ctx.gnames.(g)
  832. | OSetGlobal (g,r) ->
  833. define_global ctx g;
  834. sexpr "%s = (%s)%s" ctx.gnames.(g) (ctype code.globals.(g)) (reg r)
  835. | ORet r ->
  836. if rtype r = HVoid then expr "return" else sexpr "return %s" (rcast r fret)
  837. | OJTrue (r,d) | OJNotNull (r,d) ->
  838. sexpr "if( %s ) goto %s" (reg r) (label d)
  839. | OJFalse (r,d) | OJNull (r,d) ->
  840. sexpr "if( !%s ) goto %s" (reg r) (label d)
  841. | OJSLt (a,b,d) ->
  842. compare_op CLt a b d
  843. | OJSGte (a,b,d) ->
  844. compare_op CGte a b d
  845. | OJSGt (a,b,d) ->
  846. compare_op CGt a b d
  847. | OJSLte (a,b,d) ->
  848. compare_op CLte a b d
  849. | OJULt (a,b,d) ->
  850. sexpr "if( ((unsigned)%s) < ((unsigned)%s) ) goto %s" (reg a) (reg b) (label d)
  851. | OJUGte (a,b,d) ->
  852. sexpr "if( ((unsigned)%s) >= ((unsigned)%s) ) goto %s" (reg a) (reg b) (label d)
  853. | OJNotLt (a,b,d) ->
  854. sexpr "if( !(%s < %s) ) goto %s" (reg a) (reg b) (label d)
  855. | OJNotGte (a,b,d) ->
  856. sexpr "if( !(%s >= %s) ) goto %s" (reg a) (reg b) (label d)
  857. | OJEq (a,b,d) ->
  858. compare_op CEq a b d
  859. | OJNotEq (a,b,d) ->
  860. compare_op CNeq a b d
  861. | OJAlways d ->
  862. sexpr "goto %s" (label d)
  863. | OLabel _ ->
  864. if not (has_label i) then sline "%s:" (label (-1))
  865. | OToDyn (r,v) when rtype v = HBool ->
  866. sexpr "%s = hl_alloc_dynbool(%s)" (reg r) (reg v)
  867. | OToDyn (r,v) ->
  868. if is_ptr (rtype v) then begin
  869. sline "if( %s == NULL ) %s = NULL; else {" (reg v) (reg r);
  870. block();
  871. end;
  872. sexpr "%s = hl_alloc_dynamic(%s)" (reg r) (type_value (rtype v));
  873. (match rtype v with
  874. | HUI8 | HUI16 | HI32 | HBool ->
  875. sexpr "%s->v.i = %s" (reg r) (reg v)
  876. | HI64 ->
  877. sexpr "%s->v.i64 = %s" (reg r) (reg v)
  878. | HF32 ->
  879. sexpr "%s->v.f = %s" (reg r) (reg v)
  880. | HF64 ->
  881. sexpr "%s->v.d = %s" (reg r) (reg v)
  882. | _ ->
  883. sexpr "%s->v.ptr = %s" (reg r) (reg v));
  884. if is_ptr (rtype v) then begin
  885. unblock();
  886. line "}";
  887. end;
  888. | OToSFloat (r,v) ->
  889. sexpr "%s = (%s)%s" (reg r) (ctype (rtype r)) (reg v)
  890. | OToUFloat (r,v) ->
  891. sexpr "%s = (%s)(unsigned)%s" (reg r) (ctype (rtype r)) (reg v)
  892. | OToInt (r,v) ->
  893. sexpr "%s = (int)%s" (reg r) (reg v)
  894. | ONew r ->
  895. (match rtype r with
  896. | HObj o | HStruct o -> sexpr "%s = (%s)hl_alloc_obj(%s)" (reg r) (tname o.pname) (type_value (rtype r))
  897. | HDynObj -> sexpr "%s = hl_alloc_dynobj()" (reg r)
  898. | HVirtual _ as t -> sexpr "%s = hl_alloc_virtual(%s)" (reg r) (type_value t)
  899. | _ -> Globals.die "" __LOC__)
  900. | OField (r,obj,fid) ->
  901. get_field r obj fid
  902. | OSetField (obj,fid,v) ->
  903. set_field obj fid v
  904. | OGetThis (r,fid) ->
  905. get_field r 0 fid
  906. | OSetThis (fid,r) ->
  907. set_field 0 fid r
  908. | OThrow r ->
  909. sexpr "hl_throw((vdynamic*)%s)" (reg r)
  910. | ORethrow r ->
  911. sexpr "hl_rethrow((vdynamic*)%s)" (reg r)
  912. | OGetUI8 (r,b,idx) ->
  913. sexpr "%s = *(unsigned char*)(%s + %s)" (reg r) (reg b) (reg idx)
  914. | OGetUI16 (r,b,idx) ->
  915. sexpr "%s = *(unsigned short*)(%s + %s)" (reg r) (reg b) (reg idx)
  916. | OGetMem (r,b,idx) ->
  917. sexpr "%s = *(%s*)(%s + %s)" (reg r) (ctype (rtype r)) (reg b) (reg idx)
  918. | OGetArray (r, arr, idx) ->
  919. sexpr "%s = ((%s*)(%s + 1))[%s]" (reg r) (ctype (rtype r)) (reg arr) (reg idx)
  920. | OSetUI8 (b,idx,r) ->
  921. sexpr "*(unsigned char*)(%s + %s) = (unsigned char)%s" (reg b) (reg idx) (reg r)
  922. | OSetUI16 (b,idx,r) ->
  923. sexpr "*(unsigned short*)(%s + %s) = (unsigned short)%s" (reg b) (reg idx) (reg r)
  924. | OSetMem (b,idx,r) ->
  925. sexpr "*(%s*)(%s + %s) = %s" (ctype (rtype r)) (reg b) (reg idx) (reg r)
  926. | OSetArray (arr,idx,v) ->
  927. sexpr "((%s*)(%s + 1))[%s] = %s" (ctype (rtype v)) (reg arr) (reg idx) (reg v)
  928. | OSafeCast (r,v) ->
  929. let tsrc = rtype v in
  930. let t = rtype r in
  931. if tsrc = HNull t then
  932. sexpr "%s = %s ? %s%s : 0" (reg r) (reg v) (reg v) (dyn_value_field t)
  933. else
  934. sexpr "%s = (%s)hl_dyn_cast%s(&%s,%s%s)" (reg r) (ctype t) (dyn_prefix t) (reg v) (type_value (rtype v)) (type_value_opt t)
  935. | OUnsafeCast (r,v) ->
  936. sexpr "%s = (%s)%s" (reg r) (ctype (rtype r)) (reg v)
  937. | OArraySize (r,a) ->
  938. sexpr "%s = %s->size" (reg r) (reg a)
  939. | OType (r,t) ->
  940. sexpr "%s = %s" (reg r) (type_value t)
  941. | OGetType (r,v) ->
  942. sexpr "%s = %s ? ((vdynamic*)%s)->t : &hlt_void" (reg r) (reg v) (reg v)
  943. | OGetTID (r,v) ->
  944. sexpr "%s = %s->kind" (reg r) (reg v)
  945. | ORef (r,v) ->
  946. sexpr "%s = &%s" (reg r) (reg v)
  947. | OUnref (r,v) ->
  948. sexpr "%s = *%s" (reg r) (reg v)
  949. | OSetref (r,v) ->
  950. sexpr "*%s = %s" (reg r) (reg v)
  951. | OToVirtual (r,v) ->
  952. sexpr "%s = hl_to_virtual(%s,(vdynamic*)%s)" (reg r) (type_value (rtype r)) (reg v)
  953. | ODynGet (r,o,sid) ->
  954. let t = rtype r in
  955. let h = hash ctx sid in
  956. sexpr "%s = (%s)hl_dyn_get%s((vdynamic*)%s,%ld/*%s*/%s)" (reg r) (ctype t) (dyn_prefix t) (reg o) h code.strings.(sid) (type_value_opt t)
  957. | ODynSet (o,sid,v) ->
  958. let h = hash ctx sid in
  959. sexpr "hl_dyn_set%s((vdynamic*)%s,%ld/*%s*/%s,%s)" (dyn_prefix (rtype v)) (reg o) h code.strings.(sid) (type_value_opt (rtype v)) (reg v)
  960. | OMakeEnum (r,cid,rl) ->
  961. let e, et = (match rtype r with HEnum e -> e, enum_constr_type ctx e cid | _ -> Globals.die "" __LOC__) in
  962. let need_tmp = List.mem r rl in
  963. let tmp = if not need_tmp then reg r else begin
  964. sexpr "{ venum *tmp";
  965. "tmp"
  966. end in
  967. sexpr "%s = hl_alloc_enum(%s,%d)" tmp (type_value (rtype r)) cid;
  968. let _,_,tl = e.efields.(cid) in
  969. list_iteri (fun i v ->
  970. sexpr "((%s*)%s)->p%d = %s" et tmp i (rcast v tl.(i))
  971. ) rl;
  972. if need_tmp then sexpr "%s = tmp; }" (reg r)
  973. | OEnumAlloc (r,cid) ->
  974. sexpr "%s = hl_alloc_enum(%s,%d)" (reg r) (type_value (rtype r)) cid
  975. | OEnumIndex (r,v) ->
  976. sexpr "%s = HL__ENUM_INDEX__(%s)" (reg r) (reg v)
  977. | OEnumField (r,e,cid,pid) ->
  978. let tname,(_,_,tl) = (match rtype e with HEnum e -> enum_constr_type ctx e cid, e.efields.(cid) | _ -> Globals.die "" __LOC__) in
  979. sexpr "%s((%s*)%s)->p%d" (rassign r tl.(pid)) tname (reg e) pid
  980. | OSetEnumField (e,pid,r) ->
  981. let tname, (_,_,tl) = (match rtype e with HEnum e -> enum_constr_type ctx e 0, e.efields.(0) | _ -> Globals.die "" __LOC__) in
  982. sexpr "((%s*)%s)->p%d = (%s)%s" tname (reg e) pid (ctype tl.(pid)) (reg r)
  983. | OSwitch (r,idx,eend) ->
  984. sline "switch(%s) {" (reg r);
  985. block();
  986. let pend = i+1+eend in
  987. (* insert at end if we have another switch case here *)
  988. let old = output_options.(pend) in
  989. output_options.(pend) <- [];
  990. (* insert cases *)
  991. output_at2 (i + 1) [OODefault;OOIncreaseIndent];
  992. Array.iteri (fun k delta ->
  993. output_at2 (delta + i + 1) [OODecreaseIndent;OOCase k;OOIncreaseIndent];
  994. if delta = eend then output_at pend OOBreak;
  995. ) idx;
  996. (* insert end switch *)
  997. output_at2 pend ([OODecreaseIndent;OODecreaseIndent;OOEndBlock] @ List.rev old);
  998. | ONullCheck r ->
  999. sexpr "if( %s == NULL ) hl_null_access()" (reg r)
  1000. | OTrap (r,d) ->
  1001. sexpr "hl_trap(trap$%d,%s,%s)" !trap_depth (reg r) (label d);
  1002. incr trap_depth
  1003. | OEndTrap b ->
  1004. sexpr "hl_endtrap(trap$%d)" (!trap_depth - 1);
  1005. if b then decr trap_depth;
  1006. | OAssert _ ->
  1007. sexpr "hl_assert()"
  1008. | ORefData (r,d) ->
  1009. (match rtype d with
  1010. | HArray ->
  1011. sexpr "%s = (%s)hl_aptr(%s,void*)" (reg r) (ctype (rtype r)) (reg d)
  1012. | _ ->
  1013. Globals.die "" __LOC__)
  1014. | ORefOffset (r,r2,off) ->
  1015. sexpr "%s = %s + %s" (reg r) (reg r2) (reg off)
  1016. | ONop _ ->
  1017. ()
  1018. ) f.code;
  1019. flush_options (Array.length f.code);
  1020. unblock();
  1021. line "}";
  1022. line ""
  1023. type type_desc =
  1024. | DSimple of ttype
  1025. | DFun of type_desc list * type_desc * bool
  1026. | DNamed of string
  1027. | DVirtual of (string * type_desc) array
  1028. | DContext of type_desc array
  1029. let valid_ident =
  1030. let e = Str.regexp "[^A-Za-z0-9_]+" in
  1031. (fun str -> Str.global_replace e "_" str)
  1032. let make_types_idents htypes =
  1033. let types_descs = ref PMap.empty in
  1034. let rec make_desc t =
  1035. match t with
  1036. | HVoid | HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 | HBool | HBytes | HDyn | HArray | HType | HRef _ | HDynObj | HNull _ ->
  1037. DSimple t
  1038. | HFun (tl,t) ->
  1039. DFun (List.map make_desc tl, make_desc t, true)
  1040. | HMethod (tl, t) ->
  1041. DFun (List.map make_desc tl, make_desc t, false)
  1042. | HObj p | HStruct p ->
  1043. DNamed p.pname
  1044. | HAbstract (n,_) ->
  1045. DNamed n
  1046. | HEnum e when e.ename = "" ->
  1047. let _,_,tl = e.efields.(0) in
  1048. DContext (Array.map make_desc tl)
  1049. | HEnum e ->
  1050. DNamed e.ename
  1051. | HVirtual vp ->
  1052. try
  1053. PMap.find vp (!types_descs)
  1054. with Not_found ->
  1055. let arr = Array.create (Array.length vp.vfields) ("",DSimple HVoid) in
  1056. let td = DVirtual arr in
  1057. types_descs := PMap.add vp td (!types_descs);
  1058. Array.iteri (fun i (f,_,t) -> arr.(i) <- (f,make_desc t)) vp.vfields;
  1059. td
  1060. in
  1061. let make_sign d =
  1062. String.sub (Digest.to_hex (Digest.bytes (Marshal.to_bytes d [Marshal.Compat_32]))) 0 7
  1063. in
  1064. let rec desc_string d =
  1065. match d with
  1066. | DSimple (HNull t) ->
  1067. "t$nul_" ^ tstr t
  1068. | DSimple (HRef t) ->
  1069. "t$ref_" ^ (match make_desc t with DSimple _ -> tstr t | d -> desc_string d)
  1070. | DSimple t ->
  1071. "t$_" ^ tstr t
  1072. | DFun _ ->
  1073. "t$fun_" ^ make_sign d
  1074. | DNamed n ->
  1075. "t$" ^ (String.concat "_" (ExtString.String.nsplit n "."))
  1076. | DVirtual _ ->
  1077. "t$vrt_" ^ (make_sign d)
  1078. | DContext _ ->
  1079. "t$ctx_" ^ (make_sign d)
  1080. in
  1081. PMap.mapi (fun t _ -> desc_string (make_desc t)) htypes
  1082. let make_global_names code gnames =
  1083. let hstrings = Hashtbl.create 0 in
  1084. let is_cstr = Hashtbl.create 0 in
  1085. Array.iter (fun (g,vl) ->
  1086. match code.globals.(g) with
  1087. | HObj { pname = "String" } ->
  1088. let str = code.strings.(vl.(0)) in
  1089. let v = valid_ident str in
  1090. Hashtbl.replace hstrings v (Hashtbl.mem hstrings v);
  1091. Hashtbl.add is_cstr g ();
  1092. gnames.(g) <- str
  1093. | _ -> ()
  1094. ) code.constants;
  1095. let gids = Array.mapi (fun i n -> (n,i)) gnames in
  1096. Array.sort (fun (n1,g1) (n2,g2) -> let d = compare n1 n2 in if d = 0 then compare g1 g2 else d) gids;
  1097. let gnames_used = Hashtbl.create 0 in
  1098. let gnames = Hashtbl.create 0 in
  1099. Array.iter (fun (str,g) ->
  1100. let id = (if Hashtbl.mem is_cstr g then "s$" else "g$") ^ (if String.length str > 32 then short_digest str else let i = valid_ident str in if i = "_" || (try Hashtbl.find hstrings i with Not_found -> false) then short_digest str else i) in
  1101. let rec loop id k =
  1102. let rid = if k = 0 then id else id ^ "_" ^ string_of_int k in
  1103. if Hashtbl.mem gnames_used rid then loop id (k+1) else rid
  1104. in
  1105. let id = loop id 0 in
  1106. Hashtbl.add gnames_used id ();
  1107. Hashtbl.add gnames g id;
  1108. ) gids;
  1109. Array.init (Array.length code.globals) (fun i -> Hashtbl.find gnames i)
  1110. let make_function_table code =
  1111. let new_entry i = { fe_index = i; fe_args = []; fe_ret = HVoid; fe_name = ""; fe_module = None; fe_calling = []; fe_called_by = []; fe_decl = None; } in
  1112. let ftable = Array.init (Array.length code.functions + Array.length code.natives) new_entry in
  1113. Array.iter (fun (lib,name,t,idx) ->
  1114. let fname =
  1115. let lib = code.strings.(lib) in
  1116. let lib = if lib = "std" then "hl" else lib in
  1117. lib ^ "_" ^ code.strings.(name)
  1118. in
  1119. match t with
  1120. | HFun (args, t) ->
  1121. let ft = ftable.(idx) in
  1122. ft.fe_name <- fname;
  1123. ft.fe_args <- args;
  1124. ft.fe_ret <- t
  1125. | _ ->
  1126. Globals.die "" __LOC__
  1127. ) code.natives;
  1128. Array.iter (fun f ->
  1129. let fname = String.concat "_" (ExtString.String.nsplit (fundecl_name f) ".") in
  1130. let ft = ftable.(f.findex) in
  1131. ft.fe_name <- fname;
  1132. (match f.ftype with
  1133. | HFun (args,t) ->
  1134. ft.fe_args <- args;
  1135. ft.fe_ret <- t;
  1136. | _ ->
  1137. Globals.die "" __LOC__);
  1138. ft.fe_decl <- Some f;
  1139. Array.iter (fun op ->
  1140. match op with
  1141. | OCall0 (_,fid)
  1142. | OCall1 (_,fid,_)
  1143. | OCall2 (_,fid,_,_)
  1144. | OCall3 (_,fid,_,_,_)
  1145. | OCall4 (_,fid,_,_,_,_)
  1146. | OCallN (_,fid,_)
  1147. | OStaticClosure (_,fid)
  1148. | OInstanceClosure (_,fid,_) ->
  1149. let ft2 = ftable.(fid) in
  1150. if not (List.memq ft ft2.fe_called_by) then begin
  1151. ft2.fe_called_by <- ft :: ft2.fe_called_by;
  1152. ft.fe_calling <- ft2 :: ft.fe_calling;
  1153. end;
  1154. | _ ->
  1155. ()
  1156. ) f.code;
  1157. ) code.functions;
  1158. ftable
  1159. let make_modules ctx all_types =
  1160. let modules = Hashtbl.create 0 in
  1161. let all_modules = ref [] in
  1162. let get_module name =
  1163. try
  1164. Hashtbl.find modules name
  1165. with Not_found ->
  1166. let m = {
  1167. m_name = name;
  1168. m_functions = [];
  1169. m_types = [];
  1170. } in
  1171. Hashtbl.add modules name m;
  1172. all_modules := m :: !all_modules;
  1173. m
  1174. in
  1175. let add m fid =
  1176. let f = ctx.ftable.(fid) in
  1177. if f.fe_module <> None then Globals.die "" __LOC__;
  1178. f.fe_module <- Some m;
  1179. m.m_functions <- f :: m.m_functions;
  1180. in
  1181. let add_type m t =
  1182. m.m_types <- t :: m.m_types;
  1183. ctx.type_module <- PMap.add t m ctx.type_module;
  1184. in
  1185. let mk_name path =
  1186. let base_name, path = match List.rev (ExtString.String.nsplit path ".") with
  1187. | [] -> "enums", ["hl"]
  1188. | name :: acc -> (if name.[0] = '$' then String.sub name 1 (String.length name - 1) else name), List.rev acc
  1189. in
  1190. let path = path @ [base_name] in
  1191. let path = List.map (fun n -> if String.length n > 128 then Digest.to_hex (Digest.string n) else n) path in
  1192. let path = (match path with [name] -> ["_std";name] | _ -> path) in
  1193. String.concat "/" path
  1194. in
  1195. let all_contexts = ref [] in
  1196. Array.iter (fun t ->
  1197. match t with
  1198. | HObj o | HStruct o ->
  1199. let m = get_module (mk_name o.pname) in
  1200. Array.iter (fun p -> add m p.fmethod) o.pproto;
  1201. List.iter (fun (_,mid) -> add m mid) o.pbindings;
  1202. add_type m t
  1203. | HEnum e when e.ename = "" ->
  1204. all_contexts := t :: !all_contexts
  1205. | HEnum e ->
  1206. let m = get_module (mk_name e.ename) in
  1207. add_type m t
  1208. | _ ->
  1209. ()
  1210. ) all_types;
  1211. let ep = ctx.hlcode.entrypoint in
  1212. if ep >= 0 then begin
  1213. let m = get_module "hl/init" in
  1214. add m ep;
  1215. ctx.ftable.(ep).fe_name <- "fun$init";
  1216. end;
  1217. List.iter (fun m ->
  1218. let rec get_deps acc = function
  1219. | [] -> acc
  1220. | fm :: fl ->
  1221. let counter = ref 1 in
  1222. let rec loop acc = function
  1223. | [] -> acc
  1224. | f :: l when f.fe_module = None && List.length f.fe_called_by = 1 && f.fe_decl <> None ->
  1225. f.fe_name <- fm.fe_name ^ "__$" ^ (string_of_int !counter);
  1226. incr counter;
  1227. f.fe_module <- Some m;
  1228. loop (append f acc) l
  1229. | _ :: l ->
  1230. loop acc l
  1231. and append f acc =
  1232. loop (f :: acc) (List.rev f.fe_calling)
  1233. in
  1234. get_deps (append fm acc) fl
  1235. in
  1236. m.m_functions <- get_deps [] m.m_functions
  1237. ) !all_modules;
  1238. let contexts = ref PMap.empty in
  1239. Array.iter (fun f ->
  1240. if f.fe_module = None && ExtString.String.starts_with f.fe_name "fun$" then f.fe_name <- "wrap" ^ type_name ctx (match f.fe_decl with None -> Globals.die "" __LOC__ | Some f -> f.ftype);
  1241. (* assign context to function module *)
  1242. match f.fe_args with
  1243. | (HEnum e) as t :: _ when e.ename = "" ->
  1244. (try
  1245. let r = PMap.find t !contexts in
  1246. (match r with
  1247. | None -> ()
  1248. | Some m when (match f.fe_module with Some m2 -> m == m2 | _ -> false) -> ()
  1249. | _ -> contexts := PMap.add t None !contexts) (* multiple contexts *)
  1250. with Not_found ->
  1251. contexts := PMap.add t f.fe_module !contexts)
  1252. | _ -> ()
  1253. ) ctx.ftable;
  1254. List.iter (fun t ->
  1255. let m = (try PMap.find t !contexts with Not_found -> None) in
  1256. let m = (match m with
  1257. | None ->
  1258. let tname = PMap.find t ctx.htypes in
  1259. get_module ("hl/ctx/" ^ String.sub tname 8 (String.length tname - 8))
  1260. | Some m ->
  1261. m
  1262. ) in
  1263. add_type m t
  1264. ) (List.rev !all_contexts);
  1265. !all_modules
  1266. let generate_module_types ctx m =
  1267. let def_name = "INC_" ^ String.concat "__" (ExtString.String.nsplit m.m_name "/") in
  1268. let line = line ctx and expr = expr ctx and sexpr fmt = Printf.ksprintf (expr ctx) fmt in
  1269. let type_name t =
  1270. match t with
  1271. | HObj o | HStruct o -> o.pname
  1272. | HEnum e -> e.ename
  1273. | _ -> ""
  1274. in
  1275. let types = List.sort (fun t1 t2 -> compare (type_name t1) (type_name t2)) m.m_types in
  1276. define ctx (sprintf "#ifndef %s" def_name);
  1277. define ctx (sprintf "#define %s" def_name);
  1278. List.iter (fun t ->
  1279. match t with
  1280. | HObj o | HStruct o ->
  1281. let name = tname o.pname in
  1282. ctx.defined_types <- PMap.add t () ctx.defined_types;
  1283. define ctx (sprintf "typedef struct _%s *%s;" name name);
  1284. | _ -> ()
  1285. ) types;
  1286. line "";
  1287. List.iter (fun t ->
  1288. match t with
  1289. | HObj op | HStruct op ->
  1290. let name = tname op.pname in
  1291. line ("struct _" ^ name ^ " {");
  1292. block ctx;
  1293. let rec loop o =
  1294. (match o.psuper with
  1295. | None ->
  1296. if not (is_struct t) then expr ("hl_type *$type");
  1297. | Some c ->
  1298. define_type ctx (if is_struct t then HStruct c else HObj c);
  1299. loop c);
  1300. Array.iteri (fun i (n,_,t) ->
  1301. let rec abs_index p v =
  1302. match p with
  1303. | None -> v
  1304. | Some o -> abs_index o.psuper (Array.length o.pfields + v)
  1305. in
  1306. define_type ctx t;
  1307. expr (var_type (if n = "" then unamed_field (abs_index o.psuper i) else n) t)
  1308. ) o.pfields;
  1309. in
  1310. loop op;
  1311. unblock ctx;
  1312. expr "}";
  1313. | HEnum e ->
  1314. Array.iteri (fun i (_,_,pl) ->
  1315. if Array.length pl <> 0 then begin
  1316. line ("typedef struct {");
  1317. block ctx;
  1318. line "HL__ENUM_CONSTRUCT__";
  1319. Array.iteri (fun i t ->
  1320. define_type ctx t;
  1321. expr (var_type ("p" ^ string_of_int i) t)
  1322. ) pl;
  1323. unblock ctx;
  1324. sexpr "} %s" (enum_constr_type ctx e i);
  1325. end;
  1326. ) e.efields
  1327. | _ ->
  1328. ()
  1329. ) types;
  1330. line "#endif";
  1331. line ""
  1332. let write_c com file (code:code) gnames =
  1333. let all_types, htypes = gather_types code in
  1334. let types_ids = make_types_idents htypes in
  1335. let gnames = make_global_names code gnames in
  1336. let bnames = Array.map (fun b -> "bytes$" ^ short_digest (Digest.to_hex (Digest.bytes b))) code.bytes in
  1337. let ctx = {
  1338. version = com.Common.version;
  1339. out = Buffer.create 1024;
  1340. tabs = "";
  1341. hlcode = code;
  1342. hash_cache = Hashtbl.create 0;
  1343. hash_mem = Hashtbl.create 0;
  1344. hash_cache_list = [];
  1345. dir = (match Filename.dirname file with "" -> "." | dir -> String.concat "/" (ExtString.String.nsplit dir "\\"));
  1346. curfile = "";
  1347. cfiles = [];
  1348. ftable = make_function_table code;
  1349. htypes = types_ids;
  1350. gnames = gnames;
  1351. bytes_names = bnames;
  1352. defines = [];
  1353. hdefines = Hashtbl.create 0;
  1354. defined_funs = Hashtbl.create 0;
  1355. defined_types = PMap.empty;
  1356. file_prefix = "";
  1357. fun_index = 0;
  1358. type_module = PMap.empty;
  1359. } in
  1360. let modules = make_modules ctx all_types in
  1361. let line = line ctx and expr = expr ctx in
  1362. let sline fmt = Printf.ksprintf line fmt and sexpr fmt = Printf.ksprintf expr fmt in
  1363. open_file ctx "hl/natives.h";
  1364. define ctx "#ifndef HL_NATIVES_H";
  1365. define ctx "#define HL_NATIVES_H";
  1366. define ctx "// Abstract decls";
  1367. let rec get_abstracts = function
  1368. | [] -> []
  1369. | HAbstract (name,_) :: l -> name :: get_abstracts l
  1370. | _ :: l -> get_abstracts l
  1371. in
  1372. let abstracts = List.sort compare (get_abstracts (Array.to_list all_types)) in
  1373. List.iter (fun name -> define ctx (sprintf "typedef struct _%s %s;" name name)) abstracts;
  1374. define ctx "";
  1375. line "// Natives functions";
  1376. let native_libs = Hashtbl.create 0 in
  1377. let sorted_natives = Array.copy code.natives in
  1378. Array.sort (fun n1 n2 -> let mk (lib,name,_,_) = code.strings.(lib), code.strings.(name) in compare (mk n1) (mk n2)) sorted_natives;
  1379. Array.iter (fun (lib,_,_,idx) ->
  1380. Hashtbl.replace native_libs code.strings.(lib) ();
  1381. let ft = ctx.ftable.(idx) in
  1382. define_type ctx (HFun (ft.fe_args,ft.fe_ret));
  1383. sexpr "HL_API %s %s(%s)" (ctype ft.fe_ret) ft.fe_name (args_repr ft.fe_args);
  1384. ) sorted_natives;
  1385. line "#endif";
  1386. line "";
  1387. open_file ctx "hl/globals.c";
  1388. define ctx "#define HLC_BOOT";
  1389. define ctx "#include <hlc.h>";
  1390. line "// Globals";
  1391. Array.iteri (fun i t ->
  1392. let name = gnames.(i) in
  1393. define_type ctx t;
  1394. sexpr "%s = 0" (var_type name t)
  1395. ) code.globals;
  1396. Array.iter (fun (g,fields) ->
  1397. let t = code.globals.(g) in
  1398. let name = "const_" ^ gnames.(g) in
  1399. let field_value t idx =
  1400. match t with
  1401. | HI32 ->
  1402. Int32.to_string code.ints.(idx)
  1403. | HBytes ->
  1404. "(vbyte*)" ^ string ctx idx
  1405. | _ ->
  1406. Globals.die "" __LOC__
  1407. in
  1408. let fields = match t with
  1409. | HObj o | HStruct o ->
  1410. let fields = List.map2 field_value (List.map (fun (_,_,t) -> t) (Array.to_list o.pfields)) (Array.to_list fields) in
  1411. if is_struct t then fields else type_value ctx t :: fields
  1412. | _ ->
  1413. Globals.die "" __LOC__
  1414. in
  1415. sexpr "static struct _%s %s = {%s}" (ctype t) name (String.concat "," fields);
  1416. ) code.constants;
  1417. line "";
  1418. line "void hl_init_roots() {";
  1419. block ctx;
  1420. let is_const = Hashtbl.create 0 in
  1421. Array.iter (fun (g,fields) ->
  1422. sexpr "%s = &const_%s" gnames.(g) gnames.(g);
  1423. Hashtbl.add is_const g true;
  1424. ) code.constants;
  1425. Array.iteri (fun i t ->
  1426. if is_ptr t && not (Hashtbl.mem is_const i) then sexpr "hl_add_root((void**)&%s)" gnames.(i);
  1427. ) code.globals;
  1428. unblock ctx;
  1429. line "}";
  1430. let output_bytes f str =
  1431. for i = 0 to String.length str - 1 do
  1432. if (i+1) mod 0x80 = 0 then f "\\\n\t";
  1433. if i > 0 then f ",";
  1434. f (string_of_int (int_of_char str.[i]));
  1435. done
  1436. in
  1437. Array.iteri (fun i str ->
  1438. if String.length str >= string_data_limit then begin
  1439. let s = Common.utf8_to_utf16 str true in
  1440. sline "// %s..." (String.escaped (String.sub str 0 (string_data_limit-4)));
  1441. output ctx (Printf.sprintf "vbyte string$%s[] = {" (short_digest str));
  1442. output_bytes (output ctx) s;
  1443. sexpr "}";
  1444. end
  1445. ) code.strings;
  1446. Array.iteri (fun i bytes ->
  1447. if Bytes.length bytes > 1000 then begin
  1448. let bytes_file = "hl/bytes_" ^ (Digest.to_hex (Digest.bytes bytes)) ^ ".h" in
  1449. let abs_file = ctx.dir ^ "/" ^ bytes_file in
  1450. if not (Sys.file_exists abs_file) then begin
  1451. let ch = open_out_bin abs_file in
  1452. output_bytes (output_string ch) (Bytes.to_string bytes);
  1453. close_out ch;
  1454. end;
  1455. sline "vbyte %s[] = {" ctx.bytes_names.(i);
  1456. output ctx (Printf.sprintf "#%s include \"%s\"\n" ctx.tabs bytes_file);
  1457. sexpr "}";
  1458. end else begin
  1459. output ctx (Printf.sprintf "vbyte %s[] = {" ctx.bytes_names.(i));
  1460. output_bytes (output ctx) (Bytes.to_string bytes);
  1461. sexpr "}";
  1462. end
  1463. ) code.bytes;
  1464. let type_value ctx t = "&" ^ type_name ctx t in (* no auto import *)
  1465. open_file ctx "hl/types.c";
  1466. define ctx "#define HLC_BOOT";
  1467. define ctx "#include <hlc.h>";
  1468. line "// Types values";
  1469. Array.iteri (fun i t ->
  1470. match t with
  1471. | HMethod _ | HFun _ | HVirtual _ ->
  1472. sexpr "hl_type %s = { %s } /* %s */" (type_name ctx t) (type_id t) (tstr t);
  1473. | _ ->
  1474. sexpr "hl_type %s = { %s }" (type_name ctx t) (type_id t);
  1475. ) all_types;
  1476. line "";
  1477. line "// Types values data";
  1478. Array.iter (fun t ->
  1479. let field_value (_,name_id,t) =
  1480. sprintf "{(const uchar*)%s, %s, %ld}" (string ctx name_id) (type_value ctx t) (hash ctx name_id)
  1481. in
  1482. match t with
  1483. | HObj o | HStruct o ->
  1484. let name = type_name ctx t in
  1485. let proto_value p =
  1486. sprintf "{(const uchar*)%s, %d, %d, %ld}" (string ctx p.fid) p.fmethod (match p.fvirtual with None -> -1 | Some i -> i) (hash ctx p.fid)
  1487. in
  1488. let fields =
  1489. if Array.length o.pfields = 0 then "NULL" else
  1490. let name = sprintf "fields%s" name in
  1491. sexpr "static hl_obj_field %s[] = {%s}" name (String.concat "," (List.map field_value (Array.to_list o.pfields)));
  1492. name
  1493. in
  1494. let proto =
  1495. if Array.length o.pproto = 0 then "NULL" else
  1496. let name = sprintf "proto%s" name in
  1497. sexpr "static hl_obj_proto %s[] = {%s}" name (String.concat "," (List.map proto_value (Array.to_list o.pproto)));
  1498. name
  1499. in
  1500. let bindings =
  1501. if o.pbindings = [] then "NULL" else
  1502. let name = sprintf "bindings%s" name in
  1503. sexpr "static int %s[] = {%s}" name (String.concat "," (List.map (fun (fid,fidx) -> string_of_int fid ^ "," ^ string_of_int fidx) o.pbindings));
  1504. name
  1505. in
  1506. let ofields = [
  1507. string_of_int (Array.length o.pfields);
  1508. string_of_int (Array.length o.pproto);
  1509. string_of_int (List.length o.pbindings);
  1510. sprintf "(const uchar*)%s" (string ctx o.pid);
  1511. (match o.psuper with None -> "NULL" | Some c -> type_value ctx (HObj c));
  1512. fields;
  1513. proto;
  1514. bindings
  1515. ] in
  1516. sexpr "static hl_type_obj obj%s = {%s}" name (String.concat "," ofields);
  1517. | HEnum e ->
  1518. let ename = type_name ctx t in
  1519. let constr_value cid (name,nid,tl) =
  1520. let tval = if Array.length tl = 0 then "NULL" else
  1521. let name = sprintf "econstruct%s_%d" ename cid in
  1522. sexpr "static hl_type *%s[] = {%s}" name (String.concat "," (List.map (type_value ctx) (Array.to_list tl)));
  1523. name
  1524. in
  1525. let size = if Array.length tl = 0 then "0" else sprintf "sizeof(%s)" (enum_constr_type ctx e cid) in
  1526. let offsets = if Array.length tl = 0 then "NULL" else
  1527. let name = sprintf "eoffsets%s_%d" ename cid in
  1528. sexpr "static int %s[] = {%s}" name (String.concat "," (List.map (fun _ -> "0") (Array.to_list tl)));
  1529. name
  1530. in
  1531. let has_ptr = List.exists is_gc_ptr (Array.to_list tl) in
  1532. sprintf "{(const uchar*)%s, %d, %s, %s, %s, %s}" (string ctx nid) (Array.length tl) tval size (if has_ptr then "true" else "false") offsets
  1533. in
  1534. let constr_name = if Array.length e.efields = 0 then "NULL" else begin
  1535. let name = sprintf "econstruct%s" ename in
  1536. sexpr "static hl_enum_construct %s[] = {%s}" name (String.concat "," (Array.to_list (Array.mapi constr_value e.efields)));
  1537. name;
  1538. end in
  1539. let efields = [
  1540. if e.eid = 0 then "NULL" else sprintf "(const uchar*)%s" (string ctx e.eid);
  1541. string_of_int (Array.length e.efields);
  1542. constr_name
  1543. ] in
  1544. sexpr "static hl_type_enum enum%s = {%s}" ename (String.concat "," efields);
  1545. | HVirtual v ->
  1546. let vname = type_name ctx t in
  1547. let fields_name =
  1548. if Array.length v.vfields = 0 then "NULL" else
  1549. let name = sprintf "vfields%s" vname in
  1550. sexpr "static hl_obj_field %s[] = {%s}" name (String.concat "," (List.map field_value (Array.to_list v.vfields)));
  1551. name
  1552. in
  1553. let vfields = [
  1554. fields_name;
  1555. string_of_int (Array.length v.vfields)
  1556. ] in
  1557. sexpr "static hl_type_virtual virt%s = {%s}" vname (String.concat "," vfields);
  1558. | HFun (args,ret) | HMethod(args,ret) ->
  1559. let fname = type_name ctx t in
  1560. let aname = if args = [] then "NULL" else
  1561. let name = sprintf "fargs%s" fname in
  1562. sexpr "static hl_type *%s[] = {%s}" name (String.concat "," (List.map (type_value ctx) args));
  1563. name
  1564. in
  1565. sexpr "static hl_type_fun tfun%s = {%s,%s,%d}" fname aname (type_value ctx ret) (List.length args)
  1566. | _ ->
  1567. ()
  1568. ) all_types;
  1569. line "";
  1570. line "void hl_init_types( hl_module_context *ctx ) {";
  1571. block ctx;
  1572. Array.iter (fun t ->
  1573. match t with
  1574. | HObj o | HStruct o ->
  1575. let name = type_name ctx t in
  1576. sexpr "obj%s.m = ctx" name;
  1577. (match o.pclassglobal with
  1578. | None -> ()
  1579. | Some g ->
  1580. define_global ctx g;
  1581. sexpr "obj%s.global_value = (void**)&%s" name gnames.(g));
  1582. sexpr "%s.obj = &obj%s" name name
  1583. | HNull r | HRef r ->
  1584. sexpr "%s.tparam = %s" (type_name ctx t) (type_value ctx r)
  1585. | HEnum e ->
  1586. let name = type_name ctx t in
  1587. sexpr "%s.tenum = &enum%s" name name;
  1588. (match e.eglobal with
  1589. | None -> ()
  1590. | Some g ->
  1591. define_global ctx g;
  1592. sexpr "enum%s.global_value = (void**)&%s" name gnames.(g));
  1593. sexpr "hl_init_enum(&%s,ctx)" name;
  1594. | HVirtual _ ->
  1595. let name = type_name ctx t in
  1596. sexpr "%s.virt = &virt%s" name name;
  1597. sexpr "hl_init_virtual(&%s,ctx)" name;
  1598. | HFun _ | HMethod _ ->
  1599. let name = type_name ctx t in
  1600. sexpr "%s.fun = &tfun%s" name name
  1601. | _ ->
  1602. ()
  1603. ) all_types;
  1604. unblock ctx;
  1605. line "}";
  1606. open_file ctx "hl/reflect.c";
  1607. define ctx "#define HLC_BOOT";
  1608. define ctx "#include <hlc.h>";
  1609. line "// Reflection helpers";
  1610. generate_reflection ctx;
  1611. List.iter (fun m ->
  1612. let defined_types = ref PMap.empty in
  1613. if m.m_types <> [] then begin
  1614. open_file ctx (m.m_name ^ ".h");
  1615. generate_module_types ctx m;
  1616. defined_types := ctx.defined_types;
  1617. end;
  1618. if m.m_functions <> [] then begin
  1619. open_file ctx (m.m_name ^ ".c");
  1620. ctx.defined_types <- !defined_types;
  1621. define ctx "#define HLC_BOOT";
  1622. define ctx "#include <hlc.h>";
  1623. if m.m_types <> [] then define ctx (sprintf "#include <%s.h>" m.m_name);
  1624. let file_pos f =
  1625. match f.fe_decl with
  1626. | Some f when Array.length f.debug > 0 ->
  1627. let fid, p = f.debug.(Array.length f.debug - 1) in
  1628. (code.strings.(fid), p)
  1629. | _ ->
  1630. ("",0)
  1631. in
  1632. let funcs = List.sort (fun f1 f2 -> compare (file_pos f1) (file_pos f2)) m.m_functions in
  1633. List.iter (fun fe -> match fe.fe_decl with None -> () | Some f -> generate_function ctx f) funcs;
  1634. end;
  1635. ) modules;
  1636. open_file ctx "hl/functions.c";
  1637. define ctx "#define HLC_BOOT";
  1638. define ctx "#include <hlc.h>";
  1639. sexpr "void *hl_functions_ptrs[] = {%s}" (String.concat "," (List.map (fun f -> define_function ctx f.fe_index) (Array.to_list ctx.ftable)));
  1640. let rec loop i =
  1641. if i = Array.length ctx.ftable then [] else
  1642. let ft = ctx.ftable.(i) in
  1643. let n = type_name ctx (HFun (ft.fe_args,ft.fe_ret)) in
  1644. define ctx (sprintf "extern hl_type %s;" n);
  1645. ("&" ^ n) :: loop (i + 1)
  1646. in
  1647. sexpr "hl_type *hl_functions_types[] = {%s}" (String.concat "," (loop 0));
  1648. line "";
  1649. Array.iter (fun f ->
  1650. if f.fe_module = None then (match f.fe_decl with None -> () | Some f -> generate_function ctx f);
  1651. ) ctx.ftable;
  1652. open_file ctx "hl/hashes.c";
  1653. define ctx "#define HLC_BOOT";
  1654. define ctx "#include <hlc.h>";
  1655. line "";
  1656. line "void hl_init_hashes() {";
  1657. block ctx;
  1658. List.iter (fun i -> sexpr "hl_hash((vbyte*)%s)" (string ctx i)) (List.rev ctx.hash_cache_list);
  1659. unblock ctx;
  1660. line "}";
  1661. open_file ctx (Filename.basename file);
  1662. define ctx "#define HLC_BOOT";
  1663. define ctx "#include <hlc.h>";
  1664. line "#include <hlc_main.c>";
  1665. line "";
  1666. line "#ifndef HL_MAKE";
  1667. List.iter (sline "# include <%s>") ctx.cfiles;
  1668. line "#endif";
  1669. line "";
  1670. expr "void hl_init_hashes()";
  1671. expr "void hl_init_roots()";
  1672. expr "void hl_init_types( hl_module_context *ctx )";
  1673. expr "extern void *hl_functions_ptrs[]";
  1674. expr "extern hl_type *hl_functions_types[]";
  1675. line "";
  1676. line "// Entry point";
  1677. line "void hl_entry_point() {";
  1678. block ctx;
  1679. expr "hl_module_context ctx";
  1680. expr "hl_alloc_init(&ctx.alloc)";
  1681. expr "ctx.functions_ptrs = hl_functions_ptrs";
  1682. expr "ctx.functions_types = hl_functions_types";
  1683. expr "hl_init_types(&ctx)";
  1684. expr "hl_init_hashes()";
  1685. expr "hl_init_roots()";
  1686. if code.entrypoint >= 0 then sexpr "%s()" (define_function ctx code.entrypoint);
  1687. unblock ctx;
  1688. line "}";
  1689. line "";
  1690. open_file ctx "hlc.json";
  1691. line "{";
  1692. block ctx;
  1693. sline "\"version\" : %d," ctx.version;
  1694. sline "\"libs\" : [%s]," (String.concat "," (Hashtbl.fold (fun k _ acc -> sprintf "\"%s\"" k :: acc) native_libs []));
  1695. sline "\"defines\" : {%s\n\t}," (String.concat "," (PMap.foldi (fun k v acc -> sprintf "\n\t\t\"%s\" : \"%s\"" (String.escaped k) (String.escaped v) :: acc) com.Common.defines.Define.values []));
  1696. sline "\"files\" : [%s\n\t]" (String.concat "," (List.map (sprintf "\n\t\t\"%s\"") ctx.cfiles));
  1697. unblock ctx;
  1698. line "}";
  1699. close_file ctx