12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372 |
- (*
- * Copyright (C)2005-2013 Haxe Foundation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *)
- open Ast
- open Type
- open As3
- open As3hl
- open Common
- type read = Read
- type write = Unused__ | Write
- type tkind =
- | KInt
- | KUInt
- | KFloat
- | KBool
- | KType of hl_name
- | KDynamic
- | KNone
- type register = {
- rid : int;
- rtype : tkind;
- mutable rused : bool;
- mutable rinit : bool;
- mutable rcond : bool;
- }
- type 'a access =
- | VReg of register
- | VId of hl_name
- | VCast of hl_name * tkind
- | VGlobal of hl_name
- | VArray
- | VScope of hl_slot
- | VVolatile of hl_name * tkind option
- | VSuper of hl_name
- type local =
- | LReg of register
- | LScope of hl_slot
- | LGlobal of hl_name
- type code_infos = {
- mutable iregs : register DynArray.t;
- mutable ipos : int;
- mutable istack : int;
- mutable imax : int;
- mutable iscopes : int;
- mutable imaxscopes : int;
- mutable iloop : int;
- mutable icond : bool;
- }
- type try_infos = {
- tr_pos : int;
- tr_end : int;
- tr_catch_pos : int;
- tr_type : t;
- }
- type context = {
- (* globals *)
- com : Common.context;
- debugger : bool;
- swc : bool;
- boot : path;
- swf_protected : bool;
- need_ctor_skip : bool;
- mutable cur_class : tclass;
- mutable debug : bool;
- mutable last_line : int;
- mutable last_file : string;
- (* per-function *)
- mutable locals : (int,tvar * local) PMap.t;
- mutable code : hl_opcode DynArray.t;
- mutable infos : code_infos;
- mutable trys : try_infos list;
- mutable breaks : (unit -> unit) list;
- mutable continues : (int -> unit) list;
- mutable in_static : bool;
- mutable block_vars : (hl_slot * string * hl_name option) list;
- mutable try_scope_reg : register option;
- mutable for_call : bool;
- }
- let invalid_expr p = error "Invalid expression" p
- let stack_error p = error "Stack error" p
- let index_int (x : int) : 'a index = Obj.magic (x + 1)
- let index_nz_int (x : int) : 'a index_nz = Obj.magic x
- let tid (x : 'a index) : int = Obj.magic x
- let ethis = mk (TConst TThis) (mk_mono()) null_pos
- let dynamic_prop = HMMultiNameLate [HNPublic (Some "")]
- let is_special_compare e1 e2 =
- match e1.eexpr, e2.eexpr with
- | TConst TNull, _ | _ , TConst TNull -> None
- | _ ->
- match follow e1.etype, follow e2.etype with
- | TInst ({ cl_path = [],"Xml" } as c,_) , _ | _ , TInst ({ cl_path = [],"Xml" } as c,_) -> Some c
- | _ -> None
- let write ctx op =
- DynArray.add ctx.code op;
- ctx.infos.ipos <- ctx.infos.ipos + 1;
- let s = ctx.infos.istack + As3hlparse.stack_delta op in
- ctx.infos.istack <- s;
- if s > ctx.infos.imax then ctx.infos.imax <- s;
- match op with
- | HScope ->
- let n = ctx.infos.iscopes + 1 in
- ctx.infos.iscopes <- n;
- if n > ctx.infos.imaxscopes then ctx.infos.imaxscopes <- n
- | HPopScope ->
- ctx.infos.iscopes <- ctx.infos.iscopes - 1
- | _ ->
- ()
- let jump ctx cond =
- let op = DynArray.length ctx.code in
- let p = ctx.infos.ipos in
- write ctx (HJump (cond,0));
- (fun () ->
- let delta = ctx.infos.ipos - p in
- DynArray.set ctx.code op (HJump (cond,delta))
- )
- let jump_back ctx =
- let p = ctx.infos.ipos in
- write ctx HLabel;
- (fun cond ->
- let delta = p - ctx.infos.ipos in
- write ctx (HJump (cond,delta))
- )
- let real_path = function
- | [] , "Int" -> [] , "int"
- | [] , "UInt" -> [] , "uint"
- | [] , "Float" -> [] , "Number"
- | [] , "Bool" -> [] , "Boolean"
- | [] , "Enum" -> [] , "Class"
- | [] , "EnumValue" -> [] , "Object"
- | ["flash";"xml"], "XML" -> [], "XML"
- | ["flash";"xml"], "XMLList" -> [], "XMLList"
- | ["flash";"utils"], "QName" -> [] , "QName"
- | ["flash";"utils"], "Namespace" -> [] , "Namespace"
- | ["flash";"utils"], "Object" -> [] , "Object"
- | ["flash";"utils"], "Function" -> [] , "Function"
- | ["flash"] , "FlashXml__" -> [] , "Xml"
- | ["flash";"errors"] , "Error" -> [], "Error"
- | ["flash"] , "Vector" -> ["__AS3__";"vec"], "Vector"
- | path -> path
- let type_path ctx path =
- let pack, name = real_path path in
- HMPath (pack,name)
- let rec follow_basic t =
- match t with
- | TMono r ->
- (match !r with
- | Some t -> follow_basic t
- | _ -> t)
- | TLazy f ->
- follow_basic (!f())
- | TType ({ t_path = [],"Null" },[tp]) ->
- (match follow_basic tp with
- | TMono _
- | TFun _
- | TAbstract ({ a_path = ([],"Int") },[])
- | TAbstract ({ a_path = ([],"Float") },[])
- | TAbstract ({ a_path = [],"UInt" },[])
- | TAbstract ({ a_path = ([],"Bool") },[])
- | TInst ({ cl_path = (["haxe"],"Int32") },[])
- | TInst ({ cl_path = ([],"Int") },[])
- | TInst ({ cl_path = ([],"Float") },[])
- | TType ({ t_path = [],"UInt" },[])
- | TEnum ({ e_path = ([],"Bool") },[]) -> t
- | t -> t)
- | TType ({ t_path = ["flash";"utils"],"Object" },[])
- | TType ({ t_path = ["flash";"utils"],"Function" },[])
- | TType ({ t_path = [],"UInt" },[]) ->
- t
- | TType (t,tl) ->
- follow_basic (apply_params t.t_types tl t.t_type)
- | TAbstract (a,pl) when a.a_impl <> None ->
- follow_basic (apply_params a.a_types pl a.a_this)
- | _ -> t
- let rec type_id ctx t =
- match follow_basic t with
- | TInst ({ cl_path = ["haxe"],"Int32" },_) ->
- type_path ctx ([],"Int")
- | TInst ({ cl_path = ["flash"],"Vector" } as c,pl) ->
- (match pl with
- | [TInst({cl_kind = KTypeParameter _},_)] -> type_path ctx ([],"Object")
- | _ -> HMParams (type_path ctx c.cl_path,List.map (type_id ctx) pl))
- | TInst (c,_) ->
- (match c.cl_kind with
- | KTypeParameter l ->
- (match l with
- | [t] -> type_id ctx t
- | _ -> type_path ctx ([],"Object"))
- | KExtension (c,params) ->
- type_id ctx (TInst (c,params))
- | _ ->
- type_path ctx c.cl_path)
- | TAbstract (a,_) ->
- type_path ctx a.a_path
- | TFun _ | TType ({ t_path = ["flash";"utils"],"Function" },[]) ->
- type_path ctx ([],"Function")
- | TType ({ t_path = ([],"UInt") as path },_) ->
- type_path ctx path
- | TEnum ({ e_path = [],"XmlType"; e_extern = true },_) ->
- HMPath ([],"String")
- | TEnum (e,_) ->
- let rec loop = function
- | [] -> type_path ctx e.e_path
- | (Meta.FakeEnum,[Ast.EConst (Ast.Ident n),_],_) :: _ -> type_path ctx ([],n)
- | _ :: l -> loop l
- in
- loop e.e_meta
- | _ ->
- HMPath ([],"Object")
- let type_opt ctx t =
- match follow_basic t with
- | TDynamic _ | TMono _ -> None
- | _ -> Some (type_id ctx t)
- let type_void ctx t =
- match follow t with
- | TEnum ({ e_path = [],"Void" },_) | TAbstract ({ a_path = [],"Void" },_) -> Some (HMPath ([],"void"))
- | _ -> type_opt ctx t
- let classify ctx t =
- match follow_basic t with
- | TAbstract ({ a_path = [],"Int" },_) | TInst ({ cl_path = [],"Int" },_) | TInst ({ cl_path = ["haxe"],"Int32" },_) ->
- KInt
- | TAbstract ({ a_path = [],"Float" },_) | TInst ({ cl_path = [],"Float" },_) ->
- KFloat
- | TAbstract ({ a_path = [],"Bool" },_) | TEnum ({ e_path = [],"Bool" },_) ->
- KBool
- | TAbstract ({ a_path = [],"Void" },_) | TEnum ({ e_path = [],"Void" },_) ->
- KDynamic
- | TEnum ({ e_path = [],"XmlType"; e_extern = true },_) ->
- KType (HMPath ([],"String"))
- | TEnum (e,_) ->
- let rec loop = function
- | [] -> KType (type_id ctx t)
- | (Meta.FakeEnum,[Ast.EConst (Ident n),_],_) :: _ ->
- (match n with
- | "Int" -> KInt
- | "UInt" -> KUInt
- | "String" -> KType (HMPath ([],"String"))
- | _ -> assert false)
- | _ :: l -> loop l
- in
- loop e.e_meta
- | TAbstract ({ a_path = [],"UInt" },_) | TType ({ t_path = [],"UInt" },_) ->
- KUInt
- | TFun _ | TType ({ t_path = ["flash";"utils"],"Function" },[]) ->
- KType (HMPath ([],"Function"))
- | TAnon a ->
- (match !(a.a_status) with
- | Statics _ -> KNone
- | _ -> KDynamic)
- | TType ({ t_path = ["flash";"utils"],"Object" },[]) ->
- KType (HMPath ([],"Object"))
- | TInst _ | TAbstract _ ->
- KType (type_id ctx t)
- | TMono _
- | TType _
- | TDynamic _ ->
- KDynamic
- | TLazy _ ->
- assert false
- (* some field identifiers might cause issues with SWC *)
- let reserved i =
- match i with
- | "int" -> "_" ^ i
- | _ -> i
- let ident i =
- HMPath ([],reserved i)
- let as3 p =
- HMName (p,HNNamespace "http://adobe.com/AS3/2006/builtin")
- let property ctx p t =
- match follow t with
- | TInst ({ cl_path = [],"Array" },_) ->
- (match p with
- | "length" -> ident p, Some KInt, false (* UInt in the spec *)
- | "copy" | "insert" | "remove" | "iterator" | "toString" | "map" | "filter" -> ident p , None, true
- | _ -> as3 p, None, false);
- | TInst ({ cl_path = ["flash"],"Vector" },_) ->
- (match p with
- | "length" -> ident p, Some KInt, false (* UInt in the spec *)
- | "fixed" | "toString" -> ident p, None, false
- | "iterator" -> ident p, None, true
- | _ -> as3 p, None, false);
- | TInst ({ cl_path = [],"String" },_) ->
- (match p with
- | "length" (* Int in AS3/Haxe *) -> ident p, None, false
- | "charCodeAt" (* use Haxe version *) -> ident p, None, true
- | "cca" -> as3 "charCodeAt", None, false
- | _ -> as3 p, None, false);
- | TAnon a ->
- (match !(a.a_status) with
- | Statics { cl_path = [], "Math" } ->
- (match p with
- | "POSITIVE_INFINITY" | "NEGATIVE_INFINITY" | "NaN" -> ident p, Some KFloat, false
- | "floor" | "ceil" | "round" when ctx.for_call -> ident p, Some KInt, false
- | "ffloor" | "fceil" | "fround" -> ident (String.sub p 1 (String.length p - 1)), None, false
- | _ -> ident p, None, false)
- | _ -> ident p, None, false)
- | TInst ({ cl_kind = KExtension _ } as c,params) ->
- (* cast type when accessing an extension field *)
- (try
- let f = PMap.find p c.cl_fields in
- ident p, Some (classify ctx (apply_params c.cl_types params f.cf_type)), false
- with Not_found ->
- ident p, None, false)
- | TInst ({ cl_interface = true } as c,_) ->
- (* lookup the interface in which the field was actually declared *)
- let rec loop c =
- try
- (match PMap.find p c.cl_fields with
- | { cf_kind = Var _ } -> raise Exit (* no vars in interfaces in swf9 *)
- | _ -> c)
- with Not_found ->
- let rec loop2 = function
- | [] -> raise Not_found
- | (i,_) :: l ->
- try loop i with Not_found -> loop2 l
- in
- loop2 c.cl_implements
- in
- (try
- let c = loop c in
- let ns = HMName (reserved p, HNNamespace (match c.cl_path with [],n -> n | l,n -> String.concat "." l ^ ":" ^ n)) in
- ns, None, false
- with Not_found | Exit ->
- ident p, None, false)
- | _ ->
- ident p, None, false
- let default_infos() =
- {
- ipos = 0;
- istack = 0;
- imax = 0;
- iregs = DynArray.create();
- iscopes = 0;
- imaxscopes = 0;
- iloop = -1;
- icond = false;
- }
- let alloc_reg ctx k =
- let regs = ctx.infos.iregs in
- try
- let p = DynArray.index_of (fun r -> not r.rused && k = r.rtype) regs in
- let r = DynArray.unsafe_get regs p in
- r.rused <- true;
- r.rinit <- false;
- r
- with
- Not_found ->
- let r = {
- rid = DynArray.length regs + 1;
- rused = true;
- rinit = false;
- rtype = k;
- rcond = false;
- } in
- DynArray.add regs r;
- r
- let coerce ctx t =
- (* it would be useful to know if we don't already have
- this type on the stack (as detected by the bytecode verifier)...
- maybe this get removed at JIT, so it's only useful to reduce codesize
- *)
- if t <> KNone then
- write ctx (match t with
- | KInt -> HToInt
- | KUInt -> HToUInt
- | KFloat -> HToNumber
- | KBool -> HToBool
- | KType t -> HCast t
- | KDynamic -> HAsAny
- | KNone -> assert false
- )
- let set_reg ctx r =
- if not r.rinit then begin
- r.rinit <- true;
- if ctx.infos.icond then r.rcond <- true;
- end;
- coerce ctx r.rtype;
- write ctx (HSetReg r.rid)
- let set_reg_dup ctx r =
- if not r.rinit then begin
- r.rinit <- true;
- if ctx.infos.icond then r.rcond <- true;
- end;
- coerce ctx r.rtype;
- write ctx HDup;
- write ctx (HSetReg r.rid)
- let free_reg ctx r =
- r.rused <- false
- let pop ctx n =
- let rec loop n =
- if n > 0 then begin
- write ctx HPop;
- loop (n - 1)
- end
- in
- if n < 0 then assert false;
- let old = ctx.infos.istack in
- loop n;
- ctx.infos.istack <- old
- let is_member ctx name =
- let rec loop c =
- PMap.mem name c.cl_fields || (match c.cl_super with None -> false | Some (c,_) -> loop c)
- in
- loop ctx.cur_class
- let rename_block_var ctx v =
- (* we need to rename it since slots are accessed on a by-name basis *)
- let rec loop i =
- let name = v.v_name ^ string_of_int i in
- if List.exists (fun(_,x,_) -> name = x) ctx.block_vars || is_member ctx name then
- loop (i + 1)
- else
- v.v_name <- name
- in
- loop 1
- let define_local ctx ?(init=false) v p =
- let name = v.v_name in
- let t = v.v_type in
- let l = (if v.v_capture then begin
- let topt = type_opt ctx t in
- if List.exists (fun (_,x,_) -> name = x) ctx.block_vars || is_member ctx name then rename_block_var ctx v;
- let pos = List.length ctx.block_vars + 1 in
- ctx.block_vars <- (pos,v.v_name,topt) :: ctx.block_vars;
- LScope pos
- end else
- let r = alloc_reg ctx (classify ctx t) in
- if ctx.debug then write ctx (HDebugReg (name, r.rid, ctx.last_line));
- r.rinit <- init;
- LReg r
- ) in
- ctx.locals <- PMap.add v.v_id (v,l) ctx.locals
- let is_set v = (Obj.magic v) = Write
- let gen_local_access ctx v p (forset : 'a) : 'a access =
- match snd (try PMap.find v.v_id ctx.locals with Not_found -> error ("Unbound variable " ^ v.v_name) p) with
- | LReg r ->
- VReg r
- | LScope n ->
- write ctx (HGetScope 1);
- VScope n
- | LGlobal p ->
- if is_set forset then write ctx (HFindProp p);
- VGlobal p
- let get_local_register ctx v =
- match (try snd (PMap.find v.v_id ctx.locals) with Not_found -> LScope 0) with
- | LReg r -> Some r
- | _ -> None
- let rec setvar ctx (acc : write access) kret =
- match acc with
- | VReg r ->
- if kret <> None then
- set_reg_dup ctx r
- else
- set_reg ctx r;
- | VGlobal _ | VId _ | VCast _ | VArray | VScope _ when kret <> None ->
- let r = alloc_reg ctx (match kret with None -> assert false | Some k -> k) in
- set_reg_dup ctx r;
- setvar ctx acc None;
- write ctx (HReg r.rid);
- free_reg ctx r
- | VGlobal g ->
- write ctx (HSetProp g)
- | VId id | VCast (id,_) ->
- write ctx (HInitProp id)
- | VVolatile (id,_) ->
- write ctx (HArray 1);
- write ctx (HInitProp id)
- | VArray ->
- write ctx (HSetProp dynamic_prop);
- ctx.infos.istack <- ctx.infos.istack - 1
- | VScope n ->
- write ctx (HSetSlot n)
- | VSuper id ->
- write ctx (HSetSuper id)
- let getvar ctx (acc : read access) =
- match acc with
- | VReg r ->
- if not r.rinit then begin
- r.rinit <- true;
- r.rcond <- true;
- end;
- write ctx (HReg r.rid)
- | VId id ->
- write ctx (HGetProp id)
- | VVolatile (id,t) ->
- write ctx (HGetProp id);
- write ctx (HSmallInt 0);
- write ctx (HGetProp dynamic_prop);
- ctx.infos.istack <- ctx.infos.istack - 1;
- (match t with
- | None -> ()
- | Some t -> coerce ctx t)
- | VCast (id,t) ->
- write ctx (HGetProp id);
- coerce ctx t
- | VGlobal g ->
- write ctx (HGetLex g);
- | VArray ->
- write ctx (HGetProp dynamic_prop);
- ctx.infos.istack <- ctx.infos.istack - 1
- | VScope n ->
- write ctx (HGetSlot n)
- | VSuper id ->
- write ctx (HGetSuper id)
- let open_block ctx retval =
- let old_stack = ctx.infos.istack in
- let old_regs = DynArray.map (fun r -> r.rused) ctx.infos.iregs in
- let old_locals = ctx.locals in
- (fun() ->
- if ctx.infos.istack <> old_stack + (if retval then 1 else 0) then assert false;
- let rcount = DynArray.length old_regs + 1 in
- DynArray.iter (fun r ->
- if r.rid < rcount then
- r.rused <- DynArray.unsafe_get old_regs (r.rid - 1)
- else
- r.rused <- false
- ) ctx.infos.iregs;
- ctx.locals <- old_locals;
- )
- let begin_branch ctx =
- if ctx.infos.icond then
- (fun() -> ())
- else begin
- ctx.infos.icond <- true;
- (fun() -> ctx.infos.icond <- false)
- end
- let begin_switch ctx =
- let branch = begin_branch ctx in
- let switch_index = DynArray.length ctx.code in
- let switch_pos = ctx.infos.ipos in
- write ctx (HSwitch (0,[]));
- let constructs = ref [] in
- let max = ref 0 in
- let ftag tag =
- if tag > !max then max := tag;
- constructs := (tag,ctx.infos.ipos) :: !constructs;
- in
- let fend() =
- let cases = Array.create (!max + 1) 1 in
- List.iter (fun (tag,pos) -> Array.set cases tag (pos - switch_pos)) !constructs;
- DynArray.set ctx.code switch_index (HSwitch (1,Array.to_list cases));
- branch();
- in
- fend, ftag
- let debug_infos ?(is_min=true) ctx p =
- if ctx.debug then begin
- let line = Lexer.get_error_line (if is_min then p else { p with pmin = p.pmax }) in
- if ctx.last_file <> p.pfile then begin
- write ctx (HDebugFile (if ctx.debugger then Common.get_full_path p.pfile else p.pfile));
- ctx.last_file <- p.pfile;
- ctx.last_line <- -1;
- end;
- if ctx.last_line <> line then begin
- write ctx (HDebugLine line);
- ctx.last_line <- line;
- end
- end
- let gen_constant ctx c t p =
- match c with
- | TInt i ->
- let unsigned = classify ctx t = KUInt in
- if Int32.compare i (-128l) > 0 && Int32.compare i 128l < 0 then begin
- write ctx (HSmallInt (Int32.to_int i));
- if unsigned then write ctx HToUInt;
- end else
- write ctx (if unsigned then HUIntRef i else HIntRef i)
- | TFloat f ->
- let f = float_of_string f in
- write ctx (HFloat f);
- | TString s ->
- write ctx (HString (Genswf8.to_utf8 s));
- | TBool b ->
- write ctx (if b then HTrue else HFalse);
- | TNull ->
- write ctx HNull;
- coerce ctx (classify ctx t)
- | TThis ->
- write ctx HThis
- | TSuper ->
- assert false
- let end_fun ctx args dparams tret =
- {
- hlmt_index = 0;
- hlmt_ret = type_void ctx tret;
- hlmt_args = List.map (fun (v,_) -> type_opt ctx v.v_type) args;
- hlmt_native = false;
- hlmt_var_args = false;
- hlmt_debug_name = None;
- hlmt_dparams = dparams;
- hlmt_pnames = if ctx.swc || ctx.debugger then Some (List.map (fun (v,_) -> Some v.v_name) args) else None;
- hlmt_new_block = false;
- hlmt_unused_flag = false;
- hlmt_arguments_defined = false;
- hlmt_uses_dxns = false;
- hlmt_function = None;
- }
- let begin_fun ctx args tret el stat p =
- let old_locals = ctx.locals in
- let old_code = ctx.code in
- let old_infos = ctx.infos in
- let old_trys = ctx.trys in
- let old_bvars = ctx.block_vars in
- let old_static = ctx.in_static in
- let last_line = ctx.last_line in
- let old_treg = ctx.try_scope_reg in
- ctx.infos <- default_infos();
- ctx.code <- DynArray.create();
- ctx.trys <- [];
- ctx.block_vars <- [];
- ctx.in_static <- stat;
- ctx.last_line <- -1;
- ctx.last_file <- "";
- debug_infos ctx p;
- let rec find_this e =
- match e.eexpr with
- | TFunction _ -> ()
- | TConst TThis | TConst TSuper -> raise Exit
- | _ -> Type.iter find_this e
- in
- let this_reg = try List.iter find_this el; false with Exit -> true in
- ctx.locals <- PMap.foldi (fun _ (v,l) acc ->
- match l with
- | LReg _ -> acc
- | LScope _ -> PMap.add v.v_id (v,LGlobal (ident v.v_name)) acc
- | LGlobal _ -> PMap.add v.v_id (v,l) acc
- ) ctx.locals PMap.empty;
- let dparams = ref None in
- let make_constant_value r c t =
- let v = (match classify ctx t, c with
- | _, None -> HVNone
- | (KInt | KFloat | KUInt | KBool) as kind, Some c ->
- (match c with
- | TInt i -> if kind = KUInt then HVUInt i else HVInt i
- | TFloat s -> HVFloat (float_of_string s)
- | TBool b -> HVBool b
- | TNull -> error ("In Flash9, null can't be used as basic type " ^ s_type (print_context()) t) p
- | _ -> assert false)
- | _, Some TNull -> HVNone
- | k, Some c ->
- write ctx (HReg r.rid);
- write ctx HNull;
- let j = jump ctx J3Neq in
- gen_constant ctx c t p;
- coerce ctx k;
- write ctx (HSetReg r.rid);
- j();
- HVNone
- ) in
- match !dparams with
- | None -> if c <> None then dparams := Some [v]
- | Some l -> dparams := Some (v :: l)
- in
- let args, varargs = (match List.rev args with
- | (({ v_name = "__arguments__"; v_type = t } as v),_) :: l ->
- (match follow t with
- | TInst ({ cl_path = ([],"Array") },_) -> List.rev l, Some (v,true)
- | _ -> List.rev l, Some(v,false))
- | _ ->
- args, None
- ) in
- List.iter (fun (v,c) ->
- let t = v.v_type in
- define_local ctx v ~init:true p;
- match gen_local_access ctx v null_pos Write with
- | VReg r ->
- make_constant_value r c t
- | acc ->
- let r = alloc_reg ctx (classify ctx t) in
- make_constant_value r c t;
- write ctx (HReg r.rid);
- setvar ctx acc None
- ) args;
- (match varargs with
- | None -> ()
- | Some (v,_) ->
- define_local ctx v ~init:true p;
- ignore(alloc_reg ctx (classify ctx v.v_type)));
- let dparams = (match !dparams with None -> None | Some l -> Some (List.rev l)) in
- let rec loop_try e =
- match e.eexpr with
- | TFunction _ -> ()
- | TTry _ -> raise Exit
- | _ -> Type.iter loop_try e
- in
- ctx.try_scope_reg <- (try List.iter loop_try el; None with Exit -> Some (alloc_reg ctx KDynamic));
- (fun () ->
- let hasblock = ctx.block_vars <> [] || ctx.trys <> [] in
- let code = DynArray.to_list ctx.code in
- let extra = (
- if hasblock then begin
- let scope = (match ctx.try_scope_reg with
- | None -> [HScope]
- | Some r -> [HDup; HSetReg r.rid; HScope]
- ) in
- HThis :: HScope :: HNewBlock :: scope
- end else if this_reg then
- [HThis; HScope]
- else
- []
- ) in
- (* add dummy registers initialization *)
- let extra = extra @ List.concat (List.map (fun r ->
- if not r.rcond then
- []
- else
- let s = [HSetReg r.rid] in
- match r.rtype with
- | KInt -> HSmallInt 0 :: s
- | KUInt -> HSmallInt 0 :: HToUInt :: s
- | KFloat -> HNaN :: s
- | KBool -> HFalse :: s
- | KType t -> HNull :: HAsType t :: s
- | KDynamic -> HNull :: HAsAny :: s
- | KNone -> HNull :: HAsType (HMPath ([],"Class")) :: s
- ) (DynArray.to_list ctx.infos.iregs)) in
- let delta = List.length extra in
- let f = {
- hlf_stack_size = (if ctx.infos.imax = 0 && (hasblock || this_reg) then 1 else ctx.infos.imax);
- hlf_nregs = DynArray.length ctx.infos.iregs + 1;
- hlf_init_scope = 1;
- hlf_max_scope = ctx.infos.imaxscopes + 1 + (if hasblock then 2 else if this_reg then 1 else 0);
- hlf_code = MultiArray.of_array (Array.of_list (extra @ code));
- hlf_trys = Array.of_list (List.map (fun t ->
- {
- hltc_start = t.tr_pos + delta;
- hltc_end = t.tr_end + delta;
- hltc_handle = t.tr_catch_pos + delta;
- hltc_type = type_opt ctx t.tr_type;
- hltc_name = None;
- }
- ) (List.rev ctx.trys));
- hlf_locals = Array.of_list (List.map (fun (id,name,t) -> ident name, t, id, false) ctx.block_vars);
- } in
- let mt = { (end_fun ctx args dparams tret) with
- hlmt_var_args = (match varargs with Some (_,true) -> true | _ -> false);
- hlmt_arguments_defined = (match varargs with Some (_,false) -> true | _ -> false);
- hlmt_new_block = hasblock;
- hlmt_function = Some f;
- } in
- ctx.locals <- old_locals;
- ctx.code <- old_code;
- ctx.infos <- old_infos;
- ctx.trys <- old_trys;
- ctx.block_vars <- old_bvars;
- ctx.in_static <- old_static;
- ctx.last_line <- last_line;
- ctx.try_scope_reg <- old_treg;
- mt
- )
- let empty_method ctx p =
- let f = begin_fun ctx [] ctx.com.basic.tvoid [] true p in
- write ctx HRetVoid;
- f()
- let begin_loop ctx =
- let old_loop = ctx.infos.iloop in
- let old_breaks = ctx.breaks in
- let old_conts = ctx.continues in
- ctx.infos.iloop <- ctx.infos.istack;
- ctx.breaks <- [];
- ctx.continues <- [];
- (fun cont_pos ->
- if ctx.infos.istack <> ctx.infos.iloop then assert false;
- List.iter (fun j -> j()) ctx.breaks;
- List.iter (fun j -> j cont_pos) ctx.continues;
- ctx.infos.iloop <- old_loop;
- ctx.breaks <- old_breaks;
- ctx.continues <- old_conts;
- )
- let no_value ctx retval =
- (* does not push a null but still increment the stack like if
- a real value was pushed *)
- if retval then ctx.infos.istack <- ctx.infos.istack + 1
- let pop_value ctx retval =
- (* if we have multiple branches, make sure to forget about previous
- branch value *)
- if retval then ctx.infos.istack <- ctx.infos.istack - 1
- let gen_expr_ref = ref (fun _ _ _ -> assert false)
- let gen_expr ctx e retval = (!gen_expr_ref) ctx e retval
- let rec gen_access ctx e (forset : 'a) : 'a access =
- match e.eexpr with
- | TLocal v ->
- gen_local_access ctx v e.epos forset
- | TField ({ eexpr = TConst TSuper } as e1,f) ->
- let f = field_name f in
- let id, _, _ = property ctx f e1.etype in
- write ctx HThis;
- VSuper id
- | TField (e1,f) ->
- let f = field_name f in
- let id, k, closure = property ctx f e1.etype in
- if closure && not ctx.for_call then error "In Flash9, this method cannot be accessed this way : please define a local function" e1.epos;
- (match e1.eexpr with
- | TConst (TThis|TSuper) when not ctx.in_static ->
- write ctx (HFindProp id)
- | _ -> gen_expr ctx true e1);
- (match k with
- | Some t -> VCast (id,t)
- | None ->
- match follow e1.etype, follow e.etype with
- | _ , TFun _ when not ctx.for_call -> VCast(id,classify ctx e.etype)
- | TEnum _, _ -> VId id
- | TInst (_,tl), et ->
- (* if the return type is one of the type-parameters, then we need to cast it *)
- if List.exists (fun t -> follow t == et) tl then
- VCast (id, classify ctx et)
- else if Codegen.is_volatile e.etype then
- VVolatile (id,None)
- else
- VId id
- | TAnon a, _ when (match !(a.a_status) with Statics _ | EnumStatics _ -> true | _ -> false) ->
- if Codegen.is_volatile e.etype then
- VVolatile (id,None)
- else
- VId id
- | _ ->
- if Codegen.is_volatile e.etype then
- VVolatile (id,Some (classify ctx e.etype))
- else
- VCast (id,classify ctx e.etype)
- )
- | TArray ({ eexpr = TLocal { v_name = "__global__" } },{ eexpr = TConst (TString s) }) ->
- let path = parse_path s in
- let id = type_path ctx path in
- if is_set forset then write ctx HGetGlobalScope;
- VGlobal id
- | TArray (e,eindex) ->
- gen_expr ctx true e;
- gen_expr ctx true eindex;
- VArray
- | TTypeExpr t ->
- let id = type_path ctx (t_path t) in
- if is_set forset then write ctx HGetGlobalScope;
- VGlobal id
- | _ ->
- invalid_expr e.epos
- let gen_expr_twice ctx e =
- match e.eexpr with
- | TLocal v ->
- (match get_local_register ctx v with
- | Some r ->
- write ctx (HReg r.rid);
- write ctx (HReg r.rid);
- | None ->
- gen_expr ctx true e;
- write ctx HDup)
- | TConst _ ->
- gen_expr ctx true e;
- gen_expr ctx true e;
- | _ ->
- gen_expr ctx true e;
- write ctx HDup
- let gen_access_rw ctx e : (read access * write access) =
- match e.eexpr with
- | TArray ({ eexpr = TLocal _ }, { eexpr = TConst _ })
- | TArray ({ eexpr = TLocal _ }, { eexpr = TLocal _ })
- | TField ({ eexpr = TLocal _ },_)
- | TField ({ eexpr = TConst _ },_)
- ->
- let w = gen_access ctx e Write in
- let r = gen_access ctx e Read in
- r, w
- | TArray (e,eindex) ->
- let r = (match e.eexpr with TLocal v -> get_local_register ctx v | _ -> None) in
- (match r with
- | None ->
- let r = alloc_reg ctx (classify ctx e.etype) in
- gen_expr ctx true e;
- set_reg ctx r;
- write ctx (HReg r.rid);
- gen_expr_twice ctx eindex;
- write ctx (HReg r.rid);
- write ctx HSwap;
- free_reg ctx r;
- | Some r ->
- write ctx (HReg r.rid);
- gen_expr_twice ctx eindex;
- write ctx (HReg r.rid);
- write ctx HSwap;
- );
- VArray, VArray
- | TField _ ->
- let w = gen_access ctx e Write in
- write ctx HDup;
- Obj.magic w, w
- | _ ->
- let w = gen_access ctx e Write in
- let r = gen_access ctx e Read in
- r, w
- let rec gen_type ctx t =
- match t with
- | HMParams (t,tl) ->
- write ctx (HGetLex t);
- List.iter (gen_type ctx) tl;
- write ctx (HApplyType (List.length tl));
- | _ ->
- write ctx (HGetLex t)
- let rec gen_expr_content ctx retval e =
- match e.eexpr with
- | TConst c ->
- gen_constant ctx c e.etype e.epos
- | TThrow e ->
- ctx.infos.icond <- true;
- getvar ctx (VGlobal (type_path ctx (["flash"],"Boot")));
- let id = type_path ctx (["flash";"errors"],"Error") in
- write ctx (HFindPropStrict id);
- write ctx (HConstructProperty (id,0));
- setvar ctx (VId (ident "lastError")) None;
- gen_expr ctx true e;
- write ctx HThrow;
- no_value ctx retval;
- | TParenthesis e ->
- gen_expr ctx retval e
- | TObjectDecl fl ->
- List.iter (fun (name,e) ->
- write ctx (HString name);
- gen_expr ctx true e
- ) fl;
- write ctx (HObject (List.length fl))
- | TArrayDecl el ->
- List.iter (gen_expr ctx true) el;
- write ctx (HArray (List.length el))
- | TBlock el ->
- let rec loop = function
- | [] ->
- if retval then write ctx HNull
- | [e] ->
- gen_expr ctx retval e
- | e :: l ->
- gen_expr ctx false e;
- loop l
- in
- let b = open_block ctx retval in
- loop el;
- b();
- | TVars vl ->
- List.iter (fun (v,ei) ->
- define_local ctx v e.epos;
- (match ei with
- | None -> ()
- | Some e ->
- let acc = gen_local_access ctx v e.epos Write in
- gen_expr ctx true e;
- setvar ctx acc None)
- ) vl
- | TReturn None ->
- write ctx HRetVoid;
- ctx.infos.icond <- true;
- no_value ctx retval
- | TReturn (Some e) ->
- gen_expr ctx true e;
- write ctx HRet;
- ctx.infos.icond <- true;
- no_value ctx retval
- | TField _
- | TLocal _
- | TTypeExpr _ ->
- getvar ctx (gen_access ctx e Read)
- | TArray _ ->
- getvar ctx (gen_access ctx e Read);
- coerce ctx (classify ctx e.etype)
- | TBinop (op,e1,e2) ->
- gen_binop ctx retval op e1 e2 e.etype e.epos
- | TCall (f,el) ->
- gen_call ctx retval f el e.etype
- | TNew ({ cl_path = [],"Array" },_,[]) ->
- (* it seems that [] is 4 time faster than new Array() *)
- write ctx (HArray 0)
- | TNew (c,tl,pl) ->
- let id = type_id ctx (TInst (c,tl)) in
- (match id with
- | HMParams _ ->
- gen_type ctx id;
- List.iter (gen_expr ctx true) pl;
- write ctx (HConstruct (List.length pl))
- | _ ->
- write ctx (HFindPropStrict id);
- List.iter (gen_expr ctx true) pl;
- write ctx (HConstructProperty (id,List.length pl))
- );
- | TFunction f ->
- write ctx (HFunction (generate_function ctx f true))
- | TIf (e0,e1,e2) ->
- let j = jump_expr ctx e0 false in
- let branch = begin_branch ctx in
- gen_expr ctx retval e1;
- let t = classify ctx e.etype in
- if retval && classify ctx e1.etype <> t then coerce ctx t;
- (match e2 with
- | None -> j()
- | Some e ->
- (* two expresssions, but one per branch *)
- pop_value ctx retval;
- let jend = jump ctx J3Always in
- j();
- gen_expr ctx retval e;
- if retval && classify ctx e.etype <> t then coerce ctx t;
- jend());
- branch();
- | TWhile (econd,e,flag) ->
- let jstart = jump ctx J3Always in
- let end_loop = begin_loop ctx in
- let branch = begin_branch ctx in
- let loop = jump_back ctx in
- if flag = DoWhile then jstart();
- gen_expr ctx false e;
- if flag = NormalWhile then jstart();
- let continue_pos = ctx.infos.ipos in
- let _ = jump_expr_gen ctx econd true (fun j -> loop j; (fun() -> ())) in
- branch();
- end_loop continue_pos;
- if retval then write ctx HNull
- | TUnop (op,flag,e) ->
- gen_unop ctx retval op flag e
- | TTry (e2,cases) ->
- if ctx.infos.istack <> 0 then error "Cannot compile try/catch as a right-side expression in Flash9" e.epos;
- let branch = begin_branch ctx in
- let p = ctx.infos.ipos in
- gen_expr ctx retval e2;
- let pend = ctx.infos.ipos in
- let jend = jump ctx J3Always in
- let rec loop ncases = function
- | [] -> []
- | (v,e) :: l ->
- let b = open_block ctx retval in
- let t = v.v_type in
- ctx.trys <- {
- tr_pos = p;
- tr_end = pend;
- tr_catch_pos = ctx.infos.ipos;
- tr_type = t;
- } :: ctx.trys;
- ctx.infos.istack <- ctx.infos.istack + 1;
- if ctx.infos.imax < ctx.infos.istack then ctx.infos.imax <- ctx.infos.istack;
- write ctx HThis;
- write ctx HScope;
- write ctx (HReg (match ctx.try_scope_reg with None -> assert false | Some r -> r.rid));
- write ctx HScope;
- (* store the exception into local var, using a tmp register if needed *)
- define_local ctx v e.epos;
- let r = (match snd (try PMap.find v.v_id ctx.locals with Not_found -> assert false) with
- | LReg _ -> None
- | _ ->
- let r = alloc_reg ctx (classify ctx t) in
- set_reg ctx r;
- Some r
- ) in
- let acc = gen_local_access ctx v e.epos Write in
- (match r with None -> () | Some r -> write ctx (HReg r.rid));
- setvar ctx acc None;
- (* ----- *)
- let rec call_loop e =
- match e.eexpr with
- | TCall _ | TNew _ -> raise Exit
- | TFunction _ -> ()
- | _ -> Type.iter call_loop e
- in
- let has_call = (try call_loop e; false with Exit -> true) in
- if has_call then begin
- getvar ctx (gen_local_access ctx v e.epos Read);
- write ctx (HAsType (type_path ctx (["flash";"errors"],"Error")));
- let j = jump ctx J3False in
- getvar ctx (VGlobal (type_path ctx (["flash"],"Boot")));
- getvar ctx (gen_local_access ctx v e.epos Read);
- setvar ctx (VId (ident "lastError")) None;
- j();
- end;
- gen_expr ctx retval e;
- b();
- if retval then ctx.infos.istack <- ctx.infos.istack - 1;
- match l with
- | [] -> []
- | _ ->
- let j = jump ctx J3Always in
- j :: loop (ncases + 1) l
- in
- let loops = loop (List.length ctx.trys) cases in
- List.iter (fun j -> j()) loops;
- branch();
- jend()
- | TFor (v,it,e) ->
- gen_expr ctx true it;
- let r = alloc_reg ctx KDynamic in
- set_reg ctx r;
- let branch = begin_branch ctx in
- let b = open_block ctx retval in
- define_local ctx v e.epos;
- let end_loop = begin_loop ctx in
- let continue_pos = ctx.infos.ipos in
- let start = jump_back ctx in
- write ctx (HReg r.rid);
- write ctx (HCallProperty (ident "hasNext",0));
- let jend = jump ctx J3False in
- let acc = gen_local_access ctx v e.epos Write in
- write ctx (HReg r.rid);
- write ctx (HCallProperty (ident "next",0));
- setvar ctx acc None;
- gen_expr ctx false e;
- start J3Always;
- end_loop continue_pos;
- jend();
- if retval then getvar ctx (gen_local_access ctx v e.epos Read);
- b();
- branch();
- free_reg ctx r;
- | TBreak ->
- pop ctx (ctx.infos.istack - ctx.infos.iloop);
- ctx.breaks <- jump ctx J3Always :: ctx.breaks;
- no_value ctx retval
- | TContinue ->
- pop ctx (ctx.infos.istack - ctx.infos.iloop);
- let op = DynArray.length ctx.code in
- let p = ctx.infos.ipos in
- write ctx (HJump (J3Always,0));
- ctx.continues <- (fun target -> DynArray.set ctx.code op (HJump (J3Always,target - p))) :: ctx.continues;
- no_value ctx retval
- | TSwitch (e0,el,eo) ->
- let t = classify ctx e.etype in
- (try
- let t0 = classify ctx e0.etype in
- (* generate optimized int switch *)
- if t0 <> KInt && t0 <> KUInt then raise Exit;
- let rec get_int e =
- match e.eexpr with
- | TConst (TInt n) -> if n < 0l || n > 512l then raise Exit; Int32.to_int n
- | TParenthesis e | TBlock [e] -> get_int e
- | _ -> raise Not_found
- in
- List.iter (fun (vl,_) -> List.iter (fun v ->
- try ignore (get_int v) with _ -> raise Exit
- ) vl) el;
- gen_expr ctx true e0;
- if t0 <> KInt then write ctx HToInt;
- let switch, case = begin_switch ctx in
- (match eo with
- | None ->
- if retval then begin
- write ctx HNull;
- coerce ctx t;
- end;
- | Some e ->
- gen_expr ctx retval e;
- if retval && classify ctx e.etype <> t then coerce ctx t);
- let jends = List.map (fun (vl,e) ->
- let j = jump ctx J3Always in
- List.iter (fun v -> case (get_int v)) vl;
- pop_value ctx retval;
- gen_expr ctx retval e;
- if retval && classify ctx e.etype <> t then coerce ctx t;
- j
- ) el in
- List.iter (fun j -> j()) jends;
- switch();
- with Exit ->
- let r = alloc_reg ctx (classify ctx e0.etype) in
- gen_expr ctx true e0;
- set_reg ctx r;
- let branch = begin_branch ctx in
- let prev = ref (fun () -> ()) in
- let jend = List.map (fun (vl,e) ->
- (!prev)();
- let rec loop = function
- | [] ->
- assert false
- | [v] ->
- write ctx (HReg r.rid);
- gen_expr ctx true v;
- prev := jump ctx J3Neq;
- | v :: l ->
- write ctx (HReg r.rid);
- gen_expr ctx true v;
- let j = jump ctx J3Eq in
- loop l;
- j()
- in
- loop vl;
- gen_expr ctx retval e;
- pop_value ctx retval;
- if retval && classify ctx e.etype <> t then coerce ctx t;
- jump ctx J3Always
- ) el in
- (!prev)();
- free_reg ctx r;
- (match eo with
- | None ->
- if retval then begin
- write ctx HNull;
- coerce ctx t;
- end;
- | Some e ->
- gen_expr ctx retval e;
- if retval && classify ctx e.etype <> t then coerce ctx t;
- );
- List.iter (fun j -> j()) jend;
- branch());
- | TMatch (e0,_,cases,def) ->
- let t = classify ctx e.etype in
- let rparams = alloc_reg ctx (KType (type_path ctx ([],"Array"))) in
- let has_params = List.exists (fun (_,p,_) -> p <> None) cases in
- gen_expr ctx true e0;
- if has_params then begin
- write ctx HDup;
- write ctx (HGetProp (ident "params"));
- set_reg ctx rparams;
- end;
- write ctx (HGetProp (ident "index"));
- write ctx HToInt;
- let switch,case = begin_switch ctx in
- (match def with
- | None ->
- if retval then begin
- write ctx HNull;
- coerce ctx t;
- end;
- | Some e ->
- gen_expr ctx retval e;
- if retval && classify ctx e.etype <> t then coerce ctx t);
- let jends = List.map (fun (cl,params,e) ->
- let j = jump ctx J3Always in
- List.iter case cl;
- pop_value ctx retval;
- let b = open_block ctx retval in
- (match params with
- | None -> ()
- | Some l ->
- let p = ref (-1) in
- List.iter (fun v ->
- incr p;
- match v with
- | None -> ()
- | Some v ->
- define_local ctx v e.epos;
- let acc = gen_local_access ctx v e.epos Write in
- write ctx (HReg rparams.rid);
- write ctx (HSmallInt !p);
- getvar ctx VArray;
- setvar ctx acc None
- ) l
- );
- gen_expr ctx retval e;
- b();
- if retval && classify ctx e.etype <> t then coerce ctx t;
- j
- ) cases in
- switch();
- List.iter (fun j -> j()) jends;
- free_reg ctx rparams
- | TCast (e1,t) ->
- gen_expr ctx retval e1;
- if retval then begin
- match t with
- | None ->
- (* no error if cast failure *)
- let t1 = classify ctx e1.etype in
- let t = classify ctx e.etype in
- if t1 <> t then coerce ctx t;
- | Some t ->
- (* manual cast *)
- let tid = (match gen_access ctx (mk (TTypeExpr t) t_dynamic e.epos) Read with
- | VGlobal id -> id
- | _ -> assert false
- ) in
- match classify ctx e.etype with
- | KType n when (match n with HMPath ([],"String") -> false | _ -> true) ->
- (* for normal classes, we can use native cast *)
- write ctx (HCast tid)
- | _ ->
- (* we need to check with "is" first *)
- write ctx HDup;
- write ctx (HIsType tid);
- let j = jump ctx J3True in
- write ctx (HString "Class cast error");
- write ctx HThrow;
- j();
- write ctx (HCast tid)
- end
- and gen_call ctx retval e el r =
- match e.eexpr , el with
- | TLocal { v_name = "__is__" }, [e;t] ->
- gen_expr ctx true e;
- gen_expr ctx true t;
- write ctx (HOp A3OIs)
- | TLocal { v_name = "__as__" }, [e;t] ->
- gen_expr ctx true e;
- gen_expr ctx true t;
- write ctx (HOp A3OAs)
- | TLocal { v_name = "__int__" }, [e] ->
- gen_expr ctx true e;
- write ctx HToInt
- | TLocal { v_name = "__float__" }, [e] ->
- gen_expr ctx true e;
- write ctx HToNumber
- | TLocal { v_name = "__foreach__" }, [obj;counter] ->
- gen_expr ctx true obj;
- gen_expr ctx true counter;
- write ctx HForEach
- | TLocal { v_name = "__forin__" }, [obj;counter] ->
- gen_expr ctx true obj;
- gen_expr ctx true counter;
- write ctx HForIn
- | TLocal { v_name = "__has_next__" }, [obj;counter] ->
- let oreg = match gen_access ctx obj Read with VReg r -> r | _ -> error "Must be a local variable" obj.epos in
- let creg = match gen_access ctx counter Read with VReg r -> r | _ -> error "Must be a local variable" obj.epos in
- write ctx (HNext (oreg.rid,creg.rid))
- | TLocal { v_name = "__hkeys__" }, [e2]
- | TLocal { v_name = "__foreach__" }, [e2]
- | TLocal { v_name = "__keys__" }, [e2] ->
- let racc = alloc_reg ctx (KType (type_path ctx ([],"Array"))) in
- let rcounter = alloc_reg ctx KInt in
- let rtmp = alloc_reg ctx KDynamic in
- write ctx (HSmallInt 0);
- set_reg ctx rcounter;
- write ctx (HArray 0);
- set_reg ctx racc;
- gen_expr ctx true e2;
- set_reg ctx rtmp;
- let start = jump ctx J3Always in
- let loop = jump_back ctx in
- write ctx (HReg racc.rid);
- write ctx (HReg rtmp.rid);
- write ctx (HReg rcounter.rid);
- (match e.eexpr with
- | TLocal { v_name = "__foreach__" } ->
- write ctx HForEach
- | TLocal { v_name = "__hkeys__" } ->
- write ctx HForIn;
- write ctx (HSmallInt 1);
- write ctx (HCallProperty (as3 "substr",1));
- | _ ->
- write ctx HForIn);
- write ctx (HCallPropVoid (as3 "push",1));
- start();
- write ctx (HNext (rtmp.rid,rcounter.rid));
- loop J3True;
- write ctx (HReg racc.rid);
- free_reg ctx rtmp;
- free_reg ctx rcounter;
- free_reg ctx racc;
- | TLocal { v_name = "__new__" }, e :: el ->
- gen_expr ctx true e;
- List.iter (gen_expr ctx true) el;
- write ctx (HConstruct (List.length el))
- | TLocal { v_name = "__delete__" }, [o;f] ->
- gen_expr ctx true o;
- gen_expr ctx true f;
- write ctx (HDeleteProp dynamic_prop);
- | TLocal { v_name = "__unprotect__" }, [e] ->
- write ctx (HGetLex (type_path ctx (["flash"],"Boot")));
- gen_expr ctx true e;
- write ctx (HCallProperty (ident "__unprotect__",1));
- | TLocal { v_name = "__typeof__" }, [e] ->
- gen_expr ctx true e;
- write ctx HTypeof
- | TLocal { v_name = "__in__" }, [e; f] ->
- gen_expr ctx true e;
- gen_expr ctx true f;
- write ctx (HOp A3OIn)
- | TLocal { v_name = "__resources__" }, [] ->
- let count = ref 0 in
- Hashtbl.iter (fun name data ->
- incr count;
- write ctx (HString "name");
- write ctx (HString name);
- write ctx (HObject 1);
- ) ctx.com.resources;
- write ctx (HArray !count)
- | TLocal { v_name = "__vmem_set__" }, [{ eexpr = TConst (TInt code) };e1;e2] ->
- gen_expr ctx true e2;
- gen_expr ctx true e1;
- write ctx (HOp (match code with
- | 0l -> A3OMemSet8
- | 1l -> A3OMemSet16
- | 2l -> A3OMemSet32
- | 3l -> A3OMemSetFloat
- | 4l -> A3OMemSetDouble
- | _ -> assert false
- ))
- | TLocal { v_name = "__vmem_get__" }, [{ eexpr = TConst (TInt code) };e] ->
- gen_expr ctx true e;
- write ctx (HOp (match code with
- | 0l -> A3OMemGet8
- | 1l -> A3OMemGet16
- | 2l -> A3OMemGet32
- | 3l -> A3OMemGetFloat
- | 4l -> A3OMemGetDouble
- | _ -> assert false
- ))
- | TLocal { v_name = "__vmem_sign__" }, [{ eexpr = TConst (TInt code) };e] ->
- gen_expr ctx true e;
- write ctx (HOp (match code with
- | 0l -> A3OSign1
- | 1l -> A3OSign8
- | 2l -> A3OSign16
- | _ -> assert false
- ))
- | TLocal { v_name = "__vector__" }, [ep] ->
- gen_type ctx (type_id ctx r);
- write ctx HGetGlobalScope;
- gen_expr ctx true ep;
- write ctx (HCallStack 1)
- | TArray ({ eexpr = TLocal { v_name = "__global__" } },{ eexpr = TConst (TString s) }), _ ->
- (match gen_access ctx e Read with
- | VGlobal id ->
- write ctx (HFindPropStrict id);
- List.iter (gen_expr ctx true) el;
- write ctx (HCallProperty (id,List.length el));
- | _ -> assert false)
- | TConst TSuper , _ ->
- write ctx HThis;
- List.iter (gen_expr ctx true) el;
- write ctx (HConstructSuper (List.length el));
- | TField ({ eexpr = TConst TSuper },f) , _ ->
- let id = ident (field_name f) in
- write ctx (HFindPropStrict id);
- List.iter (gen_expr ctx true) el;
- write ctx (HCallSuper (id,List.length el));
- coerce ctx (classify ctx r);
- | TField ({ eexpr = TConst TThis },f) , _ when not ctx.in_static ->
- let id = ident (field_name f) in
- write ctx (HFindProp id);
- List.iter (gen_expr ctx true) el;
- if retval then begin
- write ctx (HCallProperty (id,List.length el));
- coerce ctx (classify ctx r);
- end else
- write ctx (HCallPropVoid (id,List.length el))
- | TField (e1,f) , _ ->
- let old = ctx.for_call in
- ctx.for_call <- true;
- gen_expr ctx true e1;
- let id , _, _ = property ctx (field_name f) e1.etype in
- ctx.for_call <- old;
- List.iter (gen_expr ctx true) el;
- if retval then begin
- write ctx (HCallProperty (id,List.length el));
- coerce ctx (classify ctx r);
- end else
- write ctx (HCallPropVoid (id,List.length el))
- | _ ->
- gen_expr ctx true e;
- write ctx HGetGlobalScope;
- List.iter (gen_expr ctx true) el;
- write ctx (HCallStack (List.length el));
- coerce ctx (classify ctx r)
- and gen_unop ctx retval op flag e =
- let k = classify ctx e.etype in
- match op with
- | Not ->
- gen_expr ctx true e;
- write ctx (HOp A3ONot);
- | Neg ->
- gen_expr ctx true e;
- write ctx (HOp (if k = KInt then A3OINeg else A3ONeg));
- | NegBits ->
- gen_expr ctx true e;
- write ctx (HOp A3OBitNot);
- | Increment
- | Decrement ->
- let incr = (op = Increment) in
- let r = (match e.eexpr with TLocal v -> get_local_register ctx v | _ -> None) in
- match r with
- | Some r when r.rtype = KInt ->
- if not r.rinit then r.rcond <- true;
- if retval && flag = Postfix then getvar ctx (VReg r);
- write ctx (if incr then HIncrIReg r.rid else HDecrIReg r.rid);
- if retval && flag = Prefix then getvar ctx (VReg r);
- | _ ->
- let acc_read, acc_write = gen_access_rw ctx e in
- let op = (match k, incr with
- | KInt, true -> A3OIIncr
- | KInt, false -> A3OIDecr
- | _ , true -> A3OIncr
- | _ , false -> A3ODecr
- ) in
- getvar ctx acc_read;
- match flag with
- | Postfix when retval ->
- let r = alloc_reg ctx k in
- write ctx HDup;
- set_reg ctx r;
- write ctx (HOp op);
- setvar ctx acc_write None;
- write ctx (HReg r.rid);
- free_reg ctx r
- | Postfix | Prefix ->
- write ctx (HOp op);
- setvar ctx acc_write (if retval then Some k else None)
- and check_binop ctx e1 e2 =
- let invalid = (match classify ctx e1.etype, classify ctx e2.etype with
- | KInt, KUInt | KUInt, KInt -> (match e1.eexpr, e2.eexpr with TConst (TInt i) , _ | _ , TConst (TInt i) -> i < 0l | _ -> true)
- | _ -> false) in
- if invalid then error "Comparison of Int and UInt might lead to unexpected results" (punion e1.epos e2.epos);
- and gen_binop ctx retval op e1 e2 t p =
- let write_op op =
- let iop = (match op with
- | OpAdd -> Some A3OIAdd
- | OpSub -> Some A3OISub
- | OpMult -> Some A3OIMul
- | _ -> None
- ) in
- let op = (match op with
- | OpAdd -> A3OAdd
- | OpSub -> A3OSub
- | OpMult -> A3OMul
- | OpDiv -> A3ODiv
- | OpAnd -> A3OAnd
- | OpOr -> A3OOr
- | OpXor -> A3OXor
- | OpShl -> A3OShl
- | OpShr -> A3OShr
- | OpUShr -> A3OUShr
- | OpMod -> A3OMod
- | _ -> assert false
- ) in
- match iop with
- | Some iop ->
- let k1 = classify ctx e1.etype in
- let k2 = classify ctx e2.etype in
- (match k1, k2 with
- | KInt, KInt | KUInt, KUInt | KInt, KUInt | KUInt, KInt -> write ctx (HOp iop)
- | _ ->
- write ctx (HOp op);
- (* add is a generic operation, so let's make sure we don't loose our type in the process *)
- if op = A3OAdd then coerce ctx (classify ctx t))
- | _ ->
- write ctx (HOp op);
- if op = A3OMod && classify ctx e1.etype = KInt && classify ctx e2.etype = KInt then coerce ctx (classify ctx t);
- in
- let gen_op o =
- check_binop ctx e1 e2;
- gen_expr ctx true e1;
- gen_expr ctx true e2;
- write ctx (HOp o)
- in
- let gen_eq() =
- match is_special_compare e1 e2 with
- | None ->
- gen_op A3OEq
- | Some c ->
- let f = FStatic (c,try PMap.find "compare" c.cl_statics with Not_found -> assert false) in
- gen_expr ctx true (mk (TCall (mk (TField (mk (TTypeExpr (TClassDecl c)) t_dynamic p,f)) t_dynamic p,[e1;e2])) ctx.com.basic.tbool p);
- in
- match op with
- | OpAssign ->
- let acc = gen_access ctx e1 Write in
- gen_expr ctx true e2;
- setvar ctx acc (if retval then Some (classify ctx e1.etype) else None)
- | OpBoolAnd ->
- write ctx HFalse;
- let j = jump_expr ctx e1 false in
- let b = begin_branch ctx in
- write ctx HPop;
- gen_expr ctx true e2;
- coerce ctx KBool;
- j();
- b();
- | OpBoolOr ->
- write ctx HTrue;
- let j = jump_expr ctx e1 true in
- let b = begin_branch ctx in
- write ctx HPop;
- gen_expr ctx true e2;
- coerce ctx KBool;
- j();
- b();
- | OpAssignOp op ->
- let racc, wacc = gen_access_rw ctx e1 in
- getvar ctx racc;
- gen_expr ctx true e2;
- write_op op;
- setvar ctx wacc (if retval then Some (classify ctx e1.etype) else None)
- | OpAdd | OpMult | OpDiv | OpSub | OpAnd | OpOr | OpXor | OpShl | OpShr | OpUShr | OpMod ->
- gen_expr ctx true e1;
- gen_expr ctx true e2;
- write_op op
- | OpEq ->
- gen_eq()
- | OpNotEq ->
- gen_eq();
- write ctx (HOp A3ONot)
- | OpGt ->
- gen_op A3OGt
- | OpGte ->
- gen_op A3OGte
- | OpLt ->
- gen_op A3OLt
- | OpLte ->
- gen_op A3OLte
- | OpInterval | OpArrow ->
- assert false
- and gen_expr ctx retval e =
- let old = ctx.infos.istack in
- debug_infos ctx e.epos;
- gen_expr_content ctx retval e;
- if old <> ctx.infos.istack then begin
- if old + 1 <> ctx.infos.istack then stack_error e.epos;
- if not retval then write ctx HPop;
- end else if retval then stack_error e.epos
- and generate_function ctx fdata stat =
- let f = begin_fun ctx fdata.tf_args fdata.tf_type [fdata.tf_expr] stat fdata.tf_expr.epos in
- gen_expr ctx false fdata.tf_expr;
- (match follow fdata.tf_type with
- | TEnum ({ e_path = [],"Void" },[]) | TAbstract ({ a_path = [],"Void" },[]) ->
- debug_infos ctx ~is_min:false fdata.tf_expr.epos;
- write ctx HRetVoid
- | _ ->
- (* check that we have a return that can be accepted by Flash9 VM *)
- let rec loop e =
- match e.eexpr with
- | TBlock [] -> false
- | TBlock l -> loop (List.hd (List.rev l))
- | TReturn None -> true
- | TReturn (Some e) ->
- let rec inner_loop e =
- match e.eexpr with
- | TSwitch _ | TMatch _ | TFor _ | TWhile _ | TTry _ -> false
- | TIf _ -> loop e
- | TParenthesis e -> inner_loop e
- | _ -> true
- in
- inner_loop e
- | TIf (_,e1,Some e2) -> loop e1 && loop e2
- | TSwitch (_,_,Some e) -> loop e
- | TParenthesis e -> loop e
- | _ -> false
- in
- if not (loop fdata.tf_expr) then write ctx HRetVoid;
- );
- f()
- and jump_expr_gen ctx e jif jfun =
- match e.eexpr with
- | TParenthesis e -> jump_expr_gen ctx e jif jfun
- | TBinop (op,e1,e2) ->
- let j t f =
- check_binop ctx e1 e2;
- gen_expr ctx true e1;
- gen_expr ctx true e2;
- jfun (if jif then t else f)
- in
- (match op with
- | OpEq when is_special_compare e1 e2 = None -> j J3Eq J3Neq
- | OpNotEq when is_special_compare e1 e2 = None -> j J3Neq J3Eq
- | OpGt -> j J3Gt J3NotGt
- | OpGte -> j J3Gte J3NotGte
- | OpLt -> j J3Lt J3NotLt
- | OpLte -> j J3Lte J3NotLte
- | _ ->
- gen_expr ctx true e;
- jfun (if jif then J3True else J3False))
- | _ ->
- gen_expr ctx true e;
- jfun (if jif then J3True else J3False)
- and jump_expr ctx e jif =
- jump_expr_gen ctx e jif (jump ctx)
- let do_debug ctx meta =
- let old = ctx.debug in
- ctx.debug <- (old || Meta.has Meta.Debug meta) && not (Meta.has Meta.NoDebug meta);
- (fun() -> ctx.debug <- old)
- let generate_method ctx fdata stat fmeta =
- let old = do_debug ctx fmeta in
- let m = generate_function ctx fdata stat in
- old();
- m
- let generate_construct ctx fdata c =
- (* make all args optional to allow no-param constructor *)
- let cargs = if not ctx.need_ctor_skip then fdata.tf_args else List.map (fun (v,c) ->
- let c = (match c with Some _ -> c | None ->
- Some (match classify ctx v.v_type with
- | KInt | KUInt -> TInt 0l
- | KFloat -> TFloat "0"
- | KBool -> TBool false
- | KType _ | KDynamic | KNone -> TNull)
- ) in
- v,c
- ) fdata.tf_args in
- let f = begin_fun ctx cargs fdata.tf_type [ethis;fdata.tf_expr] false fdata.tf_expr.epos in
- (* if skip_constructor, then returns immediatly *)
- if ctx.need_ctor_skip then (match c.cl_kind with
- | KGenericInstance _ -> ()
- | _ when not (Codegen.constructor_side_effects fdata.tf_expr) -> ()
- | _ ->
- let id = ident "skip_constructor" in
- getvar ctx (VGlobal (type_path ctx (["flash"],"Boot")));
- getvar ctx (VId id);
- let j = jump ctx J3False in
- write ctx HRetVoid;
- j());
- (* --- *)
- PMap.iter (fun _ f ->
- match f.cf_expr, f.cf_kind with
- | Some { eexpr = TFunction fdata }, Method MethDynamic ->
- let id = ident f.cf_name in
- write ctx (HFindProp id);
- write ctx (HGetProp id);
- let j = jump ctx J3True in
- write ctx (HFindProp id);
- write ctx (HFunction (generate_method ctx fdata false []));
- write ctx (HInitProp id);
- j();
- | _ -> ()
- ) c.cl_fields;
- gen_expr ctx false fdata.tf_expr;
- debug_infos ctx ~is_min:false fdata.tf_expr.epos;
- write ctx HRetVoid;
- f() , List.length fdata.tf_args
- let rec is_const e =
- match e.eexpr with
- | TConst _ -> true
- | TArrayDecl el | TBlock el -> List.for_all is_const el
- | TObjectDecl fl -> List.for_all (fun (_,e) -> is_const e) fl
- | TParenthesis e -> is_const e
- | TFunction _ -> true
- | _ -> false
- let generate_class_statics ctx c const =
- List.iter (fun f ->
- match f.cf_expr with
- | Some { eexpr = TFunction _ } when (match f.cf_kind with Method (MethNormal | MethInline) -> true | _ -> false) -> ()
- | Some e when is_const e = const ->
- write ctx (HGetLex (type_path ctx c.cl_path));
- gen_expr ctx true e;
- if Codegen.is_volatile f.cf_type then write ctx (HArray 1);
- write ctx (HInitProp (ident f.cf_name));
- | _ -> ()
- ) c.cl_ordered_statics
- let need_init ctx c =
- not ctx.swc && not c.cl_extern && List.exists (fun f -> match f.cf_expr with Some e -> not (is_const e) | _ -> false) c.cl_ordered_statics
- let generate_extern_inits ctx =
- List.iter (fun t ->
- match t with
- | TClassDecl c when c.cl_extern ->
- (match c.cl_init with
- | None -> ()
- | Some e -> gen_expr ctx false e);
- | _ -> ()
- ) ctx.com.types
- let generate_inits ctx =
- let finit = begin_fun ctx [] ctx.com.basic.tvoid [] true null_pos in
- if not ctx.swc then generate_extern_inits ctx;
- List.iter (fun t ->
- match t with
- | TClassDecl c when need_init ctx c ->
- let id = ident "init__" in
- getvar ctx (VGlobal (type_path ctx c.cl_path));
- getvar ctx (VId id);
- let j = jump ctx J3True in
- getvar ctx (VGlobal (type_path ctx c.cl_path));
- write ctx HTrue;
- setvar ctx (VId id) None;
- let branch = begin_branch ctx in
- generate_class_statics ctx c false;
- branch();
- j()
- | _ -> ()
- ) ctx.com.types;
- (match ctx.com.main with
- | None -> ()
- | Some e -> gen_expr ctx false e);
- write ctx HRetVoid;
- finit()
- let generate_class_init ctx c hc =
- write ctx HGetGlobalScope;
- if c.cl_interface then
- write ctx HNull
- else begin
- let path = (match c.cl_super with None -> ([],"Object") | Some (sup,_) -> sup.cl_path) in
- write ctx (HGetLex (type_path ctx path));
- write ctx HScope;
- write ctx (HGetLex (type_path ctx path));
- end;
- write ctx (HClassDef hc);
- List.iter (fun f ->
- match f.cf_expr, f.cf_kind with
- | Some { eexpr = TFunction fdata }, Method MethDynamic ->
- write ctx HDup;
- write ctx (HFunction (generate_method ctx fdata true f.cf_meta));
- write ctx (HInitProp (ident f.cf_name));
- | _ -> ()
- ) c.cl_ordered_statics;
- if not c.cl_interface then write ctx HPopScope;
- write ctx (HInitProp (type_path ctx c.cl_path));
- if ctx.swc && c.cl_path = ctx.boot then generate_extern_inits ctx;
- (match c.cl_init with
- | None -> ()
- | Some e ->
- gen_expr ctx false e;
- if ctx.block_vars <> [] then error "You can't have a local variable referenced from a closure inside __init__ (FP 10.1.53 crash)" e.epos;
- );
- generate_class_statics ctx c true;
- if ctx.swc then begin
- generate_class_statics ctx c false;
- if ctx.block_vars <> [] then error "You can't have a local variable referenced from a closure inside a static (FP 10.1.53 crash)" c.cl_pos;
- end
- let generate_enum_init ctx e hc meta =
- let path = ([],"Object") in
- let name_id = type_path ctx e.e_path in
- write ctx HGetGlobalScope;
- write ctx (HGetLex (type_path ctx path));
- write ctx HScope;
- write ctx (HGetLex (type_path ctx path));
- write ctx (HClassDef hc);
- write ctx HPopScope;
- let r = alloc_reg ctx KDynamic in
- write ctx HDup;
- write ctx (HSetReg r.rid); (* needed for setslot *)
- write ctx (HInitProp name_id);
- let nslot = ref 0 in
- PMap.iter (fun _ f ->
- incr nslot;
- match f.ef_type with
- | TFun _ -> ()
- | _ ->
- write ctx (HReg r.rid);
- write ctx (HFindPropStrict name_id);
- write ctx (HString f.ef_name);
- write ctx (HInt f.ef_index);
- write ctx HNull;
- write ctx (HConstructProperty (name_id,3));
- write ctx (HSetSlot !nslot);
- ) e.e_constrs;
- write ctx (HReg r.rid);
- List.iter (fun n -> write ctx (HString n)) e.e_names;
- write ctx (HArray (List.length e.e_names));
- write ctx (HSetProp (ident "__constructs__"));
- (match meta with
- | None -> ()
- | Some e ->
- write ctx (HReg r.rid);
- gen_expr ctx true e;
- write ctx (HSetProp (ident "__meta__"));
- );
- free_reg ctx r
- let extract_meta meta =
- let rec loop = function
- | [] -> []
- | (Meta.Meta,[ECall ((EConst (Ident n),_),args),_],_) :: l ->
- let mk_arg (a,p) =
- match a with
- | EConst (String s) -> (None, s)
- | EBinop (OpAssign,(EConst (Ident n),_),(EConst (String s),_)) -> (Some n, s)
- | _ -> error "Invalid meta definition" p
- in
- { hlmeta_name = n; hlmeta_data = Array.of_list (List.map mk_arg args) } :: loop l
- | _ :: l -> loop l
- in
- match loop meta with
- | [] -> None
- | l -> Some (Array.of_list l)
- let generate_field_kind ctx f c stat =
- let method_kind() =
- let rec loop = function
- | [] -> f.cf_name, MK3Normal
- | (Meta.Getter,[EConst (Ident f),_],_) :: _ -> f, MK3Getter
- | (Meta.Setter,[EConst (Ident f),_],_) :: _ -> f, MK3Setter
- | _ :: l -> loop l
- in
- loop f.cf_meta
- in
- if is_extern_field f then None else
- match f.cf_expr with
- | Some { eexpr = TFunction fdata } ->
- let rec loop c name =
- match c.cl_super with
- | None -> false
- | Some (c,_) ->
- PMap.exists name c.cl_fields || loop c name
- in
- (match f.cf_kind with
- | Method MethDynamic when List.memq f c.cl_overrides ->
- None
- | Var _ | Method MethDynamic ->
- Some (HFVar {
- hlv_type = Some (type_path ctx ([],"Function"));
- hlv_value = HVNone;
- hlv_const = false;
- })
- | _ ->
- let name, kind = method_kind() in
- let m = generate_method ctx fdata stat f.cf_meta in
- Some (HFMethod {
- hlm_type = m;
- hlm_final = stat || (Meta.has Meta.Final f.cf_meta);
- hlm_override = not stat && loop c name;
- hlm_kind = kind;
- })
- );
- | _ when c.cl_interface && not stat ->
- (match follow f.cf_type, f.cf_kind with
- | TFun (args,tret), Method (MethNormal | MethInline) ->
- let dparams = ref None in
- List.iter (fun (_,o,t) ->
- match !dparams with
- | None -> if o then dparams := Some [HVNone]
- | Some l -> dparams := Some (HVNone :: l)
- ) args;
- let dparams = (match !dparams with None -> None | Some l -> Some (List.rev l)) in
- Some (HFMethod {
- hlm_type = end_fun ctx (List.map (fun (a,opt,t) -> alloc_var a t, (if opt then Some TNull else None)) args) dparams tret;
- hlm_final = false;
- hlm_override = false;
- hlm_kind = snd (method_kind());
- })
- | _ ->
- None)
- | _ ->
- Some (HFVar {
- hlv_type = if Codegen.is_volatile f.cf_type then Some (type_path ctx ([],"Array")) else type_opt ctx f.cf_type;
- hlv_value = HVNone;
- hlv_const = false;
- })
- let generate_class ctx c =
- let name = type_path ctx c.cl_path in
- ctx.cur_class <- c;
- let cid , cnargs = (match c.cl_constructor with
- | None ->
- if c.cl_interface then
- { (empty_method ctx null_pos) with hlmt_function = None }, 0
- else
- generate_construct ctx {
- tf_args = [];
- tf_type = ctx.com.basic.tvoid;
- tf_expr = {
- eexpr = TBlock [];
- etype = ctx.com.basic.tvoid;
- epos = null_pos;
- }
- } c
- | Some f ->
- match f.cf_expr with
- | Some { eexpr = TFunction fdata } ->
- let old = do_debug ctx f.cf_meta in
- let m = generate_construct ctx fdata c in
- old();
- m
- | _ -> assert false
- ) in
- let has_protected = ref None in
- let make_name f stat =
- let rec find_meta c =
- try
- let f = PMap.find f.cf_name (if stat then c.cl_statics else c.cl_fields) in
- if List.memq f c.cl_overrides then raise Not_found;
- f.cf_meta
- with Not_found ->
- match c.cl_super with
- | None -> []
- | Some _ when stat -> []
- | Some (c,_) -> find_meta c
- in
- let protect() =
- let p = (match c.cl_path with [], n -> n | p, n -> String.concat "." p ^ ":" ^ n) in
- has_protected := Some p;
- HMName (f.cf_name,HNProtected p)
- in
- let rec loop_meta = function
- | [] ->
- if not f.cf_public && ctx.swf_protected then
- protect()
- else
- ident f.cf_name
- | x :: l ->
- match x with
- | ((Meta.Getter | Meta.Setter),[EConst (Ident f),_],_) -> ident f
- | (Meta.Ns,[EConst (String ns),_],_) -> HMName (f.cf_name,HNNamespace ns)
- | (Meta.Protected,[],_) -> protect()
- | _ -> loop_meta l
- in
- if c.cl_interface then
- HMName (reserved f.cf_name, HNNamespace (match c.cl_path with [],n -> n | l,n -> String.concat "." l ^ ":" ^ n))
- else
- loop_meta (find_meta c)
- in
- let generate_prop f acc alloc_slot =
- match f.cf_kind with
- | Method _ -> acc
- | Var v ->
- (* let p = f.cf_pos in *)
- (* let ethis = mk (TConst TThis) (TInst (c,[])) p in *)
- acc
- in
- let fields = PMap.fold (fun f acc ->
- let acc = generate_prop f acc (fun() -> 0) in
- match generate_field_kind ctx f c false with
- | None -> acc
- | Some k ->
- {
- hlf_name = make_name f false;
- hlf_slot = 0;
- hlf_kind = k;
- hlf_metas = extract_meta f.cf_meta;
- } :: acc
- ) c.cl_fields [] in
- let fields = if c.cl_path <> ctx.boot then fields else begin
- {
- hlf_name = make_name {
- cf_name = "init";
- cf_public = ctx.swc && ctx.swf_protected;
- cf_meta = [];
- cf_doc = None;
- cf_pos = c.cl_pos;
- cf_type = TFun ([],t_dynamic);
- cf_params = [];
- cf_expr = None;
- cf_kind = Method MethNormal;
- cf_overloads = [];
- } false;
- hlf_slot = 0;
- hlf_kind = (HFMethod {
- hlm_type = generate_inits ctx;
- hlm_final = false;
- hlm_override = true;
- hlm_kind = MK3Normal;
- });
- hlf_metas = None;
- } :: fields
- end in
- let st_field_count = ref 0 in
- let st_meth_count = ref 0 in
- let statics = List.rev (List.fold_left (fun acc f ->
- let acc = generate_prop f acc (fun() -> incr st_meth_count; !st_meth_count) in
- match generate_field_kind ctx f c true with
- | None -> acc
- | Some k ->
- let count = (match k with HFMethod _ -> st_meth_count | HFVar _ -> st_field_count | _ -> assert false) in
- incr count;
- {
- hlf_name = make_name f true;
- hlf_slot = !count;
- hlf_kind = k;
- hlf_metas = extract_meta f.cf_meta;
- } :: acc
- ) [] c.cl_ordered_statics) in
- let statics = if not (need_init ctx c) then statics else
- {
- hlf_name = ident "init__";
- hlf_slot = (incr st_field_count; !st_field_count);
- hlf_kind = HFVar { hlv_type = (Some (type_id ctx ctx.com.basic.tbool)); hlv_value = HVNone; hlv_const = false; };
- hlf_metas = None;
- } :: statics
- in
- let rec is_dynamic c =
- if c.cl_dynamic <> None || c.cl_array_access <> None then true
- else match c.cl_super with
- | None -> false
- | Some (c,_) -> is_dynamic c
- in
- {
- hlc_index = 0;
- hlc_name = name;
- hlc_super = (if c.cl_interface then None else Some (type_path ctx (match c.cl_super with None -> [],"Object" | Some (c,_) -> c.cl_path)));
- hlc_sealed = not (is_dynamic c);
- hlc_final = Meta.has Meta.Final c.cl_meta;
- hlc_interface = c.cl_interface;
- hlc_namespace = (match !has_protected with None -> None | Some p -> Some (HNProtected p));
- hlc_implements = Array.of_list (List.map (fun (c,_) ->
- if not c.cl_interface then error "Can't implement class in Flash9" c.cl_pos;
- let pack, name = real_path c.cl_path in
- HMMultiName (Some name,[HNPublic (Some (String.concat "." pack))])
- ) c.cl_implements);
- hlc_construct = cid;
- hlc_fields = Array.of_list fields;
- hlc_static_construct = empty_method ctx c.cl_pos;
- hlc_static_fields = Array.of_list statics;
- }
- let generate_enum ctx e meta =
- let name_id = type_path ctx e.e_path in
- let api = ctx.com.basic in
- let f = begin_fun ctx [alloc_var "tag" api.tstring, None;alloc_var "index" api.tint, None;alloc_var "params" (mk_mono()), None] api.tvoid [ethis] false e.e_pos in
- let tag_id = ident "tag" in
- let index_id = ident "index" in
- let params_id = ident "params" in
- write ctx (HFindProp tag_id);
- write ctx (HReg 1);
- write ctx (HInitProp tag_id);
- write ctx (HFindProp index_id);
- write ctx (HReg 2);
- write ctx (HInitProp index_id);
- write ctx (HFindProp params_id);
- write ctx (HReg 3);
- write ctx (HInitProp params_id);
- write ctx HRetVoid;
- let construct = f() in
- let f = begin_fun ctx [] api.tstring [] true e.e_pos in
- write ctx (HGetLex (type_path ctx (["flash"],"Boot")));
- write ctx HThis;
- write ctx (HCallProperty (ident "enum_to_string",1));
- write ctx HRet;
- let tostring = f() in
- let st_count = ref 0 in
- let constrs = PMap.fold (fun f acc ->
- incr st_count;
- {
- hlf_name = ident f.ef_name;
- hlf_slot = !st_count;
- hlf_kind = (match f.ef_type with
- | TFun (args,_) ->
- let fdata = begin_fun ctx (List.map (fun (a,opt,t) -> alloc_var a t, (if opt then Some TNull else None)) args) (TEnum (e,[])) [] true f.ef_pos in
- write ctx (HFindPropStrict name_id);
- write ctx (HString f.ef_name);
- write ctx (HInt f.ef_index);
- let n = ref 0 in
- List.iter (fun _ -> incr n; write ctx (HReg !n)) args;
- write ctx (HArray (!n));
- write ctx (HConstructProperty (name_id,3));
- write ctx HRet;
- let fid = fdata() in
- HFMethod {
- hlm_type = fid;
- hlm_final = true;
- hlm_override = false;
- hlm_kind = MK3Normal;
- }
- | _ ->
- HFVar { hlv_type = (Some name_id); hlv_value = HVNone; hlv_const = false; }
- );
- hlf_metas = None;
- } :: acc
- ) e.e_constrs [] in
- let constrs = (match meta with
- | None -> constrs
- | Some _ ->
- incr st_count;
- {
- hlf_name = ident "__meta__";
- hlf_slot = !st_count;
- hlf_kind = HFVar { hlv_type = None; hlv_value = HVNone; hlv_const = false; };
- hlf_metas = None;
- } :: constrs
- ) in
- {
- hlc_index = 0;
- hlc_name = name_id;
- hlc_super = Some (type_path ctx ([],"Object"));
- hlc_sealed = true;
- hlc_final = true;
- hlc_interface = false;
- hlc_namespace = None;
- hlc_implements = [||];
- hlc_construct = construct;
- hlc_fields = [|
- { hlf_name = tag_id; hlf_slot = 0; hlf_kind = HFVar { hlv_type = Some (HMPath ([],"String")); hlv_value = HVNone; hlv_const = false; }; hlf_metas = None };
- { hlf_name = index_id; hlf_slot = 0; hlf_kind = HFVar { hlv_type = Some (HMPath ([],"int")); hlv_value = HVNone; hlv_const = false; }; hlf_metas = None };
- { hlf_name = params_id; hlf_slot = 0; hlf_kind = HFVar { hlv_type = Some (HMPath ([],"Array")); hlv_value = HVNone; hlv_const = false; }; hlf_metas = None };
- { hlf_name = ident "__enum__"; hlf_slot = 0; hlf_kind = HFVar { hlv_type = Some (HMPath ([],"Boolean")); hlv_value = HVBool true; hlv_const = true }; hlf_metas = None };
- {
- hlf_name = ident "toString";
- hlf_slot = 0;
- hlf_kind = HFMethod {
- hlm_type = tostring;
- hlm_final = true;
- hlm_override = false;
- hlm_kind = MK3Normal;
- };
- hlf_metas = None;
- };
- |];
- hlc_static_construct = empty_method ctx e.e_pos;
- hlc_static_fields = Array.of_list ({
- hlf_name = ident "__isenum";
- hlf_slot = !st_count + 2;
- hlf_kind = HFVar { hlv_type = Some (HMPath ([],"Boolean")); hlv_value = HVBool true; hlv_const = true; };
- hlf_metas = None;
- } :: {
- hlf_name = ident "__constructs__";
- hlf_slot = !st_count + 1;
- hlf_kind = HFVar { hlv_type = None; hlv_value = HVNone; hlv_const = false; };
- hlf_metas = None;
- } :: constrs);
- }
- let rec generate_type ctx t =
- match t with
- | TClassDecl c ->
- if c.cl_path = (["flash";"_Boot"],"RealBoot") then c.cl_path <- ctx.boot;
- if c.cl_extern && (c.cl_path <> ([],"Dynamic") || Meta.has Meta.RealPath c.cl_meta) then
- None
- else
- let debug = do_debug ctx c.cl_meta in
- let hlc = generate_class ctx c in
- let init = begin_fun ctx [] ctx.com.basic.tvoid [ethis] false c.cl_pos in
- generate_class_init ctx c hlc;
- write ctx HRetVoid;
- debug();
- Some (init(), {
- hlf_name = type_path ctx c.cl_path;
- hlf_slot = 0;
- hlf_kind = HFClass hlc;
- hlf_metas = extract_meta c.cl_meta;
- })
- | TEnumDecl e ->
- if e.e_extern then
- None
- else
- let meta = Codegen.build_metadata ctx.com t in
- let hlc = generate_enum ctx e meta in
- let init = begin_fun ctx [] ctx.com.basic.tvoid [ethis] false e.e_pos in
- generate_enum_init ctx e hlc meta;
- write ctx HRetVoid;
- Some (init(), {
- hlf_name = type_path ctx e.e_path;
- hlf_slot = 0;
- hlf_kind = HFClass hlc;
- hlf_metas = extract_meta e.e_meta;
- })
- | TAbstractDecl ({ a_path = [],"Dynamic" } as a) ->
- generate_type ctx (TClassDecl (mk_class a.a_module a.a_path a.a_pos))
- | TTypeDecl _ | TAbstractDecl _ ->
- None
- let resource_path name =
- (["_res"],"_" ^ String.concat "_" (ExtString.String.nsplit name "."))
- let generate_resource ctx name =
- let c = mk_class null_module (resource_path name) null_pos in
- c.cl_super <- Some (mk_class null_module (["flash";"utils"],"ByteArray") null_pos,[]);
- let t = TClassDecl c in
- match generate_type ctx t with
- | Some (m,f) -> (t,m,f)
- | None -> assert false
- let generate com boot_name =
- let ctx = {
- com = com;
- need_ctor_skip = Common.has_feature com "Type.createEmptyInstance";
- debug = com.Common.debug;
- cur_class = null_class;
- boot = ([],boot_name);
- debugger = Common.defined com Define.Fdb;
- swc = Common.defined com Define.Swc;
- swf_protected = Common.defined com Define.SwfProtected;
- code = DynArray.create();
- locals = PMap.empty;
- infos = default_infos();
- trys = [];
- breaks = [];
- continues = [];
- block_vars = [];
- in_static = false;
- last_line = -1;
- last_file = "";
- try_scope_reg = None;
- for_call = false;
- } in
- let types = if ctx.swc && com.main_class = None then
- (*
- make sure that both Boot and RealBoot are the first two classes in the SWC
- this way initializing RealBoot will also run externs __init__ blocks before
- another class static is defined
- *)
- let hd = ref [] in
- let types = List.fold_left (fun acc t ->
- match t_path t with
- | ["flash";"_Boot"],"RealBoot" -> hd := !hd @ [t]; acc
- | ["flash"], "Boot" -> hd := t :: !hd; acc
- | _ -> t :: acc
- ) [] com.types in
- !hd @ List.rev types
- else
- com.types
- in
- let res = Hashtbl.fold (fun name _ acc -> generate_resource ctx name :: acc) com.resources [] in
- let classes = List.fold_left (fun acc t ->
- match generate_type ctx t with
- | None -> acc
- | Some (m,f) -> (t,m,f) :: acc
- ) res types in
- List.rev classes
- ;;
- Random.self_init();
- gen_expr_ref := gen_expr
|