ncompile.ml 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055
  1. (*
  2. * Neko Compiler
  3. * Copyright (c)2005 Motion-Twin
  4. *
  5. * This library is free software; you can redistribute it and/or
  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, or (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 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Lesser General Public License or the LICENSE file for more details.
  14. *)
  15. open Nast
  16. open Nbytecode
  17. type access =
  18. | XEnv of int
  19. | XStack of int
  20. | XGlobal of int
  21. | XField of string
  22. | XIndex of int
  23. | XArray
  24. | XThis
  25. type label = {
  26. lname : string;
  27. ltraps : int list;
  28. lstack : int;
  29. mutable lpos : int option;
  30. mutable lwait : (unit -> unit) list;
  31. }
  32. type globals = {
  33. globals : (global,int) Hashtbl.t;
  34. gobjects : (string list,int) Hashtbl.t;
  35. mutable functions : (opcode DynArray.t * (int * int) DynArray.t * int * int) list;
  36. mutable gtable : global DynArray.t;
  37. labels : (string,label) Hashtbl.t;
  38. hfiles : (string,int) Hashtbl.t;
  39. files : string DynArray.t;
  40. }
  41. type context = {
  42. g : globals;
  43. version : int;
  44. mutable ops : opcode DynArray.t;
  45. mutable locals : (string,int) PMap.t;
  46. mutable env : (string,int) PMap.t;
  47. mutable nenv : int;
  48. mutable stack : int;
  49. mutable loop_limit : int;
  50. mutable loop_traps : int;
  51. mutable limit : int;
  52. mutable traps : int list;
  53. mutable breaks : ((unit -> unit) * pos) list;
  54. mutable continues : ((unit -> unit) * pos) list;
  55. mutable pos : (int * int) DynArray.t;
  56. mutable curpos : (int * int);
  57. mutable curfile : string;
  58. }
  59. type error_msg = string
  60. exception Error of error_msg * pos
  61. let error e p =
  62. raise (Error(e,p))
  63. let error_msg s =
  64. s
  65. let stack_delta o =
  66. match o with
  67. | AccNull
  68. | AccTrue
  69. | AccFalse
  70. | AccThis
  71. | AccInt _
  72. | AccInt32 _
  73. | AccStack _
  74. | AccGlobal _
  75. | AccEnv _
  76. | AccField _
  77. | AccBuiltin _
  78. | AccIndex _
  79. | JumpIf _
  80. | JumpIfNot _
  81. | Jump _
  82. | JumpTable _
  83. | Ret _
  84. | SetGlobal _
  85. | SetStack _
  86. | SetEnv _
  87. | SetThis
  88. | Bool
  89. | IsNull
  90. | IsNotNull
  91. | Not
  92. | Hash
  93. | TypeOf
  94. | New
  95. | AccStack0
  96. | AccStack1
  97. | AccIndex0
  98. | AccIndex1
  99. | Loop
  100. -> 0
  101. | Add
  102. | Sub
  103. | Mult
  104. | Div
  105. | Mod
  106. | Shl
  107. | Shr
  108. | UShr
  109. | Or
  110. | And
  111. | Xor
  112. | Eq
  113. | Neq
  114. | Gt
  115. | Gte
  116. | Lt
  117. | Lte
  118. | PhysCompare
  119. -> -1
  120. | AccArray -> -1
  121. | SetField _ | SetIndex _ | Compare -> -1
  122. | SetArray -> -2
  123. | Push -> 1
  124. | Pop x -> -x
  125. | Apply nargs | Call nargs | TailCall (nargs,_) -> -nargs
  126. | ObjCall nargs -> -(nargs + 1)
  127. | MakeEnv size | MakeArray size -> -size
  128. | Trap _ -> trap_stack_delta
  129. | EndTrap -> -trap_stack_delta
  130. let check_stack ctx stack p =
  131. if ctx.stack <> stack then error "Stack alignment failure" p
  132. let pos ctx =
  133. DynArray.length ctx.ops
  134. let real_null_pos =
  135. { pline = 0; psource = "<null>" }
  136. let set_pos ctx p =
  137. if p.psource = ctx.curfile then begin
  138. if p.pline <> snd ctx.curpos then ctx.curpos <- (fst ctx.curpos, p.pline);
  139. end else if p = real_null_pos then
  140. ()
  141. else
  142. let fid = (try
  143. Hashtbl.find ctx.g.hfiles p.psource
  144. with Not_found ->
  145. let fid = DynArray.length ctx.g.files in
  146. DynArray.add ctx.g.files p.psource;
  147. Hashtbl.add ctx.g.hfiles p.psource fid;
  148. fid
  149. ) in
  150. ctx.curfile <- p.psource;
  151. ctx.curpos <- (fid,p.pline)
  152. let write ctx op =
  153. ctx.stack <- ctx.stack + stack_delta op;
  154. DynArray.add ctx.pos ctx.curpos;
  155. if op_param op then DynArray.add ctx.pos ctx.curpos;
  156. DynArray.add ctx.ops op
  157. let jmp ctx =
  158. let p = pos ctx in
  159. write ctx (Jump 0);
  160. (fun() -> DynArray.set ctx.ops p (Jump(pos ctx - p)))
  161. let cjmp cond ctx =
  162. let p = pos ctx in
  163. write ctx (Jump 0);
  164. (fun() -> DynArray.set ctx.ops p (if cond then JumpIf(pos ctx - p) else JumpIfNot(pos ctx - p)))
  165. let trap ctx =
  166. let p = pos ctx in
  167. write ctx (Trap 0);
  168. (fun() -> DynArray.set ctx.ops p (Trap(pos ctx - p)))
  169. let goto ctx p =
  170. write ctx (Jump(p - pos ctx))
  171. let global ctx g =
  172. let ginf = ctx.g in
  173. try
  174. Hashtbl.find ginf.globals g
  175. with Not_found ->
  176. let gid = DynArray.length ginf.gtable in
  177. Hashtbl.add ginf.globals g gid;
  178. DynArray.add ginf.gtable g;
  179. gid
  180. let save_breaks ctx =
  181. let oldc = ctx.continues in
  182. let oldb = ctx.breaks in
  183. let oldl = ctx.loop_limit in
  184. let oldt = ctx.loop_traps in
  185. ctx.loop_traps <- List.length ctx.traps;
  186. ctx.loop_limit <- ctx.stack;
  187. ctx.breaks <- [];
  188. ctx.continues <- [];
  189. (ctx , oldc, oldb , oldl, oldt)
  190. let process_continues (ctx,oldc,_,_,_) =
  191. List.iter (fun (f,_) -> f()) ctx.continues;
  192. ctx.continues <- oldc
  193. let process_breaks (ctx,_,oldb,oldl, oldt) =
  194. List.iter (fun (f,_) -> f()) ctx.breaks;
  195. ctx.loop_limit <- oldl;
  196. ctx.loop_traps <- oldt;
  197. ctx.breaks <- oldb
  198. let check_breaks ctx =
  199. List.iter (fun (_,p) -> error "Break outside a loop" p) ctx.breaks;
  200. List.iter (fun (_,p) -> error "Continue outside a loop" p) ctx.continues
  201. let make_array p el =
  202. (ECall ((EConst (Builtin "array"),p),el), p)
  203. let get_cases_ints(cases) =
  204. let max = ref (-1) in
  205. let l = List.map (fun (e,e2) ->
  206. match e with
  207. | (EConst (Int n),_) when n >= 0 ->
  208. if n > !max then max := n;
  209. (n,e2)
  210. | _ -> raise Exit
  211. ) cases in
  212. (* // only create jump table if small or >10% cases matched *)
  213. let nmatches = List.length l in
  214. if nmatches < 3 then raise Exit;
  215. if !max >= 16 && (nmatches * 100) / (!max + 1) < 10 then raise Exit;
  216. if !max > 512 then raise Exit;
  217. (l,!max + 1)
  218. let rec scan_labels ctx supported in_block e =
  219. match fst e with
  220. | EFunction (args,e) ->
  221. let nargs = List.length args in
  222. let traps = ctx.traps in
  223. ctx.traps <- [];
  224. ctx.stack <- ctx.stack + nargs;
  225. scan_labels ctx supported false e;
  226. ctx.stack <- ctx.stack - nargs;
  227. ctx.traps <- traps
  228. | EBlock _ ->
  229. let old = ctx.stack in
  230. Nast.iter (scan_labels ctx supported true) e;
  231. ctx.stack <- old
  232. | EVars l ->
  233. if not in_block then error "Variable declaration must be done inside a block" (snd e);
  234. List.iter (fun (_,e) ->
  235. (match e with
  236. | None -> ()
  237. | Some e -> scan_labels ctx supported false e);
  238. ctx.stack <- ctx.stack + 1
  239. ) l
  240. | ELabel l when not supported ->
  241. error "Label is not supported in this part of the program" (snd e);
  242. | ELabel l when Hashtbl.mem ctx.g.labels l ->
  243. error ("Duplicate label " ^ l) (snd e)
  244. | ELabel l ->
  245. let label = {
  246. lname = l;
  247. ltraps = List.rev ctx.traps;
  248. lstack = ctx.stack;
  249. lpos = None;
  250. lwait = [];
  251. } in
  252. Hashtbl.add ctx.g.labels l label
  253. | ETry (e,_,e2) ->
  254. ctx.stack <- ctx.stack + trap_stack_delta;
  255. ctx.traps <- ctx.stack :: ctx.traps;
  256. scan_labels ctx supported false e;
  257. ctx.stack <- ctx.stack - trap_stack_delta;
  258. ctx.traps <- (match ctx.traps with [] -> assert false | _ :: l -> l);
  259. ctx.stack <- ctx.stack + 1;
  260. scan_labels ctx supported false e2;
  261. ctx.stack <- ctx.stack - 1;
  262. | EBinop ("=",e1,e2) ->
  263. let rec is_extended (e,_) =
  264. match e with
  265. | EParenthesis e -> is_extended e
  266. | EArray _
  267. | EField _ ->
  268. true
  269. | _ ->
  270. false
  271. in
  272. let ext = is_extended e1 in
  273. if ext then ctx.stack <- ctx.stack + 1;
  274. scan_labels ctx supported false e2;
  275. ctx.stack <- ctx.stack + 1;
  276. scan_labels ctx supported false e1;
  277. ctx.stack <- ctx.stack - (if ext then 2 else 1);
  278. | ECall ((EConst (Builtin "array"),_),e :: el) ->
  279. if ctx.version >= 2 then begin
  280. scan_labels ctx supported false e;
  281. List.iter (fun e ->
  282. ctx.stack <- ctx.stack + 1;
  283. scan_labels ctx supported false e;
  284. ) el;
  285. ctx.stack <- ctx.stack - List.length el
  286. end else begin
  287. List.iter (fun e ->
  288. scan_labels ctx supported false e;
  289. ctx.stack <- ctx.stack + 1;
  290. ) el;
  291. scan_labels ctx supported false e;
  292. ctx.stack <- ctx.stack - List.length el
  293. end
  294. | ECall ((EConst (Builtin x),_),el) when x <> "apply" ->
  295. Nast.iter (scan_labels ctx false false) e
  296. | ECall ((EConst (Builtin "apply"),_),e :: el)
  297. | ECall(e,el) ->
  298. List.iter (fun e ->
  299. scan_labels ctx supported false e;
  300. ctx.stack <- ctx.stack + 1;
  301. ) el;
  302. scan_labels ctx supported false e;
  303. ctx.stack <- ctx.stack - List.length el
  304. | EObject fl ->
  305. ctx.stack <- ctx.stack + 2;
  306. List.iter (fun (s,e) ->
  307. scan_labels ctx supported false e
  308. ) fl;
  309. ctx.stack <- ctx.stack - 2;
  310. | ESwitch (ee,[(econd,exec)],eo) ->
  311. let p = snd e in
  312. scan_labels ctx supported false (EIf ((EBinop ("==",ee,econd),p),exec,eo),p)
  313. | ESwitch (e,cases,eo) ->
  314. scan_labels ctx supported false e;
  315. let delta = (try ignore(get_cases_ints cases); 0 with Exit -> 1) in
  316. ctx.stack <- ctx.stack + delta;
  317. List.iter (fun (e1,e2) ->
  318. ctx.stack <- ctx.stack + delta;
  319. scan_labels ctx supported false e1;
  320. ctx.stack <- ctx.stack - delta;
  321. scan_labels ctx supported false e2;
  322. ) cases;
  323. (match eo with
  324. | None -> ()
  325. | Some e -> scan_labels ctx supported false e);
  326. ctx.stack <- ctx.stack - delta;
  327. | ENext (e1,e2) ->
  328. scan_labels ctx supported in_block e1;
  329. scan_labels ctx supported in_block e2;
  330. | EConst _
  331. | EContinue
  332. | EBreak _
  333. | EReturn _
  334. | EIf _
  335. | EWhile _
  336. | EParenthesis _ ->
  337. Nast.iter (scan_labels ctx supported false) e
  338. | EBinop (_,_,_)
  339. | EArray _
  340. | EField _
  341. ->
  342. Nast.iter (scan_labels ctx false false) e
  343. | ENeko _ ->
  344. assert false
  345. let compile_constant ctx c p =
  346. match c with
  347. | True -> write ctx AccTrue
  348. | False -> write ctx AccFalse
  349. | Null -> write ctx AccNull
  350. | This -> write ctx AccThis
  351. | Int n -> write ctx (AccInt n)
  352. | Int32 n -> write ctx (AccInt32 n)
  353. | Float f -> write ctx (AccGlobal (global ctx (GlobalFloat f)))
  354. | String s -> write ctx (AccGlobal (global ctx (GlobalString s)))
  355. | Builtin s ->
  356. (match s with
  357. | "tnull" -> write ctx (AccInt 0)
  358. | "tint" -> write ctx (AccInt 1)
  359. | "tfloat" -> write ctx (AccInt 2)
  360. | "tbool" -> write ctx (AccInt 3)
  361. | "tstring" -> write ctx (AccInt 4)
  362. | "tobject" -> write ctx (AccInt 5)
  363. | "tarray" -> write ctx (AccInt 6)
  364. | "tfunction" -> write ctx (AccInt 7)
  365. | "tabstract" -> write ctx (AccInt 8)
  366. | s ->
  367. write ctx (AccBuiltin s))
  368. | Ident s ->
  369. try
  370. let l = PMap.find s ctx.locals in
  371. if l <= ctx.limit then
  372. let e = (try
  373. PMap.find s ctx.env
  374. with Not_found ->
  375. let e = ctx.nenv in
  376. ctx.nenv <- ctx.nenv + 1;
  377. ctx.env <- PMap.add s e ctx.env;
  378. e
  379. ) in
  380. write ctx (AccEnv e);
  381. else
  382. let p = ctx.stack - l in
  383. write ctx (if p = 0 then AccStack0 else if p = 1 then AccStack1 else AccStack p);
  384. with Not_found ->
  385. let g = global ctx (GlobalVar s) in
  386. write ctx (AccGlobal g)
  387. let rec compile_access ctx e =
  388. match fst e with
  389. | EConst (Ident s) ->
  390. (try
  391. let l = PMap.find s ctx.locals in
  392. if l <= ctx.limit then
  393. let e = (try
  394. PMap.find s ctx.env
  395. with Not_found ->
  396. let e = ctx.nenv in
  397. ctx.nenv <- ctx.nenv + 1;
  398. ctx.env <- PMap.add s e ctx.env;
  399. e
  400. ) in
  401. XEnv e
  402. else
  403. XStack l
  404. with Not_found ->
  405. let g = global ctx (GlobalVar s) in
  406. XGlobal g)
  407. | EField (e,f) ->
  408. compile ctx false e;
  409. write ctx Push;
  410. XField f
  411. | EArray (e1,(EConst (Int n),_)) ->
  412. compile ctx false e1;
  413. write ctx Push;
  414. XIndex n
  415. | EArray (ea,ei) ->
  416. compile ctx false ei;
  417. write ctx Push;
  418. compile ctx false ea;
  419. write ctx Push;
  420. XArray
  421. | EConst This ->
  422. XThis
  423. | _ ->
  424. error "Invalid access" (snd e)
  425. and compile_access_set ctx a =
  426. match a with
  427. | XEnv n -> write ctx (SetEnv n)
  428. | XStack l -> write ctx (SetStack (ctx.stack - l))
  429. | XGlobal g -> write ctx (SetGlobal g)
  430. | XField f -> write ctx (SetField f)
  431. | XIndex i -> write ctx (SetIndex i)
  432. | XThis -> write ctx SetThis
  433. | XArray -> write ctx SetArray
  434. and compile_access_get ctx a =
  435. match a with
  436. | XEnv n -> write ctx (AccEnv n)
  437. | XStack l -> write ctx (AccStack (ctx.stack - l))
  438. | XGlobal g -> write ctx (AccGlobal g)
  439. | XField f -> write ctx (AccField f)
  440. | XIndex i -> write ctx (AccIndex i)
  441. | XThis -> write ctx AccThis
  442. | XArray ->
  443. write ctx Push;
  444. write ctx (AccStack 2);
  445. write ctx AccArray
  446. and write_op ctx op p =
  447. match op with
  448. | "+" -> write ctx Add
  449. | "-" -> write ctx Sub
  450. | "/" -> write ctx Div
  451. | "*" -> write ctx Mult
  452. | "%" -> write ctx Mod
  453. | "<<" -> write ctx Shl
  454. | ">>" -> write ctx Shr
  455. | ">>>" -> write ctx UShr
  456. | "|" -> write ctx Or
  457. | "&" -> write ctx And
  458. | "^" -> write ctx Xor
  459. | "==" -> write ctx Eq
  460. | "!=" -> write ctx Neq
  461. | ">" -> write ctx Gt
  462. | ">=" -> write ctx Gte
  463. | "<" -> write ctx Lt
  464. | "<=" -> write ctx Lte
  465. | _ -> error "Unknown operation" p
  466. and compile_binop ctx tail op e1 e2 p =
  467. match op with
  468. | "=" ->
  469. let a = compile_access ctx e1 in
  470. compile ctx false e2;
  471. compile_access_set ctx a
  472. | "&&" ->
  473. compile ctx false e1;
  474. let jnext = cjmp false ctx in
  475. compile ctx tail e2;
  476. jnext()
  477. | "||" ->
  478. compile ctx false e1;
  479. let jnext = cjmp true ctx in
  480. compile ctx tail e2;
  481. jnext()
  482. | "++="
  483. | "--=" ->
  484. write ctx Push;
  485. let base = ctx.stack in
  486. let a = compile_access ctx e1 in
  487. compile_access_get ctx a;
  488. write ctx (SetStack(ctx.stack - base));
  489. write ctx Push;
  490. compile ctx false e2;
  491. write_op ctx (String.sub op 0 (String.length op - 2)) p;
  492. compile_access_set ctx a;
  493. write ctx (AccStack 0);
  494. write ctx (Pop 1);
  495. | "+="
  496. | "-="
  497. | "/="
  498. | "*="
  499. | "%="
  500. | "<<="
  501. | ">>="
  502. | ">>>="
  503. | "|="
  504. | "&="
  505. | "^=" ->
  506. let a = compile_access ctx e1 in
  507. compile_access_get ctx a;
  508. write ctx Push;
  509. compile ctx false e2;
  510. write_op ctx (String.sub op 0 (String.length op - 1)) p;
  511. compile_access_set ctx a
  512. | _ ->
  513. match (op , e1 , e2) with
  514. | ("==" , _ , (EConst Null,_)) ->
  515. compile ctx false e1;
  516. write ctx IsNull
  517. | ("!=" , _ , (EConst Null,_)) ->
  518. compile ctx false e1;
  519. write ctx IsNotNull
  520. | ("==" , (EConst Null,_) , _) ->
  521. compile ctx false e2;
  522. write ctx IsNull
  523. | ("!=" , (EConst Null,_) , _) ->
  524. compile ctx false e2;
  525. write ctx IsNotNull
  526. | ("-", (EConst (Int 0),_) , (EConst (Int i),_)) ->
  527. compile ctx tail (EConst (Int (-i)),p)
  528. | _ ->
  529. compile ctx false e1;
  530. write ctx Push;
  531. compile ctx false e2;
  532. write_op ctx op p
  533. and compile_function main params e =
  534. let ctx = {
  535. g = main.g;
  536. (* // reset *)
  537. ops = DynArray.create();
  538. pos = DynArray.create();
  539. breaks = [];
  540. continues = [];
  541. env = PMap.empty;
  542. nenv = 0;
  543. traps = [];
  544. loop_traps = 0;
  545. limit = main.stack;
  546. (* // dup *)
  547. version = main.version;
  548. stack = main.stack;
  549. locals = main.locals;
  550. loop_limit = main.loop_limit;
  551. curpos = main.curpos;
  552. curfile = main.curfile;
  553. } in
  554. List.iter (fun v ->
  555. ctx.stack <- ctx.stack + 1;
  556. ctx.locals <- PMap.add v ctx.stack ctx.locals;
  557. ) params;
  558. let s = ctx.stack in
  559. compile ctx true e;
  560. write ctx (Ret (ctx.stack - ctx.limit));
  561. check_stack ctx s (snd e);
  562. check_breaks ctx;
  563. (* // add let *)
  564. let gid = DynArray.length ctx.g.gtable in
  565. ctx.g.functions <- (ctx.ops,ctx.pos,gid,List.length params) :: ctx.g.functions;
  566. DynArray.add ctx.g.gtable (GlobalFunction(gid,-1));
  567. (* // environment *)
  568. if ctx.nenv > 0 then
  569. let a = Array.make ctx.nenv "" in
  570. PMap.iter (fun v i -> a.(i) <- v) ctx.env;
  571. Array.iter (fun v ->
  572. compile_constant main (Ident v) (snd e);
  573. write main Push;
  574. ) a;
  575. write main (AccGlobal gid);
  576. write main (MakeEnv ctx.nenv);
  577. else
  578. write main (AccGlobal gid);
  579. and compile_builtin ctx tail b el p =
  580. match (b , el) with
  581. | ("istrue" , [e]) ->
  582. compile ctx false e;
  583. write ctx Bool
  584. | ("not" , [e]) ->
  585. compile ctx false e;
  586. write ctx Not
  587. | ("typeof" , [e]) ->
  588. compile ctx false e;
  589. write ctx TypeOf
  590. | ("hash" , [e]) ->
  591. compile ctx false e;
  592. write ctx Hash
  593. | ("new" , [e]) ->
  594. compile ctx false e;
  595. write ctx New
  596. | ("compare" , [e1;e2]) ->
  597. compile ctx false e1;
  598. write ctx Push;
  599. compile ctx false e2;
  600. write ctx Compare
  601. | ("pcompare" , [e1;e2]) ->
  602. compile ctx false e1;
  603. write ctx Push;
  604. compile ctx false e2;
  605. write ctx PhysCompare
  606. | ("goto" , [(EConst (Ident l) , _)] ) ->
  607. let l = (try Hashtbl.find ctx.g.labels l with Not_found -> error ("Unknown label " ^ l) p) in
  608. let os = ctx.stack in
  609. let rec loop l1 l2 =
  610. match l1, l2 with
  611. | x :: l1 , y :: l2 when x == y -> loop l1 l2
  612. | _ -> (l1,l2)
  613. in
  614. let straps , dtraps = loop (List.rev ctx.traps) l.ltraps in
  615. List.iter (fun l ->
  616. if ctx.stack <> l then write ctx (Pop(ctx.stack - l));
  617. write ctx EndTrap;
  618. ) (List.rev straps);
  619. let dtraps = List.map (fun l ->
  620. let l = l - trap_stack_delta in
  621. if l < ctx.stack then write ctx (Pop(ctx.stack - l));
  622. while ctx.stack < l do
  623. write ctx Push;
  624. done;
  625. trap ctx
  626. ) dtraps in
  627. if l.lstack < ctx.stack then write ctx (Pop(ctx.stack - l.lstack));
  628. while l.lstack > ctx.stack do
  629. write ctx Push;
  630. done;
  631. ctx.stack <- os;
  632. (match l.lpos with
  633. | None -> l.lwait <- jmp ctx :: l.lwait
  634. | Some p -> write ctx (Jump p));
  635. List.iter (fun t ->
  636. t();
  637. write ctx Push;
  638. compile_constant ctx (Builtin "raise") p;
  639. write ctx (Call 1);
  640. (* // insert an infinite loop in order to
  641. // comply with bytecode checker *)
  642. let _ = jmp ctx in
  643. ()
  644. ) dtraps;
  645. | ("goto" , _) ->
  646. error "Invalid $goto statement" p
  647. | ("array",e :: el) ->
  648. let count = List.length el in
  649. (* // a single let can't have >128 stack *)
  650. if count > 120 - ctx.stack && count > 8 then begin
  651. (* // split in 8 and recurse *)
  652. let part = count lsr 3 in
  653. let rec loop el acc count =
  654. match el with
  655. | [] -> [List.rev acc]
  656. | e :: l ->
  657. if count == part then
  658. (List.rev acc) :: loop el [] 0
  659. else
  660. loop l (e :: acc) (count + 1)
  661. in
  662. let arr = make_array p (List.map (make_array p) (loop (e :: el) [] 0)) in
  663. compile_builtin ctx tail "aconcat" [arr] p;
  664. end else if ctx.version >= 2 then begin
  665. compile ctx false e;
  666. List.iter (fun e ->
  667. write ctx Push;
  668. compile ctx false e;
  669. ) el;
  670. write ctx (MakeArray count);
  671. end else begin
  672. List.iter (fun e ->
  673. compile ctx false e;
  674. write ctx Push;
  675. ) el;
  676. compile ctx false e;
  677. write ctx (MakeArray count);
  678. end
  679. | ("apply",e :: el) ->
  680. List.iter (fun e ->
  681. compile ctx false e;
  682. write ctx Push;
  683. ) el;
  684. compile ctx false e;
  685. let nargs = List.length el in
  686. if nargs > 0 then write ctx (Apply nargs);
  687. | _ ->
  688. List.iter (fun e ->
  689. compile ctx false e;
  690. write ctx Push;
  691. ) el;
  692. compile_constant ctx (Builtin b) p;
  693. if tail then
  694. write ctx (TailCall(List.length el,ctx.stack - ctx.limit))
  695. else
  696. write ctx (Call (List.length el))
  697. and compile ctx tail (e,p) =
  698. set_pos ctx p;
  699. match e with
  700. | EConst c ->
  701. compile_constant ctx c p
  702. | EBlock [] ->
  703. write ctx AccNull
  704. | EBlock el ->
  705. let locals = ctx.locals in
  706. let stack = ctx.stack in
  707. let rec loop(el) =
  708. match el with
  709. | [] -> assert false
  710. | [e] -> compile ctx tail e
  711. | [e; (ELabel _,_) as f] ->
  712. compile ctx tail e;
  713. compile ctx tail f
  714. | e :: el ->
  715. compile ctx false e;
  716. loop el
  717. in
  718. loop el;
  719. if stack < ctx.stack then write ctx (Pop (ctx.stack - stack));
  720. check_stack ctx stack p;
  721. ctx.locals <- locals
  722. | EParenthesis e ->
  723. compile ctx tail e
  724. | EField (e,f) ->
  725. compile ctx false e;
  726. write ctx (AccField f)
  727. | ECall (e,a :: b :: c :: d :: x1 :: x2 :: l) when (match e with (EConst (Builtin "array"),_) -> false | _ -> true) ->
  728. let call = (EConst (Builtin "call"),p) in
  729. let args = (ECall ((EConst (Builtin "array"),p),(a :: b :: c :: d :: x1 :: x2 :: l)),p) in
  730. (match e with
  731. | (EField (e,name) , p2) ->
  732. let locals = ctx.locals in
  733. let etmp = (EConst (Ident "$tmp"),p2) in
  734. compile ctx false (EVars [("$tmp",Some e)],p2);
  735. compile ctx tail (ECall (call,[(EField (etmp,name),p2);etmp;args]), p);
  736. write ctx (Pop 1);
  737. ctx.locals <- locals
  738. | _ ->
  739. compile ctx tail (ECall (call,[e; (EConst This,p); args]),p))
  740. | ECall ((EConst (Builtin b),_),el) ->
  741. compile_builtin ctx tail b el p
  742. | ECall ((EField (e,f),_),el) ->
  743. List.iter (fun e ->
  744. compile ctx false e;
  745. write ctx Push;
  746. ) el;
  747. compile ctx false e;
  748. write ctx Push;
  749. write ctx (AccField f);
  750. write ctx (ObjCall(List.length el))
  751. | ECall (e,el) ->
  752. List.iter (fun e ->
  753. compile ctx false e;
  754. write ctx Push;
  755. ) el;
  756. compile ctx false e;
  757. if tail then
  758. write ctx (TailCall(List.length el,ctx.stack - ctx.limit))
  759. else
  760. write ctx (Call(List.length el))
  761. | EArray (e1,(EConst (Int n),_)) ->
  762. compile ctx false e1;
  763. write ctx (if n == 0 then AccIndex0 else if n == 1 then AccIndex1 else AccIndex n)
  764. | EArray (e1,e2) ->
  765. compile ctx false e1;
  766. write ctx Push;
  767. compile ctx false e2;
  768. write ctx AccArray
  769. | EVars vl ->
  770. List.iter (fun (v,o) ->
  771. (match o with
  772. | None -> write ctx AccNull
  773. | Some e -> compile ctx false e);
  774. write ctx Push;
  775. ctx.locals <- PMap.add v ctx.stack ctx.locals;
  776. ) vl
  777. | EWhile (econd,e,NormalWhile) ->
  778. let start = pos ctx in
  779. if ctx.version >= 2 then write ctx Loop;
  780. compile ctx false econd;
  781. let jend = cjmp false ctx in
  782. let save = save_breaks ctx in
  783. compile ctx false e;
  784. process_continues save;
  785. goto ctx start;
  786. process_breaks save;
  787. jend();
  788. | EWhile (econd,e,DoWhile) ->
  789. let start = pos ctx in
  790. if ctx.version >= 2 then write ctx Loop;
  791. let save = save_breaks ctx in
  792. compile ctx false e;
  793. process_continues save;
  794. compile ctx false econd;
  795. write ctx (JumpIf (start - pos ctx));
  796. process_breaks save
  797. | EIf (e,e1,e2) ->
  798. let stack = ctx.stack in
  799. compile ctx false e;
  800. let jelse = cjmp false ctx in
  801. compile ctx tail e1;
  802. check_stack ctx stack p;
  803. (match e2 with
  804. | None ->
  805. jelse()
  806. | Some e2 ->
  807. let jend = jmp ctx in
  808. jelse();
  809. compile ctx tail e2;
  810. check_stack ctx stack p;
  811. jend())
  812. | ETry (e,v,ecatch) ->
  813. let trap = trap ctx in
  814. ctx.traps <- ctx.stack :: ctx.traps;
  815. compile ctx false e;
  816. write ctx EndTrap;
  817. ctx.traps <- (match ctx.traps with [] -> assert false | _ :: l -> l);
  818. let jend = jmp ctx in
  819. trap();
  820. write ctx Push;
  821. let locals = ctx.locals in
  822. ctx.locals <- PMap.add v ctx.stack ctx.locals;
  823. compile ctx tail ecatch;
  824. write ctx (Pop 1);
  825. ctx.locals <- locals;
  826. jend()
  827. | EBinop (op,e1,e2) ->
  828. compile_binop ctx tail op e1 e2 p
  829. | EReturn e ->
  830. (match e with None -> write ctx AccNull | Some e -> compile ctx (ctx.traps == []) e);
  831. let stack = ctx.stack in
  832. List.iter (fun t ->
  833. if ctx.stack > t then write ctx (Pop(ctx.stack - t));
  834. write ctx EndTrap;
  835. ) ctx.traps;
  836. write ctx (Ret (ctx.stack - ctx.limit));
  837. ctx.stack <- stack
  838. | EBreak e ->
  839. (match e with
  840. | None -> ()
  841. | Some e -> compile ctx false e);
  842. let s = ctx.stack in
  843. let n = ref (List.length ctx.traps - ctx.loop_traps) in
  844. List.iter (fun t ->
  845. if !n > 0 then begin
  846. decr n;
  847. if ctx.stack > t then write ctx (Pop(ctx.stack - t));
  848. write ctx EndTrap;
  849. end
  850. ) ctx.traps;
  851. if ctx.loop_limit <> ctx.stack then write ctx (Pop(ctx.stack - ctx.loop_limit));
  852. ctx.stack <- s;
  853. ctx.breaks <- (jmp ctx , p) :: ctx.breaks
  854. | EContinue ->
  855. let s = ctx.stack in
  856. let n = ref (List.length ctx.traps - ctx.loop_traps) in
  857. List.iter (fun t ->
  858. if !n > 0 then begin
  859. decr n;
  860. if ctx.stack > t then write ctx (Pop(ctx.stack - t));
  861. write ctx EndTrap;
  862. end
  863. ) ctx.traps;
  864. if ctx.loop_limit <> ctx.stack then write ctx (Pop(ctx.stack - ctx.loop_limit));
  865. ctx.stack <- s;
  866. ctx.continues <- (jmp ctx , p) :: ctx.continues
  867. | EFunction (params,e) ->
  868. compile_function ctx params e
  869. | ENext (e1,e2) ->
  870. compile ctx false e1;
  871. compile ctx tail e2
  872. | EObject [] ->
  873. write ctx AccNull;
  874. write ctx New
  875. | EObject fl ->
  876. let fields = List.sort compare (List.map fst fl) in
  877. let id = (try
  878. Hashtbl.find ctx.g.gobjects fields
  879. with Not_found ->
  880. let id = global ctx (GlobalVar ("o:" ^ string_of_int (Hashtbl.length ctx.g.gobjects))) in
  881. Hashtbl.add ctx.g.gobjects fields id;
  882. id
  883. ) in
  884. write ctx (AccGlobal id);
  885. write ctx New;
  886. write ctx Push;
  887. List.iter (fun (f,e) ->
  888. write ctx Push;
  889. compile ctx false e;
  890. write ctx (SetField f);
  891. write ctx AccStack0;
  892. ) fl;
  893. write ctx (Pop 1)
  894. | ELabel l ->
  895. let l = (try Hashtbl.find ctx.g.labels l with Not_found -> assert false) in
  896. if ctx.stack <> l.lstack || List.rev ctx.traps <> l.ltraps then error (Printf.sprintf "Label failure %d %d" ctx.stack l.lstack) p;
  897. List.iter (fun f -> f()) l.lwait;
  898. l.lwait <- [];
  899. l.lpos <- Some (pos ctx)
  900. | ESwitch (e,[(econd,exec)],eo) ->
  901. compile ctx tail (EIf ((EBinop ("==",e,econd),p),exec,eo),p)
  902. | ENeko _ ->
  903. assert false
  904. | ESwitch (e,cases,eo) ->
  905. try
  906. let ints , size = get_cases_ints cases in
  907. compile ctx false e;
  908. write ctx (JumpTable size);
  909. let tbl = Array.make size None in
  910. List.iter (fun (i,e) ->
  911. tbl.(i) <- Some e;
  912. ) ints;
  913. let tbl = Array.map (fun e -> (jmp ctx,e)) tbl in
  914. Array.iter (fun (j,e) ->
  915. if e == None then j()
  916. ) tbl;
  917. (match eo with
  918. | None -> write ctx AccNull
  919. | Some e -> compile ctx tail e);
  920. let jump_end = jmp ctx in
  921. let tbl = Array.map (fun (j,e) ->
  922. match e with
  923. | Some e ->
  924. j();
  925. compile ctx tail e;
  926. jmp ctx
  927. | None ->
  928. (fun() -> ())
  929. ) tbl in
  930. jump_end();
  931. Array.iter (fun j -> j()) tbl
  932. with Exit ->
  933. compile ctx false e;
  934. write ctx Push;
  935. let jumps = List.map (fun (e1,e2) ->
  936. write ctx AccStack0;
  937. write ctx Push;
  938. compile ctx false e1;
  939. write ctx Eq;
  940. (cjmp true ctx , e2)
  941. ) cases in
  942. (match eo with
  943. | None -> write ctx AccNull
  944. | Some e -> compile ctx tail (EBlock [e],p));
  945. let jump_end = jmp ctx in
  946. let jumps = List.map (fun (j,e) ->
  947. j();
  948. compile ctx tail (EBlock [e],p);
  949. jmp ctx;
  950. ) jumps in
  951. jump_end();
  952. List.iter (fun j -> j()) jumps;
  953. write ctx (Pop 1)
  954. let compile version ast =
  955. let g = {
  956. globals = Hashtbl.create 0;
  957. gobjects = Hashtbl.create 0;
  958. gtable = DynArray.create();
  959. functions = [];
  960. labels = Hashtbl.create 0;
  961. hfiles = Hashtbl.create 0;
  962. files = DynArray.create();
  963. } in
  964. let ctx = {
  965. g = g;
  966. version = version;
  967. stack = 0;
  968. loop_limit = 0;
  969. loop_traps = 0;
  970. limit = -1;
  971. locals = PMap.empty;
  972. ops = DynArray.create();
  973. breaks = [];
  974. continues = [];
  975. env = PMap.empty;
  976. nenv = 0;
  977. traps = [];
  978. pos = DynArray.create();
  979. curpos = (0,0);
  980. curfile = "_";
  981. } in
  982. if version >= 2 then DynArray.add g.gtable (GlobalVersion version);
  983. scan_labels ctx true true ast;
  984. compile ctx false ast;
  985. check_breaks ctx;
  986. if g.functions <> [] || Hashtbl.length g.gobjects <> 0 then begin
  987. let ctxops = ctx.ops in
  988. let ctxpos = ctx.pos in
  989. let ops = DynArray.create() in
  990. let pos = DynArray.create() in
  991. ctx.pos <- pos;
  992. ctx.ops <- ops;
  993. write ctx (Jump 0);
  994. List.iter (fun (fops,fpos,gid,nargs) ->
  995. DynArray.set g.gtable gid (GlobalFunction(DynArray.length ops,nargs));
  996. DynArray.append fops ops;
  997. DynArray.append fpos pos;
  998. ) (List.rev g.functions);
  999. DynArray.set ops 0 (Jump (DynArray.length ops));
  1000. let objects = DynArray.create() in
  1001. Hashtbl.iter (fun fl g -> DynArray.add objects (fl,g)) g.gobjects;
  1002. let objects = DynArray.to_array objects in
  1003. Array.sort (fun (_,g1) (_,g2) -> g1 - g2) objects;
  1004. Array.iter (fun (fl,g) ->
  1005. write ctx AccNull;
  1006. write ctx New;
  1007. write ctx (SetGlobal g);
  1008. List.iter (fun f ->
  1009. write ctx (AccGlobal g);
  1010. write ctx Push;
  1011. write ctx (SetField f);
  1012. ) fl
  1013. ) objects;
  1014. DynArray.append ctxpos pos;
  1015. DynArray.append ctxops ops;
  1016. end;
  1017. DynArray.add g.gtable (GlobalDebug (DynArray.to_array ctx.g.files,DynArray.to_array ctx.pos));
  1018. (DynArray.to_array g.gtable, DynArray.to_array ctx.ops)