as3hlparse.ml 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923
  1. (*
  2. * This file is part of SwfLib
  3. * Copyright (c)2004-2008 Nicolas Cannasse
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program 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
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  18. *)
  19. open Extlib_leftovers
  20. open As3
  21. open As3hl
  22. type parse_ctx = {
  23. as3 : as3_tag;
  24. mutable namespaces : hl_namespace array;
  25. mutable nsets : hl_ns_set array;
  26. mutable names : hl_name array;
  27. mutable methods : hl_method array;
  28. mutable classes : hl_class array;
  29. mutable jumps : (int * int) list;
  30. mutable pos : int;
  31. delta_mt : int;
  32. delta_cl : int;
  33. }
  34. let get = As3parse.iget
  35. let no_nz = As3parse.no_nz
  36. let idx n = As3parse.index_int n - 1
  37. let ident ctx i = get ctx.as3.as3_idents i
  38. let name ctx n = ctx.names.(idx n)
  39. let method_type ctx n = ctx.methods.(idx (no_nz n))
  40. let getclass ctx n = ctx.classes.(idx (no_nz n))
  41. let opt f ctx = function
  42. | None -> None
  43. | Some x -> Some (f ctx x)
  44. let stack_delta = function
  45. | HBreakPoint -> 0
  46. | HNop -> 0
  47. | HThrow -> -1
  48. | HGetSuper _ -> 0
  49. | HSetSuper _ -> -2
  50. | HDxNs _ -> 0
  51. | HDxNsLate -> -1
  52. | HRegKill _ -> 0
  53. | HLabel -> 0
  54. | HJump (cond,_) ->
  55. (match cond with
  56. | J3Always -> 0
  57. | J3True
  58. | J3False -> -1
  59. | _ -> -2)
  60. | HSwitch _ -> -1
  61. | HPushWith -> -1
  62. | HPopScope -> 0
  63. | HForIn -> -1
  64. | HHasNext -> -1
  65. | HNull
  66. | HUndefined -> 1
  67. | HForEach -> -1
  68. | HSmallInt _
  69. | HInt _
  70. | HTrue
  71. | HFalse
  72. | HString _
  73. | HIntRef _
  74. | HUIntRef _
  75. | HFunction _
  76. | HFloat _
  77. | HNaN -> 1
  78. | HPop -> -1
  79. | HDup -> 1
  80. | HSwap -> 0
  81. | HScope -> -1
  82. | HNamespace _ -> 1
  83. | HNext _ -> 1
  84. | HCallStack n -> -(n + 1)
  85. | HConstruct n -> -n
  86. | HCallMethod (_,n) -> -n
  87. | HCallStatic (_,n) -> -n
  88. | HCallSuper (_,n) -> -n
  89. | HCallProperty (_,n) -> -n
  90. | HRetVoid -> 0
  91. | HRet -> -1
  92. | HConstructSuper n -> -(n + 1)
  93. | HConstructProperty (_,n) -> -n
  94. | HCallPropLex (_,n) -> -n
  95. | HCallSuperVoid (_,n) -> -(n + 1)
  96. | HCallPropVoid (_,n) -> -(n + 1)
  97. | HApplyType n -> -n
  98. | HObject n -> -(n * 2) + 1
  99. | HArray n -> -n + 1
  100. | HNewBlock -> 1
  101. | HClassDef _ -> 0
  102. | HGetDescendants _ -> 0
  103. | HCatch _ -> 1
  104. | HFindPropStrict _ -> 1
  105. | HFindProp _ -> 1
  106. | HFindDefinition _ -> 1
  107. | HGetLex _ -> 1
  108. | HSetProp _ -> -2
  109. | HReg _ -> 1
  110. | HSetReg _ | HSetThis -> -1
  111. | HGetGlobalScope | HGetScope _ -> 1
  112. | HGetProp _ -> 0
  113. | HInitProp _ -> -2
  114. | HDeleteProp _ -> -1 (* true/false *)
  115. | HGetSlot _ -> 0
  116. | HSetSlot _ -> -2
  117. | HToString
  118. | HToXml
  119. | HToXmlAttr
  120. | HToInt
  121. | HToUInt
  122. | HToNumber
  123. | HToObject
  124. | HAsAny
  125. | HAsType _
  126. | HIsType _
  127. | HAsObject
  128. | HAsString
  129. | HToBool -> 0
  130. | HCheckIsXml -> 0
  131. | HCast _ -> 0
  132. | HTypeof -> 0
  133. | HInstanceOf -> -1
  134. | HIncrReg _ | HDecrReg _ | HIncrIReg _ | HDecrIReg _ -> 0
  135. | HThis -> 1
  136. | HDebugReg _
  137. | HDebugLine _
  138. | HBreakPointLine _
  139. | HTimestamp
  140. | HDebugFile _ -> 0
  141. | HOp op ->
  142. (match op with
  143. | A3ONeg | A3OINeg | A3OIncr | A3ODecr | A3ONot | A3OBitNot | A3OIIncr | A3OIDecr -> 0
  144. | A3OMemGet8 | A3OMemGet16 | A3OMemGet32 | A3OMemGetFloat | A3OMemGetDouble | A3OSign1 | A3OSign8 | A3OSign16 -> 0
  145. | A3OMemSet8 | A3OMemSet16 | A3OMemSet32 | A3OMemSetFloat | A3OMemSetDouble -> -2
  146. | _ -> -1)
  147. | HUnk _ -> assert false
  148. let parse_opcode ctx i = function
  149. | A3BreakPoint -> HBreakPoint
  150. | A3Nop -> HNop
  151. | A3Throw -> HThrow
  152. | A3GetSuper n -> HGetSuper (name ctx n)
  153. | A3SetSuper n -> HSetSuper (name ctx n)
  154. | A3DxNs s -> HDxNs (ident ctx s)
  155. | A3DxNsLate -> HDxNsLate
  156. | A3RegKill r -> HRegKill r
  157. | A3Label -> HLabel
  158. | A3Jump (j,n) ->
  159. ctx.jumps <- (i,ctx.pos) :: ctx.jumps;
  160. HJump (j,n)
  161. | A3Switch (n,infos) as op ->
  162. ctx.jumps <- (i,ctx.pos - As3code.length op) :: ctx.jumps;
  163. HSwitch(n,infos)
  164. | A3PushWith -> HPushWith
  165. | A3PopScope -> HPopScope
  166. | A3ForIn -> HForIn
  167. | A3HasNext -> HHasNext
  168. | A3Null -> HNull
  169. | A3Undefined -> HUndefined
  170. | A3ForEach -> HForEach
  171. | A3SmallInt n -> HSmallInt n
  172. | A3Int n -> HInt n
  173. | A3True -> HTrue
  174. | A3False -> HFalse
  175. | A3NaN -> HNaN
  176. | A3Pop -> HPop
  177. | A3Dup -> HDup
  178. | A3Swap -> HSwap
  179. | A3String i -> HString (ident ctx i)
  180. | A3IntRef i -> HIntRef (get ctx.as3.as3_ints i)
  181. | A3UIntRef i -> HUIntRef (get ctx.as3.as3_uints i)
  182. | A3Float f -> HFloat (get ctx.as3.as3_floats f)
  183. | A3Scope -> HScope
  184. | A3Namespace n -> HNamespace ctx.namespaces.(idx n)
  185. | A3Next (r1,r2) -> HNext (r1,r2)
  186. | A3Function f -> HFunction (method_type ctx f)
  187. | A3CallStack n -> HCallStack n
  188. | A3Construct n -> HConstruct n
  189. | A3CallMethod (s,n) -> HCallMethod (s,n)
  190. | A3CallStatic (m,n) -> HCallStatic (ctx.methods.(idx m),n)
  191. | A3CallSuper (p,n) -> HCallSuper (name ctx p,n)
  192. | A3CallProperty (p,n) -> HCallProperty (name ctx p,n)
  193. | A3RetVoid -> HRetVoid
  194. | A3Ret -> HRet
  195. | A3ConstructSuper n -> HConstructSuper n
  196. | A3ConstructProperty (p,n) -> HConstructProperty (name ctx p,n)
  197. | A3CallPropLex (p,n) -> HCallPropLex (name ctx p,n)
  198. | A3CallSuperVoid (p,n) -> HCallSuperVoid (name ctx p,n)
  199. | A3CallPropVoid (p,n) -> HCallPropVoid (name ctx p,n)
  200. | A3ApplyType n -> HApplyType n
  201. | A3Object n -> HObject n
  202. | A3Array n -> HArray n
  203. | A3NewBlock -> HNewBlock
  204. | A3ClassDef n -> HClassDef (getclass ctx n)
  205. | A3GetDescendants p -> HGetDescendants (name ctx p)
  206. | A3Catch n -> HCatch n
  207. | A3FindPropStrict p -> HFindPropStrict (name ctx p)
  208. | A3FindProp p -> HFindProp (name ctx p)
  209. | A3FindDefinition p -> HFindDefinition (name ctx p)
  210. | A3GetLex p -> HGetLex (name ctx p)
  211. | A3SetProp p -> HSetProp (name ctx p)
  212. | A3Reg r -> HReg r
  213. | A3SetReg r -> HSetReg r
  214. | A3GetGlobalScope -> HGetGlobalScope
  215. | A3GetScope n -> HGetScope n
  216. | A3GetProp p -> HGetProp (name ctx p)
  217. | A3InitProp p -> HInitProp (name ctx p)
  218. | A3DeleteProp p -> HDeleteProp (name ctx p)
  219. | A3GetSlot n -> HGetSlot n
  220. | A3SetSlot n -> HSetSlot n
  221. | A3ToString -> HToString
  222. | A3ToXml -> HToXml
  223. | A3ToXmlAttr -> HToXmlAttr
  224. | A3ToInt -> HToInt
  225. | A3ToUInt -> HToUInt
  226. | A3ToNumber -> HToNumber
  227. | A3ToBool -> HToBool
  228. | A3ToObject -> HToObject
  229. | A3CheckIsXml -> HCheckIsXml
  230. | A3Cast p -> HCast (name ctx p)
  231. | A3AsAny -> HAsAny
  232. | A3AsString -> HAsString
  233. | A3AsType p -> HAsType (name ctx p)
  234. | A3AsObject -> HAsObject
  235. | A3IncrReg r -> HIncrReg r
  236. | A3DecrReg r -> HDecrReg r
  237. | A3Typeof -> HTypeof
  238. | A3InstanceOf -> HInstanceOf
  239. | A3IsType p -> HIsType (name ctx p)
  240. | A3IncrIReg r -> HIncrIReg r
  241. | A3DecrIReg r -> HDecrIReg r
  242. | A3This -> HThis
  243. | A3SetThis -> HSetThis
  244. | A3DebugReg (id,r,n) -> HDebugReg (ident ctx id,r,n)
  245. | A3DebugLine n -> HDebugLine n
  246. | A3DebugFile p -> HDebugFile (ident ctx p)
  247. | A3BreakPointLine n -> HBreakPointLine n
  248. | A3Timestamp -> HTimestamp
  249. | A3Op op -> HOp op
  250. | A3Unk n -> HUnk n
  251. let parse_code ctx f trys =
  252. let code = f.fun3_code in
  253. let old = ctx.pos , ctx.jumps in
  254. let indexes = MultiArray.create() in
  255. ctx.pos <- 0;
  256. ctx.jumps <- [];
  257. let codepos pos delta =
  258. let id = (try MultiArray.get indexes (pos + delta) with _ -> -1) in
  259. if id = -1 then begin
  260. (*Printf.eprintf "MISALIGNED JUMP AT %d %c %d IN #%d\n" pos (if delta < 0 then '-' else '+') (if delta < 0 then -delta else delta) (idx (no_nz f.fun3_id));*)
  261. MultiArray.get indexes pos; (* jump 0 *)
  262. end else
  263. id
  264. in
  265. let hcode = MultiArray.mapi (fun i op ->
  266. let len = As3code.length op in
  267. MultiArray.add indexes i;
  268. for k = 2 to len do MultiArray.add indexes (-1); done;
  269. ctx.pos <- ctx.pos + len;
  270. parse_opcode ctx i op
  271. ) code in
  272. (* in case we have a dead-jump at the end of code *)
  273. MultiArray.add indexes (MultiArray.length code);
  274. (* patch jumps *)
  275. List.iter (fun (j,pos) ->
  276. MultiArray.set hcode j (match MultiArray.get hcode j with
  277. | HJump (jc,n) ->
  278. HJump (jc,codepos pos n - j)
  279. | HSwitch (n,infos) ->
  280. HSwitch (codepos pos n - j, List.map (fun n -> codepos pos n - j) infos)
  281. | _ -> assert false)
  282. ) ctx.jumps;
  283. (* patch try/catches *)
  284. Array.iteri (fun i t ->
  285. Array.set trys i {
  286. hltc_start = codepos 0 t.hltc_start;
  287. hltc_end = codepos 0 t.hltc_end;
  288. hltc_handle = codepos 0 t.hltc_handle;
  289. hltc_type = t.hltc_type;
  290. hltc_name = t.hltc_name;
  291. }
  292. ) trys;
  293. ctx.pos <- fst old;
  294. ctx.jumps <- snd old;
  295. hcode
  296. let parse_metadata ctx m =
  297. {
  298. hlmeta_name = ident ctx m.meta3_name;
  299. hlmeta_data = Array.map (fun (i1,i2) -> opt ident ctx i1, ident ctx i2) m.meta3_data;
  300. }
  301. let parse_method ctx m =
  302. {
  303. hlm_type = method_type ctx m.m3_type;
  304. hlm_final = m.m3_final;
  305. hlm_override = m.m3_override;
  306. hlm_kind = m.m3_kind;
  307. }
  308. let parse_value ctx = function
  309. | A3VNone -> HVNone
  310. | A3VNull -> HVNull
  311. | A3VBool b -> HVBool b
  312. | A3VString s -> HVString (ident ctx s)
  313. | A3VInt i -> HVInt (get ctx.as3.as3_ints i)
  314. | A3VUInt i -> HVUInt (get ctx.as3.as3_uints i)
  315. | A3VFloat f -> HVFloat (get ctx.as3.as3_floats f)
  316. | A3VNamespace (n,ns) -> HVNamespace (n,ctx.namespaces.(idx ns))
  317. let parse_var ctx v =
  318. {
  319. hlv_type = opt name ctx v.v3_type;
  320. hlv_value = parse_value ctx v.v3_value;
  321. hlv_const = v.v3_const;
  322. }
  323. let parse_field_kind ctx = function
  324. | A3FMethod m -> HFMethod (parse_method ctx m)
  325. | A3FVar v -> HFVar (parse_var ctx v)
  326. | A3FFunction f -> HFFunction (method_type ctx f)
  327. | A3FClass c -> HFClass (getclass ctx c)
  328. let parse_field ctx f =
  329. {
  330. hlf_name = name ctx f.f3_name;
  331. hlf_slot = f.f3_slot;
  332. hlf_kind = parse_field_kind ctx f.f3_kind;
  333. hlf_metas =
  334. match f.f3_metas with
  335. | None -> None
  336. | Some a ->
  337. Some (Array.map (fun i ->
  338. parse_metadata ctx (get ctx.as3.as3_metadatas (no_nz i))
  339. ) a);
  340. }
  341. let parse_static ctx s =
  342. {
  343. hls_method = method_type ctx s.st3_method;
  344. hls_fields = Array.map (parse_field ctx) s.st3_fields;
  345. }
  346. let parse_namespace ctx = function
  347. | A3NPrivate id -> HNPrivate (opt ident ctx id)
  348. | A3NPublic id -> HNPublic (opt ident ctx id)
  349. | A3NInternal id -> HNInternal (opt ident ctx id)
  350. | A3NProtected id -> HNProtected (ident ctx id)
  351. | A3NNamespace id -> HNNamespace (ident ctx id)
  352. | A3NExplicit id -> HNExplicit (ident ctx id)
  353. | A3NStaticProtected id -> HNStaticProtected (opt ident ctx id)
  354. let parse_nset ctx l = List.map (fun n -> ctx.namespaces.(idx n)) l
  355. let rec parse_name names ctx = function
  356. | A3MName (id,ns) ->
  357. (match ctx.namespaces.(idx ns) with
  358. | HNPublic p ->
  359. let pack = (match p with None -> [] | Some i -> ExtString.String.nsplit i ".") in
  360. HMPath (pack, ident ctx id)
  361. | ns ->
  362. HMName (ident ctx id, ns))
  363. | A3MNSAny (id) -> HMNSAny(ident ctx id)
  364. | A3MAny -> HMAny
  365. | A3MMultiName (id,ns) -> HMMultiName (opt ident ctx id,ctx.nsets.(idx ns))
  366. | A3MRuntimeName id -> HMRuntimeName (ident ctx id)
  367. | A3MRuntimeNameLate -> HMRuntimeNameLate
  368. | A3MMultiNameLate ns -> HMMultiNameLate ctx.nsets.(idx ns)
  369. | A3MAttrib multi -> HMAttrib (parse_name names ctx multi)
  370. | A3MParams (id,pl) -> HMParams (parse_name names ctx names.(idx id),List.map (fun id -> if idx id = -1 then HMAny else parse_name names ctx names.(idx id)) pl)
  371. let parse_try_catch ctx t =
  372. {
  373. hltc_start = t.tc3_start;
  374. hltc_end = t.tc3_end;
  375. hltc_handle = t.tc3_handle;
  376. hltc_type = opt name ctx t.tc3_type;
  377. hltc_name = opt name ctx t.tc3_name;
  378. }
  379. let parse_function ctx f =
  380. {
  381. hlf_stack_size = f.fun3_stack_size;
  382. hlf_nregs = f.fun3_nregs;
  383. hlf_init_scope = f.fun3_init_scope;
  384. hlf_max_scope = f.fun3_max_scope;
  385. hlf_code = MultiArray.create(); (* keep for later *)
  386. hlf_trys = Array.map (parse_try_catch ctx) f.fun3_trys;
  387. hlf_locals = Array.map (fun f ->
  388. if f.f3_metas <> None then assert false;
  389. match f.f3_kind with
  390. | A3FVar v ->
  391. (* v3_value can be <> None if it's a fun parameter with a default value
  392. - which looks like a bug of the AS3 compiler *)
  393. name ctx f.f3_name , opt name ctx v.v3_type , f.f3_slot, v.v3_const
  394. | _ -> assert false
  395. ) f.fun3_locals;
  396. }
  397. let parse_method_type ctx idx f =
  398. let m = ctx.as3.as3_method_types.(idx) in
  399. {
  400. hlmt_index = idx + ctx.delta_mt;
  401. hlmt_ret = opt name ctx m.mt3_ret;
  402. hlmt_args = List.map (opt name ctx) m.mt3_args;
  403. hlmt_native = m.mt3_native;
  404. hlmt_var_args = m.mt3_var_args;
  405. hlmt_arguments_defined = m.mt3_arguments_defined;
  406. hlmt_uses_dxns = m.mt3_uses_dxns;
  407. hlmt_new_block = m.mt3_new_block;
  408. hlmt_unused_flag = m.mt3_unused_flag;
  409. hlmt_debug_name = opt ident ctx m.mt3_debug_name;
  410. hlmt_dparams = opt (fun ctx -> List.map (parse_value ctx)) ctx m.mt3_dparams;
  411. hlmt_pnames = opt (fun ctx -> List.map (opt ident ctx)) ctx m.mt3_pnames;
  412. hlmt_function = opt parse_function ctx f;
  413. }
  414. let parse_class ctx c s index =
  415. {
  416. hlc_index = index + ctx.delta_cl;
  417. hlc_name = name ctx c.cl3_name;
  418. hlc_super = opt name ctx c.cl3_super;
  419. hlc_sealed = c.cl3_sealed;
  420. hlc_final = c.cl3_final;
  421. hlc_interface = c.cl3_interface;
  422. hlc_namespace = opt (fun ctx i -> ctx.namespaces.(idx i)) ctx c.cl3_namespace;
  423. hlc_implements = Array.map (name ctx) c.cl3_implements;
  424. hlc_construct = method_type ctx c.cl3_construct;
  425. hlc_fields = Array.map (parse_field ctx) c.cl3_fields;
  426. hlc_static_construct = method_type ctx s.st3_method;
  427. hlc_static_fields = Array.map (parse_field ctx) s.st3_fields;
  428. }
  429. let parse_static ctx s =
  430. {
  431. hls_method = method_type ctx s.st3_method;
  432. hls_fields = Array.map (parse_field ctx) s.st3_fields;
  433. }
  434. let parse ?(delta_mt=0) ?(delta_cl=0) t =
  435. let ctx = {
  436. as3 = t;
  437. namespaces = [||];
  438. nsets = [||];
  439. names = [||];
  440. methods = [||];
  441. classes = [||];
  442. jumps = [];
  443. pos = 0;
  444. delta_mt = delta_mt;
  445. delta_cl = delta_cl;
  446. } in
  447. ctx.namespaces <- Array.map (parse_namespace ctx) t.as3_namespaces;
  448. ctx.nsets <- Array.map (parse_nset ctx) t.as3_nsets;
  449. ctx.names <- Array.map (parse_name t.as3_names ctx) t.as3_names;
  450. let hfunctions = Hashtbl.create 0 in
  451. Array.iter (fun f -> Hashtbl.add hfunctions (idx (no_nz f.fun3_id)) f) t.as3_functions;
  452. ctx.methods <- Array.mapi (fun i m ->
  453. parse_method_type ctx i (try Some (Hashtbl.find hfunctions i) with Not_found -> None);
  454. ) t.as3_method_types;
  455. ctx.classes <- Array.mapi (fun i c ->
  456. parse_class ctx c t.as3_statics.(i) i
  457. ) t.as3_classes;
  458. let inits = List.map (parse_static ctx) (Array.to_list t.as3_inits) in
  459. Array.iter (fun f ->
  460. match (method_type ctx f.fun3_id).hlmt_function with
  461. | None -> assert false
  462. | Some fl -> fl.hlf_code <- parse_code ctx f fl.hlf_trys
  463. ) t.as3_functions;
  464. inits
  465. (* ************************************************************************ *)
  466. (* FLATTEN *)
  467. (* ************************************************************************ *)
  468. type ('hl,'item) lookup = {
  469. h : ('hl,int) Hashtbl.t;
  470. a : 'item DynArray.t;
  471. f : flatten_ctx -> 'hl -> 'item;
  472. }
  473. and ('hl,'item) index_lookup = {
  474. ordered_list : 'hl list;
  475. ordered_array : 'item option DynArray.t;
  476. map_f : flatten_ctx -> 'hl -> 'item;
  477. }
  478. and flatten_ctx = {
  479. fints : (hl_int,as3_int) lookup;
  480. fuints : (hl_uint,as3_uint) lookup;
  481. ffloats : (hl_float,as3_float) lookup;
  482. fidents : (hl_ident,as3_ident) lookup;
  483. fnamespaces : (hl_namespace,as3_namespace) lookup;
  484. fnsets : (hl_ns_set,as3_ns_set) lookup;
  485. fnames : (hl_name,as3_multi_name) lookup;
  486. fmetas : (hl_metadata,as3_metadata) lookup;
  487. fmethods : (hl_method,as3_method_type) index_lookup;
  488. fclasses : (hl_class,as3_class * as3_static) index_lookup;
  489. mutable ffunctions : as3_function list;
  490. mutable fjumps : int list;
  491. }
  492. let new_lookup f =
  493. {
  494. h = Hashtbl.create 0;
  495. a = DynArray.create();
  496. f = f;
  497. }
  498. let new_index_lookup l f =
  499. {
  500. ordered_list = l;
  501. ordered_array = DynArray.init (List.length l) (fun _ -> None);
  502. map_f = f;
  503. }
  504. let lookup_array l = DynArray.to_array l.a
  505. let lookup_index_array l =
  506. Array.map (function None -> assert false | Some x -> x) (DynArray.to_array l.ordered_array)
  507. let lookup ctx (l:('a,'b) lookup) item : 'b index =
  508. let idx = try
  509. Hashtbl.find l.h item
  510. with Not_found ->
  511. let idx = DynArray.length l.a in
  512. (* set dummy value for recursion *)
  513. DynArray.add l.a (Obj.magic 0);
  514. Hashtbl.add l.h item (idx + 1);
  515. DynArray.set l.a idx (l.f ctx item);
  516. idx + 1
  517. in
  518. As3parse.magic_index idx
  519. let lookup_index_nz ctx (l:('a,'b) index_lookup) item : 'c index_nz =
  520. let rec loop n = function
  521. | [] -> assert false
  522. | x :: l ->
  523. if x == item then n else loop (n + 1) l
  524. in
  525. let idx = loop 0 l.ordered_list in
  526. if DynArray.get l.ordered_array idx = None then begin
  527. (* set dummy value for recursion *)
  528. DynArray.set l.ordered_array idx (Some (Obj.magic 0));
  529. DynArray.set l.ordered_array idx (Some (l.map_f ctx item));
  530. end;
  531. As3parse.magic_index_nz idx
  532. let lookup_nz ctx l item =
  533. As3parse.magic_index_nz (As3parse.index_int (lookup ctx l item) - 1)
  534. let lookup_ident ctx i = lookup ctx ctx.fidents i
  535. let lookup_name ctx n = lookup ctx ctx.fnames n
  536. let lookup_method ctx m : as3_method_type index_nz =
  537. lookup_index_nz ctx ctx.fmethods m
  538. let lookup_class ctx c : as3_class index_nz =
  539. lookup_index_nz ctx ctx.fclasses c
  540. let flatten_namespace ctx = function
  541. | HNPrivate i -> A3NPrivate (opt lookup_ident ctx i)
  542. | HNPublic i -> A3NPublic (opt lookup_ident ctx i)
  543. | HNInternal i -> A3NInternal (opt lookup_ident ctx i)
  544. | HNProtected i -> A3NProtected (lookup_ident ctx i)
  545. | HNNamespace i -> A3NNamespace (lookup_ident ctx i)
  546. | HNExplicit i -> A3NExplicit (lookup_ident ctx i)
  547. | HNStaticProtected i -> A3NStaticProtected (opt lookup_ident ctx i)
  548. let flatten_ns_set ctx n =
  549. List.map (lookup ctx ctx.fnamespaces) n
  550. let rec flatten_name ctx = function
  551. | HMPath (pack,i) ->
  552. let ns = HNPublic (match pack with [] -> None | l -> Some (String.concat "." l)) in
  553. A3MName (lookup_ident ctx i,lookup ctx ctx.fnamespaces ns)
  554. | HMName (i,n) -> A3MName (lookup_ident ctx i,lookup ctx ctx.fnamespaces n)
  555. | HMNSAny (i) -> A3MNSAny (lookup_ident ctx i)
  556. | HMAny -> A3MAny
  557. | HMMultiName (i,ns) -> A3MMultiName (opt lookup_ident ctx i,lookup ctx ctx.fnsets ns)
  558. | HMRuntimeName i -> A3MRuntimeName (lookup_ident ctx i)
  559. | HMRuntimeNameLate -> A3MRuntimeNameLate
  560. | HMMultiNameLate ns -> A3MMultiNameLate (lookup ctx ctx.fnsets ns)
  561. | HMAttrib n -> A3MAttrib (flatten_name ctx n)
  562. | HMParams (i,nl) -> A3MParams (lookup_name ctx i,List.map (lookup_name ctx) nl)
  563. let flatten_meta ctx m =
  564. {
  565. meta3_name = lookup_ident ctx m.hlmeta_name;
  566. meta3_data = Array.map (fun (i,i2) -> opt lookup_ident ctx i, lookup_ident ctx i2) m.hlmeta_data;
  567. }
  568. let flatten_value ctx = function
  569. | HVNone -> A3VNone
  570. | HVNull -> A3VNull
  571. | HVBool b -> A3VBool b
  572. | HVString s -> A3VString (lookup_ident ctx s)
  573. | HVInt i -> A3VInt (lookup ctx ctx.fints i)
  574. | HVUInt i -> A3VUInt (lookup ctx ctx.fuints i)
  575. | HVFloat f -> A3VFloat (lookup ctx ctx.ffloats f)
  576. | HVNamespace (n,ns) -> A3VNamespace (n,lookup ctx ctx.fnamespaces ns)
  577. let flatten_field ctx f =
  578. {
  579. f3_name = lookup_name ctx f.hlf_name;
  580. f3_slot = f.hlf_slot;
  581. f3_kind = (match f.hlf_kind with
  582. | HFMethod m ->
  583. A3FMethod {
  584. m3_type = lookup_method ctx m.hlm_type;
  585. m3_final = m.hlm_final;
  586. m3_override = m.hlm_override;
  587. m3_kind = m.hlm_kind;
  588. }
  589. | HFVar v ->
  590. A3FVar {
  591. v3_type = opt lookup_name ctx v.hlv_type;
  592. v3_value = flatten_value ctx v.hlv_value;
  593. v3_const = v.hlv_const;
  594. }
  595. | HFFunction f ->
  596. A3FFunction (lookup_method ctx f)
  597. | HFClass c ->
  598. A3FClass (lookup_class ctx c)
  599. );
  600. f3_metas = opt (fun ctx -> Array.map (fun m -> lookup_nz ctx ctx.fmetas m)) ctx f.hlf_metas;
  601. }
  602. let flatten_class ctx c =
  603. {
  604. cl3_name = lookup_name ctx c.hlc_name;
  605. cl3_super = opt lookup_name ctx c.hlc_super;
  606. cl3_sealed = c.hlc_sealed;
  607. cl3_final = c.hlc_final;
  608. cl3_interface = c.hlc_interface;
  609. cl3_namespace = opt (fun ctx -> lookup ctx ctx.fnamespaces) ctx c.hlc_namespace;
  610. cl3_implements = Array.map (lookup_name ctx) c.hlc_implements;
  611. cl3_construct = lookup_method ctx c.hlc_construct;
  612. cl3_fields = Array.map (flatten_field ctx) c.hlc_fields;
  613. },
  614. {
  615. st3_method = lookup_method ctx c.hlc_static_construct;
  616. st3_fields = Array.map (flatten_field ctx) c.hlc_static_fields;
  617. }
  618. let flatten_opcode ctx i = function
  619. | HBreakPoint -> A3BreakPoint
  620. | HNop -> A3Nop
  621. | HThrow -> A3Throw
  622. | HGetSuper n -> A3GetSuper (lookup_name ctx n)
  623. | HSetSuper n -> A3SetSuper (lookup_name ctx n)
  624. | HDxNs s -> A3DxNs (lookup_ident ctx s)
  625. | HDxNsLate -> A3DxNsLate
  626. | HRegKill r -> A3RegKill r
  627. | HLabel -> A3Label
  628. | HJump (j,n) ->
  629. ctx.fjumps <- i :: ctx.fjumps;
  630. A3Jump (j,n)
  631. | HSwitch (n,l) ->
  632. ctx.fjumps <- i :: ctx.fjumps;
  633. A3Switch (n,l)
  634. | HPushWith -> A3PushWith
  635. | HPopScope -> A3PopScope
  636. | HForIn -> A3ForIn
  637. | HHasNext -> A3HasNext
  638. | HNull -> A3Null
  639. | HUndefined -> A3Undefined
  640. | HForEach -> A3ForEach
  641. | HSmallInt n -> A3SmallInt n
  642. | HInt n -> A3Int n
  643. | HTrue -> A3True
  644. | HFalse -> A3False
  645. | HNaN -> A3NaN
  646. | HPop -> A3Pop
  647. | HDup -> A3Dup
  648. | HSwap -> A3Swap
  649. | HString s -> A3String (lookup_ident ctx s)
  650. | HIntRef i -> A3IntRef (lookup ctx ctx.fints i)
  651. | HUIntRef i -> A3UIntRef (lookup ctx ctx.fuints i)
  652. | HFloat f -> A3Float (lookup ctx ctx.ffloats f)
  653. | HScope -> A3Scope
  654. | HNamespace n -> A3Namespace (lookup ctx ctx.fnamespaces n)
  655. | HNext (r1,r2) -> A3Next (r1,r2)
  656. | HFunction m -> A3Function (lookup_method ctx m)
  657. | HCallStack n -> A3CallStack n
  658. | HConstruct n -> A3Construct n
  659. | HCallMethod (s,n) -> A3CallMethod (s,n)
  660. | HCallStatic (m,n) -> A3CallStatic (no_nz (lookup_method ctx m),n)
  661. | HCallSuper (i,n) -> A3CallSuper (lookup_name ctx i,n)
  662. | HCallProperty (i,n) -> A3CallProperty (lookup_name ctx i,n)
  663. | HRetVoid -> A3RetVoid
  664. | HRet -> A3Ret
  665. | HConstructSuper n -> A3ConstructSuper n
  666. | HConstructProperty (i,n) -> A3ConstructProperty (lookup_name ctx i,n)
  667. | HCallPropLex (i,n) -> A3CallPropLex (lookup_name ctx i,n)
  668. | HCallSuperVoid (i,n) -> A3CallSuperVoid (lookup_name ctx i,n)
  669. | HCallPropVoid (i,n)-> A3CallPropVoid (lookup_name ctx i,n)
  670. | HApplyType n -> A3ApplyType n
  671. | HObject n -> A3Object n
  672. | HArray n -> A3Array n
  673. | HNewBlock -> A3NewBlock
  674. | HClassDef c -> A3ClassDef (As3parse.magic_index_nz (As3parse.index_nz_int (lookup_class ctx c)))
  675. | HGetDescendants i -> A3GetDescendants (lookup_name ctx i)
  676. | HCatch n -> A3Catch n
  677. | HFindPropStrict i -> A3FindPropStrict (lookup_name ctx i)
  678. | HFindProp i -> A3FindProp (lookup_name ctx i)
  679. | HFindDefinition i -> A3FindDefinition (lookup_name ctx i)
  680. | HGetLex i -> A3GetLex (lookup_name ctx i)
  681. | HSetProp i -> A3SetProp (lookup_name ctx i)
  682. | HReg r -> A3Reg r
  683. | HSetReg r -> A3SetReg r
  684. | HGetGlobalScope -> A3GetGlobalScope
  685. | HGetScope n -> A3GetScope n
  686. | HGetProp n -> A3GetProp (lookup_name ctx n)
  687. | HInitProp n -> A3InitProp (lookup_name ctx n)
  688. | HDeleteProp n -> A3DeleteProp (lookup_name ctx n)
  689. | HGetSlot s -> A3GetSlot s
  690. | HSetSlot s -> A3SetSlot s
  691. | HToString -> A3ToString
  692. | HToXml -> A3ToXml
  693. | HToXmlAttr -> A3ToXmlAttr
  694. | HToInt -> A3ToInt
  695. | HToUInt -> A3ToUInt
  696. | HToNumber -> A3ToNumber
  697. | HToBool -> A3ToBool
  698. | HToObject -> A3ToObject
  699. | HCheckIsXml -> A3CheckIsXml
  700. | HCast n -> A3Cast (lookup_name ctx n)
  701. | HAsAny -> A3AsAny
  702. | HAsString -> A3AsString
  703. | HAsType n -> A3AsType (lookup_name ctx n)
  704. | HAsObject -> A3AsObject
  705. | HIncrReg r -> A3IncrReg r
  706. | HDecrReg r -> A3DecrReg r
  707. | HTypeof -> A3Typeof
  708. | HInstanceOf -> A3InstanceOf
  709. | HIsType t -> A3IsType (lookup_name ctx t)
  710. | HIncrIReg r -> A3IncrIReg r
  711. | HDecrIReg r -> A3DecrIReg r
  712. | HThis -> A3This
  713. | HSetThis -> A3SetThis
  714. | HDebugReg (i,r,l) -> A3DebugReg (lookup_ident ctx i,r,l)
  715. | HDebugLine l -> A3DebugLine l
  716. | HDebugFile f -> A3DebugFile (lookup_ident ctx f)
  717. | HBreakPointLine n -> A3BreakPointLine n
  718. | HTimestamp -> A3Timestamp
  719. | HOp op -> A3Op op
  720. | HUnk c -> A3Unk c
  721. let flatten_code ctx hcode trys =
  722. let positions = MultiArray.make (MultiArray.length hcode + 1) 0 in
  723. let pos = ref 0 in
  724. let old = ctx.fjumps in
  725. ctx.fjumps <- [];
  726. let code = MultiArray.mapi (fun i op ->
  727. let op = flatten_opcode ctx i op in
  728. pos := !pos + As3code.length op;
  729. MultiArray.set positions (i + 1) !pos;
  730. op
  731. ) hcode in
  732. (* patch jumps *)
  733. List.iter (fun j ->
  734. MultiArray.set code j (match MultiArray.get code j with
  735. | A3Jump (jc,n) ->
  736. A3Jump (jc,MultiArray.get positions (j+n) - MultiArray.get positions (j+1))
  737. | A3Switch (n,infos) ->
  738. A3Switch (MultiArray.get positions (j+n) - MultiArray.get positions (j),List.map (fun n -> MultiArray.get positions (j+n) - MultiArray.get positions (j)) infos)
  739. | _ -> assert false);
  740. ) ctx.fjumps;
  741. (* patch trys *)
  742. let trys = Array.mapi (fun i t ->
  743. {
  744. tc3_start = MultiArray.get positions t.hltc_start;
  745. tc3_end = MultiArray.get positions t.hltc_end;
  746. tc3_handle = MultiArray.get positions t.hltc_handle;
  747. tc3_type = opt lookup_name ctx t.hltc_type;
  748. tc3_name = opt lookup_name ctx t.hltc_name;
  749. }
  750. ) trys in
  751. ctx.fjumps <- old;
  752. code, trys
  753. let flatten_function ctx f mid =
  754. let code, trys = flatten_code ctx f.hlf_code f.hlf_trys in
  755. {
  756. fun3_id = mid;
  757. fun3_stack_size = f.hlf_stack_size;
  758. fun3_nregs = f.hlf_nregs;
  759. fun3_init_scope = f.hlf_init_scope;
  760. fun3_max_scope = f.hlf_max_scope;
  761. fun3_code = code;
  762. fun3_trys = trys;
  763. fun3_locals = Array.map (fun (n,t,s,c) ->
  764. {
  765. f3_name = lookup_name ctx n;
  766. f3_slot = s;
  767. f3_kind = A3FVar { v3_type = opt lookup_name ctx t; v3_value = A3VNone; v3_const = c };
  768. f3_metas = None;
  769. }
  770. ) f.hlf_locals;
  771. }
  772. let flatten_method ctx m =
  773. let mid = lookup_method ctx m in
  774. (match m.hlmt_function with
  775. | None -> ()
  776. | Some f ->
  777. let x = flatten_function ctx f mid in
  778. ctx.ffunctions <- x :: ctx.ffunctions);
  779. {
  780. mt3_ret = opt lookup_name ctx m.hlmt_ret;
  781. mt3_args = List.map (opt lookup_name ctx) m.hlmt_args;
  782. mt3_native = m.hlmt_native;
  783. mt3_var_args = m.hlmt_var_args;
  784. mt3_arguments_defined = m.hlmt_arguments_defined;
  785. mt3_uses_dxns = m.hlmt_uses_dxns;
  786. mt3_new_block = m.hlmt_new_block;
  787. mt3_unused_flag = m.hlmt_unused_flag;
  788. mt3_debug_name = opt lookup_ident ctx m.hlmt_debug_name;
  789. mt3_dparams = opt (fun ctx -> List.map (flatten_value ctx)) ctx m.hlmt_dparams;
  790. mt3_pnames = opt (fun ctx -> List.map (opt lookup_ident ctx)) ctx m.hlmt_pnames;
  791. }
  792. let flatten_static ctx s =
  793. {
  794. st3_method = lookup_method ctx s.hls_method;
  795. st3_fields = Array.map (flatten_field ctx) s.hls_fields;
  796. }
  797. let rec browse_method ctx m =
  798. let ml, _ = ctx in
  799. if not (List.memq m !ml) then begin
  800. ml := m :: !ml;
  801. match m.hlmt_function with
  802. | None -> ()
  803. | Some f ->
  804. MultiArray.iter (function
  805. | HFunction f | HCallStatic (f,_) -> browse_method ctx f
  806. | HClassDef _ -> () (* ignore, should be in fields list anyway *)
  807. | _ -> ()
  808. ) f.hlf_code
  809. end
  810. and browse_class ctx c =
  811. let _, cl = ctx in
  812. if not (List.memq c !cl) then begin
  813. cl := c :: !cl;
  814. browse_method ctx c.hlc_construct;
  815. browse_method ctx c.hlc_static_construct;
  816. Array.iter (browse_field ctx) c.hlc_fields;
  817. Array.iter (browse_field ctx) c.hlc_static_fields;
  818. end
  819. and browse_field ctx f =
  820. match f.hlf_kind with
  821. | HFMethod m -> browse_method ctx m.hlm_type
  822. | HFVar _ -> ()
  823. | HFFunction m -> browse_method ctx m
  824. | HFClass c -> browse_class ctx c
  825. let flatten t =
  826. let id _ x = x in
  827. (* collect methods and classes, sort by index and force evaluation in order to keep order *)
  828. let methods = ref [] in
  829. let classes = ref [] in
  830. let ctx = (methods,classes) in
  831. List.iter (fun s ->
  832. Array.iter (browse_field ctx) s.hls_fields;
  833. browse_method ctx s.hls_method;
  834. ) t;
  835. let methods = List.sort (fun m1 m2 -> m1.hlmt_index - m2.hlmt_index) (List.rev !methods) in
  836. (* done *)
  837. let rec ctx = {
  838. fints = new_lookup id;
  839. fuints = new_lookup id;
  840. ffloats = new_lookup id;
  841. fidents = new_lookup id;
  842. fnamespaces = new_lookup flatten_namespace;
  843. fnsets = new_lookup flatten_ns_set;
  844. fnames = new_lookup flatten_name;
  845. fmetas = new_lookup flatten_meta;
  846. fmethods = new_index_lookup methods flatten_method;
  847. fclasses = new_index_lookup (List.rev !classes) flatten_class;
  848. fjumps = [];
  849. ffunctions = [];
  850. } in
  851. ignore(lookup_ident ctx "");
  852. let inits = List.map (flatten_static ctx) t in
  853. let classes = lookup_index_array ctx.fclasses in
  854. {
  855. as3_ints = lookup_array ctx.fints;
  856. as3_uints = lookup_array ctx.fuints;
  857. as3_floats = lookup_array ctx.ffloats;
  858. as3_idents = lookup_array ctx.fidents;
  859. as3_namespaces = lookup_array ctx.fnamespaces;
  860. as3_nsets = lookup_array ctx.fnsets;
  861. as3_names = lookup_array ctx.fnames;
  862. as3_metadatas = lookup_array ctx.fmetas;
  863. as3_method_types = lookup_index_array ctx.fmethods;
  864. as3_classes = Array.map fst classes;
  865. as3_statics = Array.map snd classes;
  866. as3_functions = Array.of_list (List.rev ctx.ffunctions);
  867. as3_inits = Array.of_list inits;
  868. as3_unknown = "";
  869. }