as3hlparse.ml 28 KB

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