瀏覽代碼

bootstrap working.

Nicolas Cannasse 19 年之前
父節點
當前提交
3e387b4195
共有 1 個文件被更改,包括 240 次插入50 次删除
  1. 240 50
      genswf9.ml

+ 240 - 50
genswf9.ml

@@ -28,9 +28,19 @@ type ('a,'b) gen_lookup = {
 type 'a lookup = ('a,'a index) gen_lookup
 type 'a lookup_nz = ('a,'a index_nz) gen_lookup
 
+type code_infos = {
+	mutable iregs : int;
+	mutable imaxregs : int;
+	mutable ipos : int;
+	mutable istack : int;
+	mutable imax : int;
+	mutable iscopes : int;
+	mutable imaxscopes : int;
+}
+
 type context = {
 	(* globals *)
-	idents : string lookup;
+	strings : string lookup;
 	ints : int32 lookup;
 	floats : float lookup;
 	brights : as3_base_right lookup;
@@ -39,14 +49,13 @@ type context = {
 	mtypes : as3_method_type lookup_nz;
 	mutable classes : as3_class list;
 	mutable statics : as3_static list;
-	mutable inits : as3_static list;
 	functions : as3_function lookup;
 	rpublic : as3_base_right index;
 
 	(* per-function *)
 	mutable locals : (string,int) PMap.t;
 	mutable code : as3_opcode DynArray.t;
-	mutable pos : int;
+	mutable infos : code_infos;	
 }
 
 let public = A3RPublic None
@@ -61,6 +70,82 @@ let mt0 = {
 	mt3_unk_flags = (false,false,false,false);
 }
 
+let stack_delta = function
+	| A3Throw -> -1
+	| A3GetSuper _ -> 1
+	| A3SetSuper _ -> -1
+	| A3RegReset _ -> 0
+	| A3Nop -> 0
+	| A3Jump _ -> 0
+	| A3Switch _ -> -1
+	| A3PopScope -> 0
+	| A3XmlOp3 -> assert false
+	| A3ForIn | A3ForEach -> assert false
+	| A3Null
+	| A3Undefined
+	| A3SmallInt _
+	| A3Int _
+	| A3True
+	| A3False
+	| A3String _
+	| A3IntRef _
+	| A3Function _
+	| A3Float _
+	| A3NaN -> 1
+	| A3Pop -> -1
+	| A3Dup -> 1
+	| A3CatchDone -> assert false
+	| A3Scope -> -1
+	| A3Next _ -> 0
+	| A3StackCall n -> -(n + 2)
+	| A3StackNew n -> -(n + 2)
+	| A3SuperCall (_,n) -> -(n + 1)
+	| A3Call (_,n) -> -(n + 1)
+	| A3RetVoid -> 0
+	| A3Ret -> -1
+	| A3SuperConstr n -> -(n + 1)
+	| A3New (_,n) -> -n
+	| A3SuperCallUnknown (_,n) -> -(n + 1)
+	| A3CallUnknown (_,n) -> -(n + 1)
+	| A3Object n -> -(n * 2)
+	| A3Array n -> -n
+	| A3NewBlock -> 1
+	| A3ClassDef _ -> 0
+	| A3XmlOp1 _ -> assert false
+	| A3Catch _ -> assert false
+	| A3GetInf _ -> 1
+	| A3SetInf _ -> 1
+	| A3GetProp _ -> 1
+	| A3SetProp _ -> -1
+	| A3Reg _ -> 1
+	| A3SetReg _ -> -1
+	| A3GetScope _ -> 1	
+	| A3Get _ -> 1
+	| A3Set _ -> -2
+	| A3Delete _ -> -1
+	| A3GetSlot _ -> 0
+	| A3SetSlot _ -> -2
+	| A3ToInt
+	| A3ToUInt
+	| A3ToNumber
+	| A3ToObject
+	| A3ToString
+	| A3ToBool -> 0
+	| A3XmlOp2 -> assert false
+	| A3Cast _ -> 0
+	| A3Typeof
+	| A3InstanceOf -> -1
+	| A3IncrReg _ -> 0
+	| A3This -> 1
+	| A3DebugReg _ 
+	| A3DebugLine _
+	| A3DebugFile _ -> 0
+	| A3Op op ->
+		(match op with
+		| A3Neg | A3Incr | A3Decr | A3Not | A3BitNot | A3IIncr | A3IDecr -> 0
+		| _ -> -1)
+	| A3Unk _ -> assert false
+
 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
@@ -85,11 +170,27 @@ let add i w =
 
 let lookup_array w = DynArray.to_array w.a
 
-let ident ctx i = lookup i ctx.idents
+let string ctx i = lookup i ctx.strings
 
 let write ctx op =
 	DynArray.add ctx.code op;
-	ctx.pos <- As3code.length op + ctx.pos
+	ctx.infos.ipos <- As3code.length op + ctx.infos.ipos;
+	let s = ctx.infos.istack + stack_delta op in	
+	ctx.infos.istack <- s;
+	if s > ctx.infos.imax then ctx.infos.imax <- s;
+	match op with
+	| A3Scope ->
+		let n = ctx.infos.iscopes + 1 in
+		ctx.infos.iscopes <- n;
+		if n > ctx.infos.imaxscopes then ctx.infos.imaxscopes <- n
+	| A3PopScope ->
+		ctx.infos.iscopes <- ctx.infos.iscopes - 1
+	| _ ->
+		()
+
+let debug ctx ?file line =
+	(match file with None -> () | Some f -> write ctx (A3DebugFile (tid (string ctx f))));
+	write ctx (A3DebugLine line)
 
 let acc_ident ctx i =
 	try
@@ -98,12 +199,32 @@ let acc_ident ctx i =
 		Not_found -> assert false
 
 let type_path ctx ?(getclass=false) (pack,name) =
-	let pid = ident ctx (String.concat "." pack) in
-	let nameid = ident ctx name in
-	let pid = lookup (A3RPublic (Some pid)) ctx.brights in
-	let tid = lookup (if getclass then A3TClassInterface (Some nameid,pid) else A3TMethodVar (nameid,pid)) ctx.types in
+	let pid = string ctx (String.concat "." pack) in
+	let nameid = string ctx name in
+	let pid = lookup (A3RPublic (Some pid)) ctx.brights in	
+	let tid = lookup (if getclass then A3TClassInterface (Some nameid,lookup [pid] ctx.rights) else A3TMethodVar (nameid,pid)) ctx.types in
 	tid
 
+let ident ctx i = type_path ctx ([],i)
+let tident ctx i = tid (ident ctx i)
+
+let default_infos n =
+	{ ipos = 0; istack = 0; imax = 0; iregs = n; imaxregs = n; iscopes = 0; imaxscopes = 0 }
+
+let alloc_reg ctx =
+	let r = ctx.infos.iregs + 1 in
+	ctx.infos.iregs <- r;
+	if ctx.infos.imaxregs < r then ctx.infos.imaxregs <- r;
+	r
+
+let open_block ctx =
+	let old_stack = ctx.infos.istack in
+	let old_regs = ctx.infos.iregs in
+	(fun() ->
+		if ctx.infos.istack <> old_stack then assert false;
+		ctx.infos.iregs <- old_regs
+	)
+
 let begin_fun ctx args =
 	let mt = {
 		mt3_ret = None;
@@ -117,18 +238,18 @@ let begin_fun ctx args =
 	} in
 	let old_locals = ctx.locals in
 	let old_code = ctx.code in
-	let old_pos = ctx.pos in
-	let count = ref 0 in
-	ctx.locals <- List.fold_left (fun acc name -> incr count; PMap.add name (!count) acc) PMap.empty args;
+	let old_infos = ctx.infos in
+	ctx.infos <- default_infos (List.length args);
 	ctx.code <- DynArray.create();
-	ctx.pos <- 0;
+	ctx.locals <- List.fold_left (fun acc name -> PMap.add name (alloc_reg ctx) acc) PMap.empty args;
+	write ctx (A3DebugFile (tid (string ctx "test")));
 	(fun () ->
 		let f = {
 			fun3_id = add mt ctx.mtypes;
-			fun3_unk1 = 2;
-			fun3_unk2 = 1;
+			fun3_stack_size = ctx.infos.imax;
+			fun3_nregs = ctx.infos.imaxregs + 1;
 			fun3_unk3 = 1;
-			fun3_unk4 = 3;
+			fun3_max_scope = ctx.infos.imaxscopes + 1;
 			fun3_code = DynArray.to_list ctx.code;
 			fun3_trys = [||];
 			fun3_locals = [||];
@@ -136,33 +257,81 @@ let begin_fun ctx args =
 		ignore(add f ctx.functions);
 		ctx.locals <- old_locals;
 		ctx.code <- old_code;
-		ctx.pos <- old_pos;
+		ctx.infos <- old_infos;
 		f.fun3_id
 	)
 
+let gen_constant ctx c =
+	match c with
+	| TInt i ->
+		if Int32.compare i (-128l) > 0 && Int32.compare i 128l < 0 then
+			write ctx (A3SmallInt (Int32.to_int i))
+		else
+			write ctx (A3IntRef (tid (lookup i ctx.ints)))
+	| TFloat f ->
+		let f = float_of_string f in
+		write ctx (A3Float (tid (lookup f ctx.floats)))
+	| TString s ->
+		write ctx (A3String (tid (lookup s ctx.strings)))
+	| TBool b ->
+		write ctx (if b then A3True else A3False)
+	| TNull ->
+		write ctx A3Null
+	| TThis ->
+		write ctx A3This
+	| TSuper ->
+		assert false
+
+let rec gen_expr ctx e =
+	match e.eexpr with
+	| TConst c ->
+		gen_constant ctx c
+	| TThrow e ->
+		gen_expr ctx e;
+		write ctx A3Throw
+	| TField (e,f) ->
+		gen_expr ctx e;
+		write ctx (A3Get (tid (type_path ctx ([],f))))
+	| TTypeExpr t ->
+		write ctx (A3GetScope (0,true));
+		write ctx (A3Get (tid (type_path ctx (t_path t))));
+	| _ ->
+		assert false
+
 let generate_construct ctx args =
 	let f = begin_fun ctx args in
+	write ctx A3NaN;
+	write ctx A3Throw;
 	write ctx A3This;
-	write ctx A3Context;
+	write ctx A3Scope;
 	write ctx A3This;
 	List.iter (acc_ident ctx) args;
 	write ctx (A3SuperConstr (List.length args));
 	write ctx A3RetVoid;
 	f()
 
-let generate_class_init ctx c =
-	let f = begin_fun ctx [] in
-	write ctx A3This;
-	write ctx A3Context;
-	write ctx (A3LoadBlock 0);
-	write ctx (A3GetProp (tid (type_path ctx ([],"Object"))));
-	write ctx A3Context;
-	write ctx (A3GetProp (tid (type_path ~getclass:true ctx ([],"Object"))));
-	write ctx (A3ClassDef (List.length ctx.classes));
-	write ctx A3PopContext;
+let generate_class_init ctx c slot =
+	write ctx (A3GetScope (0,true));
+	let path = (match c.cl_super with None -> ([],"Object") | Some (sup,_) -> sup.cl_path) in
+	write ctx (A3GetProp (tid (type_path ctx path)));
+	write ctx A3Scope;
+	write ctx (A3GetProp (tid (type_path ~getclass:true ctx path)));
+	write ctx (A3ClassDef slot);
+	write ctx A3PopScope;
+	let r = alloc_reg ctx in
+	write ctx A3Dup;
+	write ctx (A3SetReg r);	
 	write ctx (A3Set (tid (type_path ctx c.cl_path)));
-	write ctx A3RetVoid;
-	f()
+	let nslot = ref 0 in
+	List.iter (fun f ->
+		incr nslot;
+		match f.cf_expr with
+		| Some { eexpr = TFunction _ } | None -> ()
+		| Some e ->
+			write ctx (A3Reg r);
+			gen_expr ctx e;
+			write ctx (A3SetSlot !nslot);
+	) c.cl_ordered_statics
 
 let generate_class_static ctx c =
 	let f = begin_fun ctx [] in
@@ -189,7 +358,7 @@ let generate_class ctx c =
 	let fields = [||] in
 	let sc = {
 		cl3_name = name_id;
-		cl3_super = (match c.cl_super with None -> Some (type_path ctx ([],"Object")) | Some _ -> assert false);
+		cl3_super = Some (type_path ctx (match c.cl_super with None -> [],"Object" | Some (c,_) -> c.cl_path));
 		cl3_sealed = true;
 		cl3_final = false;
 		cl3_interface = false;
@@ -198,24 +367,21 @@ let generate_class ctx c =
 		cl3_construct = cid;
 		cl3_fields = fields;
 	} in
+	let st_count = ref 0 in
 	let st = {
 		st3_method = st_id;
-		st3_fields = [||];
-	} in
-	let ic = {
-		st3_method = generate_class_init ctx c;
-		st3_fields = [|
+		st3_fields = Array.of_list (List.map (fun f ->
+			incr st_count;
 			{
-				f3_name = sc.cl3_name;
-				f3_slot = 1;
-				f3_kind = A3FClass (index_nz_int (List.length ctx.classes));
+				f3_name = ident ctx f.cf_name;
+				f3_slot = !st_count;
+				f3_kind = A3FVar { v3_type = None; v3_value = A3VNone; v3_const = false };				
 				f3_metas = None;
 			}
-		|];
-	} in	
+		) c.cl_ordered_statics)
+	} in
 	ctx.classes <- sc :: ctx.classes;
 	ctx.statics <- st :: ctx.statics;
-	ctx.inits <- ic :: ctx.inits;
 	()
 
 let generate_type ctx t =
@@ -228,13 +394,37 @@ let generate_type ctx t =
 		| _ ->
 			failwith (Ast.s_type_path e.e_path)
 
+let generate_inits ctx types =
+	let f = begin_fun ctx [] in
+	write ctx A3This;
+	write ctx A3Scope;
+	let slot = ref 0 in
+	let classes = List.fold_left (fun acc t ->
+		match t with
+		| TClassDecl c when not c.cl_extern ->
+			incr slot;
+			generate_class_init ctx c (!slot - 1);
+			{ 
+				f3_name = type_path ctx c.cl_path;
+				f3_slot = !slot;
+				f3_kind = A3FClass (index_nz_int (!slot - 1));
+				f3_metas = None;
+			} :: acc
+		| _ -> acc
+	) [] types in
+	write ctx A3RetVoid;	
+	{
+		st3_method = f();
+		st3_fields = Array.of_list (List.rev classes);
+	}
+	
 let generate types hres =
 	let brights = new_lookup() in
-	let idents = new_lookup() in
-	let empty_id = lookup "" idents in
+	let strings = new_lookup() in
+	let empty_id = lookup "" strings in
 	let rpublic = lookup (A3RPublic (Some empty_id)) brights in
 	let ctx = {
-		idents = idents;
+		strings = strings;
 		ints = new_lookup();
 		floats = new_lookup();
 		brights = brights;
@@ -244,20 +434,20 @@ let generate types hres =
 		rpublic = rpublic;
 		classes = [];
 		statics = [];
-		inits = [];
 		functions = new_lookup();
 
 		code = DynArray.create();
 		locals = PMap.empty;
-		pos = 0;
+		infos = default_infos 0;
 	} in
 	ignore(lookup [ctx.rpublic] ctx.rights);
 	List.iter (generate_type ctx) types;
 	Hashtbl.iter (fun _ _ -> assert false) hres;
+	let init = generate_inits ctx types in
 	let a = {
 		as3_ints = lookup_array ctx.ints;
 		as3_floats = lookup_array ctx.floats;
-		as3_idents = lookup_array ctx.idents;
+		as3_idents = lookup_array ctx.strings;
 		as3_base_rights = lookup_array ctx.brights;
 		as3_rights = lookup_array ctx.rights;
 		as3_types = lookup_array ctx.types;
@@ -265,8 +455,8 @@ let generate types hres =
 		as3_metadatas = [||];
 		as3_classes = Array.of_list (List.rev ctx.classes);
 		as3_statics = Array.of_list (List.rev ctx.statics);
-		as3_inits = Array.of_list (List.rev ctx.inits);
+		as3_inits = [|init|];
 		as3_functions = lookup_array ctx.functions;
 		as3_unknown = "";
 	} in
-	[Swf.TActionScript3 (None,a); Swf.TSwf9Name [0,"Test"]]
+	[Swf.TActionScript3 (None,a)]