optimizer.ml 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245
  1. (*
  2. * Copyright (C)2005-2013 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 Ast
  23. open Type
  24. open Common
  25. open Typecore
  26. (* ---------------------------------------------------------------------- *)
  27. (* API OPTIMIZATIONS *)
  28. let has_side_effect e =
  29. let rec loop e =
  30. match e.eexpr with
  31. | TConst _ | TLocal _ | TField (_,FEnum _) | TTypeExpr _ | TFunction _ -> ()
  32. | TMatch _ | TNew _ | TCall _ | TField _ | TArray _ | TBinop ((OpAssignOp _ | OpAssign),_,_) | TUnop ((Increment|Decrement),_,_) -> raise Exit
  33. | TReturn _ | TBreak | TContinue | TThrow _ | TCast (_,Some _) -> raise Exit
  34. | TCast (_,None) | TBinop _ | TUnop _ | TParenthesis _ | TWhile _ | TFor _ | TIf _ | TTry _ | TSwitch _ | TArrayDecl _ | TVars _ | TBlock _ | TObjectDecl _ -> Type.iter loop e
  35. in
  36. try
  37. loop e; false
  38. with Exit ->
  39. true
  40. let api_inline ctx c field params p =
  41. match c.cl_path, field, params with
  42. | ([],"Type"),"enumIndex",[{ eexpr = TField (_,FEnum (en,f)) }] ->
  43. Some (mk (TConst (TInt (Int32.of_int f.ef_index))) ctx.t.tint p)
  44. | ([],"Type"),"enumIndex",[{ eexpr = TCall({ eexpr = TField (_,FEnum (en,f)) },pl) }] when List.for_all (fun e -> not (has_side_effect e)) pl ->
  45. Some (mk (TConst (TInt (Int32.of_int f.ef_index))) ctx.t.tint p)
  46. | ([],"Std"),"int",[{ eexpr = TConst (TInt _) } as e] ->
  47. Some { e with epos = p }
  48. | ([],"String"),"fromCharCode",[{ eexpr = TConst (TInt i) }] when i > 0l && i < 128l ->
  49. Some (mk (TConst (TString (String.make 1 (char_of_int (Int32.to_int i))))) ctx.t.tstring p)
  50. | ([],"Std"),"string",[{ eexpr = TConst c } as e] ->
  51. (match c with
  52. | TString s ->
  53. Some { e with epos = p }
  54. | TInt i ->
  55. Some { eexpr = TConst (TString (Int32.to_string i)); epos = p; etype = ctx.t.tstring }
  56. | TBool b ->
  57. Some { eexpr = TConst (TString (if b then "true" else "false")); epos = p; etype = ctx.t.tstring }
  58. | _ ->
  59. None)
  60. | ([],"Std"),"int",[{ eexpr = TConst (TFloat f) }] ->
  61. let f = float_of_string f in
  62. (match classify_float f with
  63. | FP_infinite | FP_nan ->
  64. None
  65. | _ when f <= Int32.to_float Int32.min_int -. 1. || f >= Int32.to_float Int32.max_int +. 1. ->
  66. None (* out range, keep platform-specific behavior *)
  67. | _ ->
  68. Some { eexpr = TConst (TInt (Int32.of_float f)); etype = ctx.t.tint; epos = p })
  69. | _ ->
  70. None
  71. (* ---------------------------------------------------------------------- *)
  72. (* INLINING *)
  73. type in_local = {
  74. i_var : tvar;
  75. i_subst : tvar;
  76. mutable i_captured : bool;
  77. mutable i_write : bool;
  78. mutable i_read : int;
  79. }
  80. let inline_default_config cf t =
  81. (* type substitution on both class and function type parameters *)
  82. let rec get_params c pl =
  83. match c.cl_super with
  84. | None -> c.cl_types, pl
  85. | Some (csup,spl) ->
  86. let spl = (match apply_params c.cl_types pl (TInst (csup,spl)) with
  87. | TInst (_,pl) -> pl
  88. | _ -> assert false
  89. ) in
  90. let ct, cpl = get_params csup spl in
  91. c.cl_types @ ct, pl @ cpl
  92. in
  93. let tparams = (match follow t with
  94. | TInst (c,pl) -> get_params c pl
  95. | _ -> ([],[]))
  96. in
  97. let pmonos = List.map (fun _ -> mk_mono()) cf.cf_params in
  98. let tmonos = snd tparams @ pmonos in
  99. let tparams = fst tparams @ cf.cf_params in
  100. tparams <> [], apply_params tparams tmonos
  101. let rec type_inline ctx cf f ethis params tret config p force =
  102. (* perform some specific optimization before we inline the call since it's not possible to detect at final optimization time *)
  103. try
  104. let cl = (match follow ethis.etype with
  105. | TInst (c,_) -> c
  106. | TAnon a -> (match !(a.a_status) with Statics c -> c | _ -> raise Exit)
  107. | _ -> raise Exit
  108. ) in
  109. (match api_inline ctx cl cf.cf_name params p with
  110. | None -> raise Exit
  111. | Some e -> Some e)
  112. with Exit ->
  113. let has_params,map_type = match config with Some config -> config | None -> inline_default_config cf ethis.etype in
  114. (* locals substitution *)
  115. let locals = Hashtbl.create 0 in
  116. let local v =
  117. try
  118. Hashtbl.find locals v.v_id
  119. with Not_found ->
  120. let i = {
  121. i_var = v;
  122. i_subst = alloc_var v.v_name v.v_type;
  123. i_captured = false;
  124. i_write = false;
  125. i_read = 0;
  126. } in
  127. Hashtbl.add locals v.v_id i;
  128. Hashtbl.add locals i.i_subst.v_id i;
  129. i
  130. in
  131. let read_local v =
  132. try
  133. Hashtbl.find locals v.v_id
  134. with Not_found ->
  135. {
  136. i_var = v;
  137. i_subst = v;
  138. i_captured = false;
  139. i_write = false;
  140. i_read = 0;
  141. }
  142. in
  143. (* use default values for null/unset arguments *)
  144. let rec loop pl al first =
  145. match pl, al with
  146. | _, [] -> []
  147. | e :: pl, (v, opt) :: al ->
  148. (*
  149. if we pass a Null<T> var to an inlined method that needs a T.
  150. we need to force a local var to be created on some platforms.
  151. *)
  152. if ctx.com.config.pf_static && not (is_nullable v.v_type) && is_null e.etype then (local v).i_write <- true;
  153. (*
  154. if we cast from Dynamic, create a local var as well to do the cast
  155. once and allow DCE to perform properly.
  156. *)
  157. if v.v_type != t_dynamic && follow e.etype == t_dynamic then (local v).i_write <- true;
  158. (match e.eexpr, opt with
  159. | TConst TNull , Some c -> mk (TConst c) v.v_type e.epos
  160. (* we have to check for abstract casts here because we can't do that later. However, we have to skip the check for the
  161. first argument of abstract implementation functions. *)
  162. | _ when not (first && Meta.has Meta.Impl cf.cf_meta && cf.cf_name <> "_new") -> (!check_abstract_cast_ref) ctx (map_type v.v_type) e e.epos
  163. | _ -> e) :: loop pl al false
  164. | [], (v,opt) :: al ->
  165. mk (TConst (match opt with None -> TNull | Some c -> c)) v.v_type p :: loop [] al false
  166. in
  167. (*
  168. Build the expr/var subst list
  169. *)
  170. let ethis = (match ethis.eexpr with TConst TSuper -> { ethis with eexpr = TConst TThis } | _ -> ethis) in
  171. let vthis = alloc_var "_this" ethis.etype in
  172. let inlined_vars = List.map2 (fun e (v,_) -> local v, e) (ethis :: loop params f.tf_args true) ((vthis,None) :: f.tf_args) in
  173. (*
  174. here, we try to eliminate final returns from the expression tree.
  175. However, this is not entirely correct since we don't yet correctly propagate
  176. the type of returned expressions upwards ("return" expr itself being Dynamic).
  177. We also substitute variables with fresh ones that might be renamed at later stage.
  178. *)
  179. let opt f = function
  180. | None -> None
  181. | Some e -> Some (f e)
  182. in
  183. let has_vars = ref false in
  184. let in_loop = ref false in
  185. let in_local_fun = ref false in
  186. let cancel_inlining = ref false in
  187. let has_return_value = ref false in
  188. let ret_val = (match follow f.tf_type with TAbstract ({ a_path = ([],"Void") },[]) -> false | _ -> true) in
  189. let rec map term e =
  190. let po = e.epos in
  191. let e = { e with epos = p } in
  192. match e.eexpr with
  193. | TLocal v ->
  194. let l = read_local v in
  195. if !in_local_fun then l.i_captured <- true;
  196. l.i_read <- l.i_read + (if !in_loop then 2 else 1);
  197. (* never inline a function which contain a delayed macro because its bound
  198. to its variables and not the calling method *)
  199. if v.v_name = "__dollar__delay_call" then cancel_inlining := true;
  200. { e with eexpr = TLocal l.i_subst }
  201. | TConst TThis ->
  202. let l = read_local vthis in
  203. l.i_read <- l.i_read + (if !in_loop then 2 else 1);
  204. { e with eexpr = TLocal l.i_subst }
  205. | TVars vl ->
  206. has_vars := true;
  207. let vl = List.map (fun (v,e) ->
  208. (local v).i_subst,opt (map false) e
  209. ) vl in
  210. { e with eexpr = TVars vl }
  211. | TReturn eo when not !in_local_fun ->
  212. if not term then error "Cannot inline a not final return" po;
  213. (match eo with
  214. | None -> mk (TConst TNull) f.tf_type p
  215. | Some e -> has_return_value := true;
  216. (* we can omit unsafe casts to retain the real type, the cast will be added back later anyway *)
  217. (match e.eexpr with
  218. | TCast(e1,None) -> map term e1
  219. | _ -> map term e))
  220. | TFor (v,e1,e2) ->
  221. let i = local v in
  222. let e1 = map false e1 in
  223. let old = !in_loop in
  224. in_loop := true;
  225. let e2 = map false e2 in
  226. in_loop := old;
  227. { e with eexpr = TFor (i.i_subst,e1,e2) }
  228. | TWhile (cond,eloop,flag) ->
  229. let cond = map false cond in
  230. let old = !in_loop in
  231. in_loop := true;
  232. let eloop = map false eloop in
  233. in_loop := old;
  234. { e with eexpr = TWhile (cond,eloop,flag) }
  235. | TMatch (v,en,cases,def) ->
  236. let term = term && def <> None in
  237. let cases = List.map (fun (i,vl,e) ->
  238. let vl = opt (List.map (fun v -> opt (fun v -> (local v).i_subst) v)) vl in
  239. i, vl, map term e
  240. ) cases in
  241. let def = opt (map term) def in
  242. { e with eexpr = TMatch (map false v,en,cases,def); etype = if term && ret_val then unify_min ctx ((List.map (fun (_,_,e) -> e) cases) @ (match def with None -> [] | Some e -> [e])) else e.etype }
  243. | TSwitch (e1,cases,def) when term ->
  244. let term = term && def <> None in
  245. let cases = List.map (fun (el,e) ->
  246. let el = List.map (map false) el in
  247. el, map term e
  248. ) cases in
  249. let def = opt (map term) def in
  250. { e with eexpr = TSwitch (map false e1,cases,def); etype = if ret_val then unify_min ctx ((List.map snd cases) @ (match def with None -> [] | Some e -> [e])) else e.etype }
  251. | TTry (e1,catches) ->
  252. { e with eexpr = TTry (map term e1,List.map (fun (v,e) ->
  253. let lv = (local v).i_subst in
  254. let e = map term e in
  255. lv,e
  256. ) catches); etype = if term && ret_val then unify_min ctx (e1::List.map snd catches) else e.etype }
  257. | TBlock l ->
  258. let old = save_locals ctx in
  259. let t = ref e.etype in
  260. let rec loop = function
  261. | [] when term ->
  262. t := mk_mono();
  263. [mk (TConst TNull) (!t) p]
  264. | [] -> []
  265. | [e] ->
  266. let e = map term e in
  267. if term then t := e.etype;
  268. [e]
  269. | e :: l ->
  270. let e = map false e in
  271. e :: loop l
  272. in
  273. let l = loop l in
  274. old();
  275. { e with eexpr = TBlock l; etype = !t }
  276. | TIf (econd,eif,Some eelse) when term ->
  277. let econd = map false econd in
  278. let eif = map term eif in
  279. let eelse = map term eelse in
  280. { e with eexpr = TIf(econd,eif,Some eelse); etype = if ret_val then unify_min ctx [eif;eelse] else e.etype }
  281. | TParenthesis e1 ->
  282. let e1 = map term e1 in
  283. mk (TParenthesis e1) e1.etype e.epos
  284. | TUnop ((Increment|Decrement),_,{ eexpr = TLocal v }) ->
  285. (read_local v).i_write <- true;
  286. Type.map_expr (map false) e
  287. | TBinop ((OpAssign | OpAssignOp _),{ eexpr = TLocal v },_) ->
  288. (read_local v).i_write <- true;
  289. Type.map_expr (map false) e;
  290. | TFunction f ->
  291. (match f.tf_args with [] -> () | _ -> has_vars := true);
  292. let old = save_locals ctx and old_fun = !in_local_fun in
  293. let args = List.map (function(v,c) -> (local v).i_subst, c) f.tf_args in
  294. in_local_fun := true;
  295. let expr = map false f.tf_expr in
  296. in_local_fun := old_fun;
  297. old();
  298. { e with eexpr = TFunction { tf_args = args; tf_expr = expr; tf_type = f.tf_type } }
  299. | TConst TSuper ->
  300. error "Cannot inline function containing super" po
  301. | _ ->
  302. Type.map_expr (map false) e
  303. in
  304. let e = map true f.tf_expr in
  305. (*
  306. if variables are not written and used with a const value, let's substitute
  307. with the actual value, either create a temp var
  308. *)
  309. let subst = ref PMap.empty in
  310. let is_constant e =
  311. let rec loop e =
  312. match e.eexpr with
  313. | TLocal _
  314. | TConst TThis (* not really, but should not be move inside a function body *)
  315. -> raise Exit
  316. | TField (_,FEnum _)
  317. | TTypeExpr _
  318. | TConst _ -> ()
  319. | _ ->
  320. Type.iter loop e
  321. in
  322. try loop e; true with Exit -> false
  323. in
  324. let is_writable e =
  325. match e.eexpr with
  326. | TField _ | TLocal _ | TArray _ -> true
  327. | _ -> false
  328. in
  329. let force = ref force in
  330. let vars = List.fold_left (fun acc (i,e) ->
  331. let flag = (match e.eexpr with
  332. | TLocal { v_name = "this" } -> true
  333. | TLocal _ | TConst _ -> not i.i_write
  334. | TFunction _ -> if i.i_write then error "Cannot modify a closure parameter inside inline method" p; true
  335. | _ -> not i.i_write && i.i_read <= 1
  336. ) in
  337. let flag = flag && (not i.i_captured || is_constant e) in
  338. (* force inlining if we modify 'this' *)
  339. if i.i_write && i.i_var.v_name = "this" then force := true;
  340. (* force inlining of 'this' variable if the expression is writable *)
  341. let flag = if not flag && i.i_var.v_name = "this" then begin
  342. if i.i_write && not (is_writable e) then error "Cannot modify the abstract value, store it into a local first" p;
  343. true
  344. end else flag in
  345. if flag then begin
  346. subst := PMap.add i.i_subst.v_id e !subst;
  347. acc
  348. end else
  349. (i.i_subst,Some e) :: acc
  350. ) [] inlined_vars in
  351. let subst = !subst in
  352. let rec inline_params e =
  353. match e.eexpr with
  354. | TLocal v -> (try PMap.find v.v_id subst with Not_found -> e)
  355. | _ -> Type.map_expr inline_params e
  356. in
  357. let e = (if PMap.is_empty subst then e else inline_params e) in
  358. let init = (match vars with [] -> None | l -> Some (mk (TVars (List.rev l)) ctx.t.tvoid p)) in
  359. (*
  360. If we have local variables and returning a value, then this will result in
  361. unoptimized JS code, so let's instead skip inlining.
  362. This could be fixed with better post process code cleanup (planed)
  363. *)
  364. if !cancel_inlining || (Common.platform ctx.com Js && not !force && (init <> None || !has_vars)) then
  365. None
  366. else
  367. let wrap e =
  368. (* we can't mute the type of the expression because it is not correct to do so *)
  369. (try
  370. let etype = if has_params then map_type e.etype else e.etype in
  371. (* if the expression is "untyped" and we don't want to unify it accidentally ! *)
  372. (match follow e.etype with
  373. | TMono _ ->
  374. (match follow tret with
  375. | TAbstract ({ a_path = [],"Void" },_) -> e
  376. | _ -> raise (Unify_error []))
  377. | _ -> try
  378. type_eq EqStrict etype tret;
  379. e
  380. with Unify_error _ when (match ctx.com.platform with Cpp -> true | Flash when Common.defined ctx.com Define.As3 -> true | _ -> false) ->
  381. (* try to detect upcasts: in that case we may use a safe cast *)
  382. Type.unify tret etype;
  383. let ct = match follow tret with
  384. | TInst(c,_) -> Some (TClassDecl c)
  385. | _ -> None
  386. in
  387. mk (TCast (e,ct)) tret e.epos)
  388. with Unify_error _ ->
  389. mk (TCast (e,None)) tret e.epos)
  390. in
  391. let e = (match e.eexpr, init with
  392. | _, None when not !has_return_value ->
  393. {e with etype = tret}
  394. | TBlock [e] , None -> wrap e
  395. | _ , None -> wrap e
  396. | TBlock l, Some init -> mk (TBlock (init :: l)) tret e.epos
  397. | _, Some init -> mk (TBlock [init;e]) tret e.epos
  398. ) in
  399. (* we need to replace type-parameters that were used in the expression *)
  400. if not has_params then
  401. Some e
  402. else
  403. let mt = map_type cf.cf_type in
  404. let unify_func () = unify_raise ctx mt (TFun (List.map (fun e -> "",false,e.etype) params,tret)) p in
  405. (match follow ethis.etype with
  406. | TAnon a -> (match !(a.a_status) with
  407. | Statics {cl_kind = KAbstractImpl a } when Meta.has Meta.Impl cf.cf_meta ->
  408. if cf.cf_name <> "_new" then begin
  409. (* the first argument must unify with a_this for abstract implementation functions *)
  410. let tb = (TFun(("",false,map_type a.a_this) :: List.map (fun e -> "",false,e.etype) (List.tl params),tret)) in
  411. unify_raise ctx mt tb p
  412. end
  413. | _ -> unify_func())
  414. | _ -> unify_func());
  415. (*
  416. this is very expensive since we are building the substitution list for
  417. every expression, but hopefully in such cases the expression size is small
  418. *)
  419. let vars = Hashtbl.create 0 in
  420. let map_var v =
  421. if not (Hashtbl.mem vars v.v_id) then begin
  422. Hashtbl.add vars v.v_id ();
  423. v.v_type <- map_type v.v_type;
  424. end;
  425. v
  426. in
  427. let rec map_expr_type e = Type.map_expr_type map_expr_type map_type map_var e in
  428. Some (map_expr_type e)
  429. (* ---------------------------------------------------------------------- *)
  430. (* LOOPS *)
  431. let rec optimize_for_loop ctx i e1 e2 p =
  432. let t_void = ctx.t.tvoid in
  433. let t_int = ctx.t.tint in
  434. let lblock el = Some (mk (TBlock el) t_void p) in
  435. let mk_field e n =
  436. TField (e,try quick_field e.etype n with Not_found -> assert false)
  437. in
  438. let gen_int_iter pt =
  439. let i = add_local ctx i pt in
  440. let index = gen_local ctx t_int in
  441. let arr, avars = (match e1.eexpr with
  442. | TLocal _ -> e1, []
  443. | _ ->
  444. let atmp = gen_local ctx e1.etype in
  445. mk (TLocal atmp) e1.etype e1.epos, [atmp,Some e1]
  446. ) in
  447. let iexpr = mk (TLocal index) t_int p in
  448. let e2 = type_expr ctx e2 NoValue in
  449. let aget = mk (TVars [i,Some (mk (TArray (arr,iexpr)) pt p)]) t_void p in
  450. let incr = mk (TUnop (Increment,Prefix,iexpr)) t_int p in
  451. let block = match e2.eexpr with
  452. | TBlock el -> mk (TBlock (aget :: incr :: el)) t_void e2.epos
  453. | _ -> mk (TBlock [aget;incr;e2]) t_void p
  454. in
  455. let ivar = index, Some (mk (TConst (TInt 0l)) t_int p) in
  456. let elength = match follow e1.etype with
  457. | TAbstract({a_impl = Some c},_) ->
  458. let ta = TAnon { a_fields = c.cl_statics; a_status = ref (Statics c) } in
  459. let ethis = mk (TTypeExpr (TClassDecl c)) ta e1.epos in
  460. let efield = mk (mk_field ethis "get_length") (tfun [arr.etype] t_int) p in
  461. make_call ctx efield [arr] t_int e1.epos
  462. | _ -> mk (mk_field arr "length") t_int p
  463. in
  464. lblock [
  465. mk (TVars (ivar :: avars)) t_void p;
  466. mk (TWhile (
  467. mk (TBinop (OpLt, iexpr, elength)) ctx.t.tbool p,
  468. block,
  469. NormalWhile
  470. )) t_void p;
  471. ]
  472. in
  473. match e1.eexpr, follow e1.etype with
  474. | TNew ({ cl_path = ([],"IntIterator") },[],[i1;i2]) , _ ->
  475. let max = (match i1.eexpr , i2.eexpr with
  476. | TConst (TInt a), TConst (TInt b) when Int32.compare b a < 0 -> error "Range operate can't iterate backwards" p
  477. | _, TConst _ | _ , TLocal _ -> None
  478. | _ -> Some (gen_local ctx t_int)
  479. ) in
  480. let tmp = gen_local ctx t_int in
  481. let i = add_local ctx i t_int in
  482. let rec check e =
  483. match e.eexpr with
  484. | TBinop (OpAssign,{ eexpr = TLocal l },_)
  485. | TBinop (OpAssignOp _,{ eexpr = TLocal l },_)
  486. | TUnop (Increment,_,{ eexpr = TLocal l })
  487. | TUnop (Decrement,_,{ eexpr = TLocal l }) when l == i ->
  488. error "Loop variable cannot be modified" e.epos
  489. | _ ->
  490. Type.iter check e
  491. in
  492. let e2 = type_expr ctx e2 NoValue in
  493. check e2;
  494. let etmp = mk (TLocal tmp) t_int p in
  495. let incr = mk (TUnop (Increment,Postfix,etmp)) t_int p in
  496. let init = mk (TVars [i,Some incr]) t_void p in
  497. let block = match e2.eexpr with
  498. | TBlock el -> mk (TBlock (init :: el)) t_void e2.epos
  499. | _ -> mk (TBlock [init;e2]) t_void p
  500. in
  501. (*
  502. force locals to be of Int type (to prevent Int/UInt issues)
  503. *)
  504. let i2 = match i2.etype with
  505. | TAbstract ({ a_path = ([],"Int") }, []) -> i2
  506. | _ -> { i2 with eexpr = TCast(i2, None); etype = t_int }
  507. in
  508. (match max with
  509. | None ->
  510. lblock [
  511. mk (TVars [tmp,Some i1]) t_void p;
  512. mk (TWhile (
  513. mk (TBinop (OpLt, etmp, i2)) ctx.t.tbool p,
  514. block,
  515. NormalWhile
  516. )) t_void p;
  517. ]
  518. | Some max ->
  519. lblock [
  520. mk (TVars [tmp,Some i1;max,Some i2]) t_void p;
  521. mk (TWhile (
  522. mk (TBinop (OpLt, etmp, mk (TLocal max) t_int p)) ctx.t.tbool p,
  523. block,
  524. NormalWhile
  525. )) t_void p;
  526. ])
  527. | _ , TInst({ cl_path = [],"Array" },[pt])
  528. | _ , TInst({ cl_path = ["flash"],"Vector" },[pt]) ->
  529. gen_int_iter pt
  530. | _ , TInst({ cl_array_access = Some pt } as c,pl) when (try match follow (PMap.find "length" c.cl_fields).cf_type with TAbstract ({ a_path = [],"Int" },[]) -> true | _ -> false with Not_found -> false) && not (PMap.mem "iterator" c.cl_fields) ->
  531. gen_int_iter (apply_params c.cl_types pl pt)
  532. | (TLocal _ | TField _), TAbstract({a_impl = Some c} as a,[pt]) when Meta.has Meta.ArrayAccess a.a_meta && (try match follow (PMap.find "length" c.cl_statics).cf_type with TAbstract ({ a_path = [],"Int" },[]) -> true | _ -> false with Not_found -> false) && not (PMap.mem "iterator" c.cl_statics) ->
  533. gen_int_iter pt
  534. | _ , TInst ({ cl_kind = KGenericInstance ({ cl_path = ["haxe";"ds"],"GenericStack" },[t]) } as c,[]) ->
  535. let tcell = (try (PMap.find "head" c.cl_fields).cf_type with Not_found -> assert false) in
  536. let i = add_local ctx i t in
  537. let cell = gen_local ctx tcell in
  538. let cexpr = mk (TLocal cell) tcell p in
  539. let e2 = type_expr ctx e2 NoValue in
  540. let evar = mk (TVars [i,Some (mk (mk_field cexpr "elt") t p)]) t_void p in
  541. let enext = mk (TBinop (OpAssign,cexpr,mk (mk_field cexpr "next") tcell p)) tcell p in
  542. let block = match e2.eexpr with
  543. | TBlock el -> mk (TBlock (evar :: enext :: el)) t_void e2.epos
  544. | _ -> mk (TBlock [evar;enext;e2]) t_void p
  545. in
  546. lblock [
  547. mk (TVars [cell,Some (mk (mk_field e1 "head") tcell p)]) t_void p;
  548. mk (TWhile (
  549. mk (TBinop (OpNotEq, cexpr, mk (TConst TNull) tcell p)) ctx.t.tbool p,
  550. block,
  551. NormalWhile
  552. )) t_void p
  553. ]
  554. | _ ->
  555. None
  556. (* ---------------------------------------------------------------------- *)
  557. (* SANITIZE *)
  558. (*
  559. makes sure that when an AST get generated to source code, it will not
  560. generate expressions that evaluate differently. It is then necessary to
  561. add parenthesises around some binary expressions when the AST does not
  562. correspond to the natural operand priority order for the platform
  563. *)
  564. (*
  565. this is the standard C++ operator precedence, which is also used by both JS and PHP
  566. *)
  567. let standard_precedence op =
  568. let left = true and right = false in
  569. match op with
  570. | OpMult | OpDiv | OpMod -> 5, left
  571. | OpAdd | OpSub -> 6, left
  572. | OpShl | OpShr | OpUShr -> 7, left
  573. | OpLt | OpLte | OpGt | OpGte -> 8, left
  574. | OpEq | OpNotEq -> 9, left
  575. | OpAnd -> 10, left
  576. | OpXor -> 11, left
  577. | OpOr -> 12, left
  578. | OpInterval -> 13, right (* haxe specific *)
  579. | OpBoolAnd -> 14, left
  580. | OpBoolOr -> 15, left
  581. | OpArrow -> 16, left
  582. | OpAssignOp OpAssign -> 17, right (* mimics ?: *)
  583. | OpAssign | OpAssignOp _ -> 18, right
  584. let rec need_parent e =
  585. match e.eexpr with
  586. | TConst _ | TLocal _ | TArray _ | TField _ | TParenthesis _ | TCall _ | TNew _ | TTypeExpr _ | TObjectDecl _ | TArrayDecl _ -> false
  587. | TCast (e,None) -> need_parent e
  588. | TCast _ | TThrow _ | TReturn _ | TTry _ | TMatch _ | TSwitch _ | TFor _ | TIf _ | TWhile _ | TBinop _ | TContinue | TBreak
  589. | TBlock _ | TVars _ | TFunction _ | TUnop _ -> true
  590. let rec add_final_return e t =
  591. let def_return p =
  592. let c = (match follow t with
  593. | TAbstract ({ a_path = [],"Int" },_) -> TInt 0l
  594. | TAbstract ({ a_path = [],"Float" },_) -> TFloat "0."
  595. | TAbstract ({ a_path = [],"Bool" },_) -> TBool false
  596. | _ -> TNull
  597. ) in
  598. { eexpr = TReturn (Some { eexpr = TConst c; epos = p; etype = t }); etype = t; epos = p }
  599. in
  600. match e.eexpr with
  601. | TBlock el ->
  602. (match List.rev el with
  603. | [] -> e
  604. | elast :: el ->
  605. match add_final_return elast t with
  606. | { eexpr = TBlock el2 } -> { e with eexpr = TBlock ((List.rev el) @ el2) }
  607. | elast -> { e with eexpr = TBlock (List.rev (elast :: el)) })
  608. | TReturn _ ->
  609. e
  610. | _ ->
  611. { e with eexpr = TBlock [e;def_return e.epos] }
  612. let sanitize_expr com e =
  613. let parent e =
  614. match e.eexpr with
  615. | TParenthesis _ -> e
  616. | _ -> mk (TParenthesis e) e.etype e.epos
  617. in
  618. let block e =
  619. match e.eexpr with
  620. | TBlock _ -> e
  621. | _ -> mk (TBlock [e]) e.etype e.epos
  622. in
  623. let complex e =
  624. (* complex expressions are the one that once generated to source consists in several expressions *)
  625. match e.eexpr with
  626. | TVars _ (* needs to be put into blocks *)
  627. | TFor _ (* a temp var is needed for holding iterator *)
  628. | TMatch _ (* a temp var is needed for holding enum *)
  629. | TCall ({ eexpr = TLocal { v_name = "__js__" } },_) (* we never know *)
  630. -> block e
  631. | _ -> e
  632. in
  633. (* tells if the printed expresssion ends with an if without else *)
  634. let rec has_if e =
  635. match e.eexpr with
  636. | TIf (_,_,None) -> true
  637. | TWhile (_,e,NormalWhile) -> has_if e
  638. | TFor (_,_,e) -> has_if e
  639. | _ -> false
  640. in
  641. match e.eexpr with
  642. | TConst TNull ->
  643. if com.config.pf_static && not (is_nullable e.etype) then
  644. (match follow e.etype with
  645. | TMono _ -> () (* in these cases the null will cast to default value *)
  646. | TFun _ -> () (* this is a bit a particular case, maybe flash-specific actually *)
  647. | _ -> com.error ("On static platforms, null can't be used as basic type " ^ s_type (print_context()) e.etype) e.epos);
  648. e
  649. | TBinop (op,e1,e2) ->
  650. let swap op1 op2 =
  651. let p1, left1 = standard_precedence op1 in
  652. let p2, _ = standard_precedence op2 in
  653. left1 && p1 <= p2
  654. in
  655. let rec loop ee left =
  656. match ee.eexpr with
  657. | TBinop (op2,_,_) -> if left then not (swap op2 op) else swap op op2
  658. | TIf _ -> if left then not (swap (OpAssignOp OpAssign) op) else swap op (OpAssignOp OpAssign)
  659. | TCast (e,None) -> loop e left
  660. | _ -> false
  661. in
  662. let e1 = if loop e1 true then parent e1 else e1 in
  663. let e2 = if loop e2 false then parent e2 else e2 in
  664. { e with eexpr = TBinop (op,e1,e2) }
  665. | TUnop (op,mode,e2) ->
  666. let rec loop ee =
  667. match ee.eexpr with
  668. | TBinop _ | TIf _ -> parent e2
  669. | TCast (e,None) -> loop e
  670. | _ -> e2
  671. in
  672. { e with eexpr = TUnop (op,mode,loop e2) }
  673. | TIf (e1,e2,eelse) ->
  674. let e1 = parent e1 in
  675. let e2 = (if (eelse <> None && has_if e2) || (match e2.eexpr with TIf _ -> true | _ -> false) then block e2 else complex e2) in
  676. let eelse = (match eelse with None -> None | Some e -> Some (complex e)) in
  677. { e with eexpr = TIf (e1,e2,eelse) }
  678. | TWhile (e1,e2,flag) ->
  679. let e1 = parent e1 in
  680. let e2 = complex e2 in
  681. { e with eexpr = TWhile (e1,e2,flag) }
  682. | TFor (v,e1,e2) ->
  683. let e2 = complex e2 in
  684. { e with eexpr = TFor (v,e1,e2) }
  685. | TFunction f ->
  686. let f = (match follow f.tf_type with
  687. | TAbstract ({ a_path = [],"Void" },[]) -> f
  688. | t ->
  689. if com.config.pf_add_final_return then { f with tf_expr = add_final_return f.tf_expr t } else f
  690. ) in
  691. let f = (match f.tf_expr.eexpr with
  692. | TBlock _ -> f
  693. | _ -> { f with tf_expr = block f.tf_expr }
  694. ) in
  695. { e with eexpr = TFunction f }
  696. | TCall (e2,args) ->
  697. if need_parent e2 then { e with eexpr = TCall(parent e2,args) } else e
  698. | TField (e2,f) ->
  699. if need_parent e2 then { e with eexpr = TField(parent e2,f) } else e
  700. | TArray (e1,e2) ->
  701. if need_parent e1 then { e with eexpr = TArray(parent e1,e2) } else e
  702. | TTry (e1,catches) ->
  703. let e1 = block e1 in
  704. let catches = List.map (fun (v,e) -> v, block e) catches in
  705. { e with eexpr = TTry (e1,catches) }
  706. | TSwitch (e1,cases,def) ->
  707. let e1 = parent e1 in
  708. let cases = List.map (fun (el,e) -> el, complex e) cases in
  709. let def = (match def with None -> None | Some e -> Some (complex e)) in
  710. { e with eexpr = TSwitch (e1,cases,def) }
  711. | TMatch (e1, en, cases, def) ->
  712. let e1 = parent e1 in
  713. let cases = List.map (fun (el,vars,e) -> el, vars, complex e) cases in
  714. let def = (match def with None -> None | Some e -> Some (complex e)) in
  715. { e with eexpr = TMatch (e1,en,cases,def) }
  716. | _ ->
  717. e
  718. let reduce_expr ctx e =
  719. match e.eexpr with
  720. | TSwitch (_,cases,_) ->
  721. List.iter (fun (cl,_) ->
  722. List.iter (fun e ->
  723. match e.eexpr with
  724. | TCall ({ eexpr = TField (_,FEnum _) },_) -> error "Not-constant enum in switch cannot be matched" e.epos
  725. | _ -> ()
  726. ) cl
  727. ) cases;
  728. e
  729. | TBlock l ->
  730. (match List.rev l with
  731. | [] -> e
  732. | ec :: l ->
  733. (* remove all no-ops : not-final constants in blocks *)
  734. match List.filter (fun e -> match e.eexpr with
  735. | TConst _
  736. | TBlock []
  737. | TObjectDecl [] ->
  738. false
  739. | _ ->
  740. true
  741. ) l with
  742. | [] -> { ec with epos = e.epos }
  743. | l -> { e with eexpr = TBlock (List.rev (ec :: l)) })
  744. | TParenthesis ec ->
  745. { ec with epos = e.epos }
  746. | TTry (e,[]) ->
  747. e
  748. | _ ->
  749. e
  750. let rec sanitize ctx e =
  751. sanitize_expr ctx.com (reduce_expr ctx (Type.map_expr (sanitize ctx) e))
  752. (* ---------------------------------------------------------------------- *)
  753. (* REDUCE *)
  754. let rec reduce_loop ctx e =
  755. let is_float t =
  756. match follow t with
  757. | TAbstract({ a_path = [],"Float" },_) -> true
  758. | _ -> false
  759. in
  760. let is_numeric t =
  761. match follow t with
  762. | TAbstract({ a_path = [],("Float"|"Int") },_) -> true
  763. | _ -> false
  764. in
  765. let e = Type.map_expr (reduce_loop ctx) e in
  766. let check_float op f1 f2 =
  767. let f = op f1 f2 in
  768. let fstr = string_of_float f in
  769. if (match classify_float f with FP_nan | FP_infinite -> false | _ -> float_of_string fstr = f) then { e with eexpr = TConst (TFloat fstr) } else e
  770. in
  771. sanitize_expr ctx.com (match e.eexpr with
  772. | TIf ({ eexpr = TConst (TBool t) },e1,e2) ->
  773. (if t then e1 else match e2 with None -> { e with eexpr = TBlock [] } | Some e -> e)
  774. | TWhile ({ eexpr = TConst (TBool false) },sub,flag) ->
  775. (match flag with
  776. | NormalWhile -> { e with eexpr = TBlock [] } (* erase sub *)
  777. | DoWhile -> e) (* we cant remove while since sub can contain continue/break *)
  778. | TBinop (op,e1,e2) ->
  779. (match e1.eexpr, e2.eexpr with
  780. | TConst (TInt 0l) , _ when op = OpAdd && is_numeric e2.etype -> e2
  781. | TConst (TInt 1l) , _ when op = OpMult -> e2
  782. | TConst (TFloat v) , _ when op = OpAdd && float_of_string v = 0. && is_float e2.etype -> e2
  783. | TConst (TFloat v) , _ when op = OpMult && float_of_string v = 1. && is_float e2.etype -> e2
  784. | _ , TConst (TInt 0l) when (match op with OpAdd -> is_numeric e1.etype | OpSub | OpShr | OpShl -> true | _ -> false) -> e1 (* bits operations might cause overflow *)
  785. | _ , TConst (TInt 1l) when op = OpMult -> e1
  786. | _ , TConst (TFloat v) when (match op with OpAdd | OpSub -> float_of_string v = 0. && is_float e1.etype | _ -> false) -> e1 (* bits operations might cause overflow *)
  787. | _ , TConst (TFloat v) when op = OpMult && float_of_string v = 1. && is_float e1.etype -> e1
  788. | TConst TNull, TConst TNull ->
  789. (match op with
  790. | OpEq -> { e with eexpr = TConst (TBool true) }
  791. | OpNotEq -> { e with eexpr = TConst (TBool false) }
  792. | _ -> e)
  793. | TConst (TInt a), TConst (TInt b) ->
  794. let opt f = try { e with eexpr = TConst (TInt (f a b)) } with Exit -> e in
  795. let check_overflow f =
  796. opt (fun a b ->
  797. let v = f (Int64.of_int32 a) (Int64.of_int32 b) in
  798. let iv = Int64.to_int32 v in
  799. if Int64.compare (Int64.of_int32 iv) v <> 0 then raise Exit;
  800. iv
  801. )
  802. in
  803. let ebool t =
  804. { e with eexpr = TConst (TBool (t (Int32.compare a b) 0)) }
  805. in
  806. (match op with
  807. | OpAdd -> check_overflow Int64.add
  808. | OpSub -> check_overflow Int64.sub
  809. | OpMult -> check_overflow Int64.mul
  810. | OpDiv -> check_float ( /. ) (Int32.to_float a) (Int32.to_float b)
  811. | OpAnd -> opt Int32.logand
  812. | OpOr -> opt Int32.logor
  813. | OpXor -> opt Int32.logxor
  814. | OpShl -> opt (fun a b -> Int32.shift_left a (Int32.to_int b))
  815. | OpShr -> opt (fun a b -> Int32.shift_right a (Int32.to_int b))
  816. | OpUShr -> opt (fun a b -> Int32.shift_right_logical a (Int32.to_int b))
  817. | OpEq -> ebool (=)
  818. | OpNotEq -> ebool (<>)
  819. | OpGt -> ebool (>)
  820. | OpGte -> ebool (>=)
  821. | OpLt -> ebool (<)
  822. | OpLte -> ebool (<=)
  823. | _ -> e)
  824. | TConst ((TFloat _ | TInt _) as ca), TConst ((TFloat _ | TInt _) as cb) ->
  825. let fa = (match ca with
  826. | TFloat a -> float_of_string a
  827. | TInt a -> Int32.to_float a
  828. | _ -> assert false
  829. ) in
  830. let fb = (match cb with
  831. | TFloat b -> float_of_string b
  832. | TInt b -> Int32.to_float b
  833. | _ -> assert false
  834. ) in
  835. let fop op = check_float op fa fb in
  836. let ebool t =
  837. { e with eexpr = TConst (TBool (t (compare fa fb) 0)) }
  838. in
  839. (match op with
  840. | OpAdd -> fop (+.)
  841. | OpDiv -> fop (/.)
  842. | OpSub -> fop (-.)
  843. | OpMult -> fop ( *. )
  844. | OpEq -> ebool (=)
  845. | OpNotEq -> ebool (<>)
  846. | OpGt -> ebool (>)
  847. | OpGte -> ebool (>=)
  848. | OpLt -> ebool (<)
  849. | OpLte -> ebool (<=)
  850. | _ -> e)
  851. | TConst (TBool a), TConst (TBool b) ->
  852. let ebool f =
  853. { e with eexpr = TConst (TBool (f a b)) }
  854. in
  855. (match op with
  856. | OpEq -> ebool (=)
  857. | OpNotEq -> ebool (<>)
  858. | OpBoolAnd -> ebool (&&)
  859. | OpBoolOr -> ebool (||)
  860. | _ -> e)
  861. | TConst a, TConst b when op = OpEq || op = OpNotEq ->
  862. let ebool b =
  863. { e with eexpr = TConst (TBool (if op = OpEq then b else not b)) }
  864. in
  865. (match a, b with
  866. | TInt a, TFloat b | TFloat b, TInt a -> ebool (Int32.to_float a = float_of_string b)
  867. | _ -> ebool (a = b))
  868. | TConst (TBool a), _ ->
  869. (match op with
  870. | OpBoolAnd -> if a then e2 else { e with eexpr = TConst (TBool false) }
  871. | OpBoolOr -> if a then { e with eexpr = TConst (TBool true) } else e2
  872. | _ -> e)
  873. | _ , TConst (TBool a) ->
  874. (match op with
  875. | OpBoolAnd when a -> e1
  876. | OpBoolOr when not a -> e1
  877. | _ -> e)
  878. | TField (_,FEnum (e1,f1)), TField (_,FEnum (e2,f2)) when e1 == e2 ->
  879. (match op with
  880. | OpEq -> { e with eexpr = TConst (TBool (f1 == f2)) }
  881. | OpNotEq -> { e with eexpr = TConst (TBool (f1 != f2)) }
  882. | _ -> e)
  883. | _, TCall ({ eexpr = TField (_,FEnum _) },_) | TCall ({ eexpr = TField (_,FEnum _) },_), _ ->
  884. (match op with
  885. | OpAssign -> e
  886. | _ ->
  887. error "You cannot directly compare enums with arguments. Use either 'switch' or 'Type.enumEq'" e.epos)
  888. | _ ->
  889. e)
  890. | TUnop (op,flag,esub) ->
  891. (match op, esub.eexpr with
  892. | Not, TConst (TBool f) -> { e with eexpr = TConst (TBool (not f)) }
  893. | Neg, TConst (TInt i) -> { e with eexpr = TConst (TInt (Int32.neg i)) }
  894. | NegBits, TConst (TInt i) -> { e with eexpr = TConst (TInt (Int32.lognot i)) }
  895. | Neg, TConst (TFloat f) ->
  896. let v = 0. -. float_of_string f in
  897. let vstr = string_of_float v in
  898. if float_of_string vstr = v then
  899. { e with eexpr = TConst (TFloat vstr) }
  900. else
  901. e
  902. | _ -> e
  903. )
  904. | TCall ({ eexpr = TField ({ eexpr = TTypeExpr (TClassDecl c) },field) },params) ->
  905. (match api_inline ctx c (field_name field) params e.epos with
  906. | None -> reduce_expr ctx e
  907. | Some e -> reduce_loop ctx e)
  908. | TCall ({ eexpr = TFunction func } as ef,el) ->
  909. let cf = mk_field "" ef.etype e.epos in
  910. let ethis = mk (TConst TThis) t_dynamic e.epos in
  911. let rt = (match follow ef.etype with TFun (_,rt) -> rt | _ -> assert false) in
  912. let inl = (try type_inline ctx cf func ethis el rt None e.epos false with Error (Custom _,_) -> None) in
  913. (match inl with
  914. | None -> reduce_expr ctx e
  915. | Some e -> reduce_loop ctx e)
  916. | TCall ({ eexpr = TField (o,FClosure (c,cf)) } as f,el) ->
  917. let fmode = (match c with None -> FAnon cf | Some c -> FInstance (c,cf)) in
  918. { e with eexpr = TCall ({ f with eexpr = TField (o,fmode) },el) }
  919. | _ ->
  920. reduce_expr ctx e)
  921. let reduce_expression ctx e =
  922. if ctx.com.foptimize then reduce_loop ctx e else e
  923. let rec make_constant_expression ctx ?(concat_strings=false) e =
  924. let e = reduce_loop ctx e in
  925. match e.eexpr with
  926. | TConst _ -> Some e
  927. | TBinop ((OpAdd|OpSub|OpMult|OpDiv|OpMod) as op,e1,e2) -> (match make_constant_expression ctx e1,make_constant_expression ctx e2 with
  928. | Some ({eexpr = TConst (TString s1)}), Some ({eexpr = TConst (TString s2)}) when concat_strings ->
  929. Some (mk (TConst (TString (s1 ^ s2))) ctx.com.basic.tstring (punion e1.epos e2.epos))
  930. | Some e1, Some e2 -> Some (mk (TBinop(op, e1, e2)) e.etype e.epos)
  931. | _ -> None)
  932. | TParenthesis e -> Some e
  933. | TTypeExpr _ -> Some e
  934. (* try to inline static function calls *)
  935. | TCall ({ etype = TFun(_,ret); eexpr = TField (_,FStatic (c,cf)) },el) ->
  936. (try
  937. let func = match cf.cf_expr with Some ({eexpr = TFunction func}) -> func | _ -> raise Not_found in
  938. let ethis = mk (TConst TThis) t_dynamic e.epos in
  939. let inl = (try type_inline ctx cf func ethis el ret None e.epos false with Error (Custom _,_) -> None) in
  940. (match inl with
  941. | None -> None
  942. | Some e -> make_constant_expression ctx e)
  943. with Not_found -> None)
  944. | _ -> None
  945. (* ---------------------------------------------------------------------- *)
  946. (* INLINE CONSTRUCTORS *)
  947. (*
  948. First pass :
  949. We will look at local variables in the form var v = new ....
  950. we only capture the ones which have constructors marked as inlined
  951. then we make sure that these locals are no more referenced except for fields accesses
  952. Second pass :
  953. We replace the variables by their fields lists, and the corresponding fields accesses as well
  954. *)
  955. let inline_constructors ctx e =
  956. let vars = ref PMap.empty in
  957. let rec find_locals e =
  958. match e.eexpr with
  959. | TVars vl ->
  960. Type.iter find_locals e;
  961. List.iter (fun (v,e) ->
  962. match e with
  963. | Some ({ eexpr = TNew ({ cl_constructor = Some ({ cf_kind = Method MethInline; cf_expr = Some { eexpr = TFunction f } } as cst) } as c,_,pl) } as n) ->
  964. (* inline the constructor *)
  965. (match (try type_inline ctx cst f (mk (TLocal v) v.v_type n.epos) pl ctx.t.tvoid None n.epos true with Error (Custom _,_) -> None) with
  966. | None -> ()
  967. | Some ecst ->
  968. let assigns = ref [] in
  969. (* make sure we only have v.field = expr calls *)
  970. let rec get_assigns e =
  971. match e.eexpr with
  972. | TBlock el ->
  973. List.iter get_assigns el
  974. | TBinop (OpAssign, { eexpr = TField ({ eexpr = TLocal vv },FInstance(_,cf)); etype = t }, e) when v == vv ->
  975. assigns := (cf.cf_name,e,t) :: !assigns
  976. | _ ->
  977. raise Exit
  978. in
  979. try
  980. get_assigns ecst;
  981. (* mark variable as candidate for inlining *)
  982. vars := PMap.add v.v_id (v,List.rev !assigns,c.cl_extern || Meta.has Meta.Extern cst.cf_meta,n.epos) !vars;
  983. v.v_id <- -v.v_id; (* mark *)
  984. (* recurse with the constructor code which will be inlined here *)
  985. find_locals ecst
  986. with Exit ->
  987. ())
  988. | _ -> ()
  989. ) vl
  990. | TField ({ eexpr = TLocal _ },FInstance (_,{ cf_kind = Var _ })) ->
  991. ()
  992. | TLocal v when v.v_id < 0 ->
  993. v.v_id <- -v.v_id;
  994. (* error if the constructor is extern *)
  995. (match PMap.find v.v_id !vars with
  996. | _,_,true,p ->
  997. display_error ctx "Extern constructor could not be inlined" p;
  998. error "Variable is used here" e.epos
  999. | _ -> ());
  1000. vars := PMap.remove v.v_id !vars;
  1001. | _ ->
  1002. Type.iter find_locals e
  1003. in
  1004. find_locals e;
  1005. let vars = !vars in
  1006. if PMap.is_empty vars then
  1007. e
  1008. else begin
  1009. let vfields = PMap.map (fun (v,assigns,_,_) ->
  1010. List.fold_left (fun (acc,map) (name,e,t) ->
  1011. let vf = alloc_var (v.v_name ^ "_" ^ name) t in
  1012. ((vf,e) :: acc, PMap.add name vf map)
  1013. ) ([],PMap.empty) assigns
  1014. ) vars in
  1015. let rec subst e =
  1016. match e.eexpr with
  1017. | TVars vl ->
  1018. let rec loop acc vl =
  1019. match vl with
  1020. | [] -> List.rev acc
  1021. | (v,None) :: vl -> loop ((v,None) :: acc) vl
  1022. | (v,Some e) :: vl when v.v_id < 0 ->
  1023. let vars, _ = PMap.find (-v.v_id) vfields in
  1024. loop (List.map (fun (v,e) -> v, Some (subst e)) vars @ acc) vl
  1025. | (v,Some e) :: vl ->
  1026. loop ((v,Some (subst e)) :: acc) vl
  1027. in
  1028. let vl = loop [] vl in
  1029. mk (TVars vl) e.etype e.epos
  1030. | TField ({ eexpr = TLocal v },FInstance (_,cf)) when v.v_id < 0 ->
  1031. let _, vars = PMap.find (-v.v_id) vfields in
  1032. (try
  1033. let v = PMap.find cf.cf_name vars in
  1034. mk (TLocal v) v.v_type e.epos
  1035. with Not_found ->
  1036. (* the variable was not set in the constructor, assume null *)
  1037. mk (TConst TNull) e.etype e.epos)
  1038. | _ ->
  1039. Type.map_expr subst e
  1040. in
  1041. let e = (try subst e with Not_found -> assert false) in
  1042. PMap.iter (fun _ (v,_,_,_) -> v.v_id <- -v.v_id) vars;
  1043. e
  1044. end
  1045. (* ---------------------------------------------------------------------- *)
  1046. (* COMPLETION *)
  1047. exception Return of Ast.expr
  1048. type compl_locals = {
  1049. mutable r : (string, (complex_type option * (int * Ast.expr * compl_locals) option)) PMap.t;
  1050. }
  1051. let optimize_completion_expr e =
  1052. let iid = ref 0 in
  1053. let typing_side_effect = ref false in
  1054. let locals : compl_locals = { r = PMap.empty } in
  1055. let save() = let old = locals.r in (fun() -> locals.r <- old) in
  1056. let get_local n = PMap.find n locals.r in
  1057. let maybe_typed e =
  1058. match fst e with
  1059. | EConst (Ident "null") -> false
  1060. | _ -> true
  1061. in
  1062. let decl n t e =
  1063. typing_side_effect := true;
  1064. locals.r <- PMap.add n (t,(match e with Some e when maybe_typed e -> incr iid; Some (!iid,e,{ r = locals.r }) | _ -> None)) locals.r
  1065. in
  1066. let rec loop e =
  1067. let p = snd e in
  1068. match fst e with
  1069. | EConst (Ident n) ->
  1070. (try
  1071. (match get_local n with
  1072. | Some _ , _ -> ()
  1073. | _ -> typing_side_effect := true)
  1074. with Not_found ->
  1075. ());
  1076. e
  1077. | EBinop (OpAssign,(EConst (Ident n),_),esub) ->
  1078. (try
  1079. (match get_local n with
  1080. | None, None when maybe_typed esub -> decl n None (Some esub)
  1081. | _ -> ())
  1082. with Not_found ->
  1083. ());
  1084. map e
  1085. | EVars vl ->
  1086. let vl = List.map (fun (v,t,e) ->
  1087. let e = (match e with None -> None | Some e -> Some (loop e)) in
  1088. decl v t e;
  1089. (v,t,e)
  1090. ) vl in
  1091. (EVars vl,p)
  1092. | EBlock el ->
  1093. let old = save() in
  1094. let told = ref (!typing_side_effect) in
  1095. let el = List.fold_left (fun acc e ->
  1096. typing_side_effect := false;
  1097. let e = loop e in
  1098. if !typing_side_effect then begin told := true; e :: acc end else acc
  1099. ) [] el in
  1100. old();
  1101. typing_side_effect := !told;
  1102. (EBlock (List.rev el),p)
  1103. | EFunction (v,f) ->
  1104. (match v with
  1105. | None -> ()
  1106. | Some name ->
  1107. decl name None (Some e));
  1108. let old = save() in
  1109. List.iter (fun (n,_,t,e) -> decl n t e) f.f_args;
  1110. let e = map e in
  1111. old();
  1112. e
  1113. | EFor ((EIn ((EConst (Ident n),_) as id,it),p),efor) ->
  1114. let it = loop it in
  1115. let old = save() in
  1116. let etmp = (EConst (Ident "$tmp"),p) in
  1117. decl n None (Some (EBlock [
  1118. (EVars ["$tmp",None,None],p);
  1119. (EFor ((EIn (id,it),p),(EBinop (OpAssign,etmp,(EConst (Ident n),p)),p)),p);
  1120. etmp
  1121. ],p));
  1122. let efor = loop efor in
  1123. old();
  1124. (EFor ((EIn (id,it),p),efor),p)
  1125. | EReturn _ ->
  1126. typing_side_effect := true;
  1127. map e
  1128. | ESwitch (e,cases,def) ->
  1129. let e = loop e in
  1130. let cases = List.map (fun (el,eg,eo) -> match eo with
  1131. | None ->
  1132. el,eg,eo
  1133. | Some e ->
  1134. let el = List.map loop el in
  1135. let old = save() in
  1136. List.iter (fun e ->
  1137. match fst e with
  1138. | ECall (_,pl) ->
  1139. List.iter (fun p ->
  1140. match fst p with
  1141. | EConst (Ident i) -> decl i None None (* sadly *)
  1142. | _ -> ()
  1143. ) pl
  1144. | _ -> ()
  1145. ) el;
  1146. let e = loop e in
  1147. old();
  1148. el, eg, Some e
  1149. ) cases in
  1150. let def = match def with
  1151. | None -> None
  1152. | Some None -> Some None
  1153. | Some (Some e) -> Some (Some (loop e))
  1154. in
  1155. (ESwitch (e,cases,def),p)
  1156. | ETry (et,cl) ->
  1157. let et = loop et in
  1158. let cl = List.map (fun (n,t,e) ->
  1159. let old = save() in
  1160. decl n (Some t) None;
  1161. let e = loop e in
  1162. old();
  1163. n, t, e
  1164. ) cl in
  1165. (ETry (et,cl),p)
  1166. | EDisplay (s,call) ->
  1167. typing_side_effect := true;
  1168. let tmp_locals = ref [] in
  1169. let tmp_hlocals = ref PMap.empty in
  1170. let rec subst_locals locals e =
  1171. match fst e with
  1172. | EConst (Ident n) ->
  1173. let p = snd e in
  1174. (try
  1175. (match PMap.find n locals.r with
  1176. | Some t , _ -> (ECheckType ((EConst (Ident "null"),p),t),p)
  1177. | _, Some (id,e,lc) ->
  1178. let name = (try
  1179. PMap.find id (!tmp_hlocals)
  1180. with Not_found ->
  1181. let e = subst_locals lc e in
  1182. let name = "$tmp_" ^ string_of_int id in
  1183. tmp_locals := (name,None,Some e) :: !tmp_locals;
  1184. tmp_hlocals := PMap.add id name !tmp_hlocals;
  1185. name
  1186. ) in
  1187. (EConst (Ident name),p)
  1188. | None, None ->
  1189. (* we can't replace the var *)
  1190. raise Exit)
  1191. with Not_found ->
  1192. (* not found locals are most likely to be member/static vars *)
  1193. e)
  1194. | _ ->
  1195. Ast.map_expr (subst_locals locals) e
  1196. in
  1197. (try
  1198. let e = subst_locals locals s in
  1199. let e = (EBlock [(EVars (List.rev !tmp_locals),p);(EDisplay (e,call),p)],p) in
  1200. raise (Return e)
  1201. with Exit ->
  1202. map e)
  1203. | EDisplayNew _ ->
  1204. raise (Return e)
  1205. | _ ->
  1206. map e
  1207. and map e =
  1208. Ast.map_expr loop e
  1209. in
  1210. (try loop e with Return e -> e)
  1211. (* ---------------------------------------------------------------------- *)