浏览代码

fixed SWF loading issues : class boot_xxxx extends flash.Boot
ensure single initialization for classes statics

Nicolas Cannasse 14 年之前
父节点
当前提交
fb1fffc67d
共有 3 个文件被更改,包括 166 次插入105 次删除
  1. 5 4
      genswf.ml
  2. 90 44
      genswf9.ml
  3. 71 57
      std/flash9/Boot.hx

+ 5 - 4
genswf.ml

@@ -794,8 +794,9 @@ let build_swf8 com codeclip exports =
 	) in
 	clips @ code
 
-let build_swf9 com swc =
-	let code = Genswf9.generate com in
+let build_swf9 com file swc =
+	let boot_name = if swc <> None || Common.defined com "haxe-boot" then "haxe" else "boot_" ^ (String.sub (Digest.to_hex (Digest.string file)) 0 4) in
+	let code = Genswf9.generate com boot_name in
 	let code = (match swc with
 	| Some cat ->
 		cat := build_swc_catalog com (List.map (fun (t,_,_) -> t) code);
@@ -819,7 +820,7 @@ let build_swf9 com swc =
 		) code in
 		[tag (TActionScript3 (None,As3hlparse.flatten inits))]
 	) in
-	let clips = [tag (TF9Classes [{ f9_cid = None; f9_classname = "flash.Boot" }])] in
+	let clips = [tag (TF9Classes [{ f9_cid = None; f9_classname = boot_name }])] in
 	code @ clips
 
 let merge com file priority (h1,tags1) (h2,tags2) =
@@ -941,7 +942,7 @@ let generate com swf_header =
 		) tags;
 	) com.swf_libs;
   (* build haxe swf *)
-	let tags = if isf9 then build_swf9 com swc else build_swf8 com codeclip exports in
+	let tags = if isf9 then build_swf9 com file swc else build_swf8 com codeclip exports in
 	let header, bg = (match swf_header with None -> default_header com | Some h -> convert_header com h) in
 	let bg = tag (TSetBgColor { cr = bg lsr 16; cg = (bg lsr 8) land 0xFF; cb = bg land 0xFF }) in
 	let debug = (if isf9 && Common.defined com "fdb" then [tag (TEnableDebugger2 (0,""))] else []) in

+ 90 - 44
genswf9.ml

@@ -79,6 +79,7 @@ type context = {
 	com : Common.context;
 	debugger : bool;
 	swc : bool;
+	boot : path;
 	mutable last_line : int;
 	mutable last_file : string;
 	(* per-function *)
@@ -1673,18 +1674,60 @@ let generate_construct ctx fdata c =
 	write ctx HRetVoid;
 	f() , List.length fdata.tf_args
 
-let generate_class_statics ctx c =
+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
-		| None -> ()
 		| Some { eexpr = TFunction _ } when (match f.cf_kind with Method (MethNormal | MethInline) -> true | _ -> false) -> ()
-		| Some e ->
+		| 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_inits ctx =
+	let finit = begin_fun ctx [] ctx.com.basic.tvoid [] true null_pos in
+	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;
+	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;
+			generate_class_statics ctx c false;
+			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
@@ -1706,7 +1749,11 @@ let generate_class_init ctx c hc =
 	) 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 then generate_class_statics ctx c
+	(match c.cl_init with
+	| None -> ()
+	| Some e -> gen_expr ctx false e);
+	generate_class_statics ctx c true;
+	if ctx.swc then generate_class_statics ctx c false
 
 let generate_enum_init ctx e hc meta =
 	let path = ([],"Object") in
@@ -1838,7 +1885,7 @@ let generate_class ctx c =
 			| _ -> assert false
 	) in
 	let has_protected = ref None in
-	let fields = Array.of_list (PMap.fold (fun f acc ->
+	let fields = PMap.fold (fun f acc ->
 		match generate_field_kind ctx f c false with
 		| None -> acc
 		| Some k ->
@@ -1875,9 +1922,41 @@ let generate_class ctx c =
 				hlf_kind = k;
 				hlf_metas = extract_meta f.cf_meta;
 			} :: acc
-	) c.cl_fields []) in
+	) c.cl_fields [] in
+	let fields = if c.cl_path <> ctx.boot then fields else
+		{
+			hlf_name = ident "init";
+			hlf_slot = 0;
+			hlf_kind = (HFMethod {
+				hlm_type = generate_inits ctx;
+				hlm_final = false;
+				hlm_override = true;
+				hlm_kind = MK3Normal;
+			});
+			hlf_metas = None;
+		} :: fields
+	in
 	let st_field_count = ref 0 in
 	let st_meth_count = ref 0 in
+	let statics = List.map (fun f ->
+		let k = (match generate_field_kind ctx f c true with None -> assert false | Some k -> k) in
+		let count = (match k with HFMethod _ -> st_meth_count | HFVar _ -> st_field_count | _ -> assert false) in
+		incr count;
+		{
+			hlf_name = ident f.cf_name;
+			hlf_slot = !count;
+			hlf_kind = k;
+			hlf_metas = extract_meta f.cf_meta;
+		}
+	) 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
@@ -1898,19 +1977,9 @@ let generate_class ctx c =
 			HMMultiName (Some name,[HNPublic (Some (String.concat "." pack))])
 		) c.cl_implements);
 		hlc_construct = cid;
-		hlc_fields = fields;
+		hlc_fields = Array.of_list fields;
 		hlc_static_construct = empty_method ctx c.cl_pos;
-		hlc_static_fields = Array.of_list (List.map (fun f ->
-			let k = (match generate_field_kind ctx f c true with None -> assert false | Some k -> k) in
-			let count = (match k with HFMethod _ -> st_meth_count | HFVar _ -> st_field_count | _ -> assert false) in
-			incr count;
-			{
-				hlf_name = ident f.cf_name;
-				hlf_slot = !count;
-				hlf_kind = k;
-				hlf_metas = extract_meta f.cf_meta;
-			}
-		) c.cl_ordered_statics);
+		hlc_static_fields = Array.of_list statics;
 	}
 
 let generate_enum ctx e meta =
@@ -2019,40 +2088,16 @@ let generate_enum ctx e meta =
 		} :: constrs);
 	}
 
-
-let generate_inits ctx =
-	(* define flash.Boot.init method *)
-	write ctx HGetGlobalScope;
-	write ctx (HGetProp (type_path ctx (["flash"],"Boot")));
-	let finit = begin_fun ctx [] ctx.com.basic.tvoid [] true null_pos in
-	List.iter (fun t ->
-		match t with
-		| TClassDecl c ->
-			(match c.cl_init with
-			| None -> ()
-			| Some e -> gen_expr ctx false e);
-		| _ -> ()
-	) ctx.com.types;
-	if not ctx.swc then List.iter (fun t ->
-		match t with
-		| TClassDecl { cl_extern = true } -> ()
-		| TClassDecl c -> generate_class_statics ctx c
-		| _ -> ()
-	) ctx.com.types;
-	write ctx HRetVoid;
-	write ctx (HFunction (finit()));
-	write ctx (HInitProp (ident "init"))
-
 let 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") then
 			None
 		else
 			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;
-			if c.cl_path = (["flash"],"Boot") then generate_inits ctx;
 			write ctx HRetVoid;
 			Some (init(), {
 				hlf_name = type_path ctx c.cl_path;
@@ -2078,9 +2123,10 @@ let generate_type ctx t =
 	| TTypeDecl _ ->
 		None
 
-let generate com =
+let generate com boot_name =
 	let ctx = {
 		com = com;
+		boot = ([],boot_name);
 		debugger = Common.defined com "fdb";
 		swc = Common.defined com "swc";
 		code = DynArray.create();

+ 71 - 57
std/flash9/Boot.hx

@@ -24,73 +24,42 @@
  */
 package flash;
 
+#if !as3
+@:keep private class RealBoot extends Boot {
+	#if swc
+	public static function init(mc) {
+		flash.Lib.current = mc;
+		new RealBoot().init();
+	}
+	#else
+	function new() {
+		super();
+		if( flash.Lib.current == null ) flash.Lib.current = this;
+		start();
+	}
+	#end
+}
+#end
+
 @:keep class Boot extends flash.display.MovieClip, implements Dynamic {
 
-	static var init : Void -> Void;
 	static var tf : flash.text.TextField;
 	static var lines : Array<String>;
 	static var lastError : flash.errors.Error;
 
 	public static var skip_constructor = false;
 
-	public function new(?mc:flash.display.MovieClip) {
-		super();
-		untyped {
-			var aproto = Array.prototype;
-			aproto.copy = function() {
-				return this.slice();
-			};
-			aproto.insert = function(i,x) {
-				this.splice(i,0,x);
-			};
-			aproto.remove = function(obj) {
-				var idx = this.indexOf(obj);
-				if( idx == -1 ) return false;
-				this.splice(idx,1);
-				return true;
-			}
-			aproto.iterator = function() {
-				var cur = 0;
-				var arr : Array<Dynamic> = this;
-				return {
-					hasNext : function() {
-						return cur < arr.length;
-					},
-					next : function() {
-						return arr[cur++];
-					}
-				}
-			};
-			aproto.setPropertyIsEnumerable("copy", false);
-			aproto.setPropertyIsEnumerable("insert", false);
-			aproto.setPropertyIsEnumerable("remove", false);
-			aproto.setPropertyIsEnumerable("iterator", false);
-			var cca = String.prototype.charCodeAt;
-			String.prototype.charCodeAt = function(i) {
-				var x = cca.call(this,i);
-				if( __global__["isNaN"](x) )
-					return null;
-				return x;
-			};
-		}
-		lines = new Array();
-		var c = if( mc == null ) this else mc;
-		flash.Lib.current = c;
-		if( init != null )
-			start();
-	}
-
 	function start() {
-		var c = flash.Lib.current;
-		try {
-			untyped if( c.stage != null && c.stage.align == "" )
-				c.stage.align = "TOP_LEFT";
-		} catch( e : Dynamic ) {
-			// security error when loading from different domain
-		}
-		#if (dontWaitStage || swc)
+		#if dontWaitStage
 			init();
 		#else
+			var c = flash.Lib.current;
+			try {
+				untyped if( c == this && c.stage != null && c.stage.align == "" )
+					c.stage.align = "TOP_LEFT";
+			} catch( e : Dynamic ) {
+				// security error when loading from different domain
+			}
 			if( c.stage == null )
 				c.addEventListener(flash.events.Event.ADDED_TO_STAGE, doInitDelay);
 			else if( c.stage.stageWidth == 0 )
@@ -105,6 +74,10 @@ package flash;
 		start();
 	}
 
+	function init() {
+		throw "assert";
+	}
+
 	public static function enum_to_string( e : { tag : String, params : Array<Dynamic> } ) {
 		if( e.params == null )
 			return e.tag;
@@ -129,7 +102,7 @@ package flash;
 			return;
 		tf.parent.removeChild(tf);
 		tf = null;
-		lines = new Array();
+		lines = null;
 	}
 
 	public static function __set_trace_color(rgb) {
@@ -158,6 +131,7 @@ package flash;
 	public static function __trace( v : Dynamic, pos : haxe.PosInfos ) {
 		var tf = getTrace();
 		var pstr = if( pos == null ) "(null)" else pos.fileName+":"+pos.lineNumber;
+		if( lines == null ) lines = [];
 		lines = lines.concat((pstr +": "+__string_rec(v,"")).split("\n"));
 		tf.text = lines.join("\n");
 		var stage = flash.Lib.current.stage;
@@ -215,4 +189,44 @@ package flash;
 		return s;
 	}
 
+
+	static function __init__() untyped {
+		var aproto = Array.prototype;
+		aproto.copy = function() {
+			return this.slice();
+		};
+		aproto.insert = function(i,x) {
+			this.splice(i,0,x);
+		};
+		aproto.remove = function(obj) {
+			var idx = this.indexOf(obj);
+			if( idx == -1 ) return false;
+			this.splice(idx,1);
+			return true;
+		}
+		aproto.iterator = function() {
+			var cur = 0;
+			var arr : Array<Dynamic> = this;
+			return {
+				hasNext : function() {
+					return cur < arr.length;
+				},
+				next : function() {
+					return arr[cur++];
+				}
+			}
+		};
+		aproto.setPropertyIsEnumerable("copy", false);
+		aproto.setPropertyIsEnumerable("insert", false);
+		aproto.setPropertyIsEnumerable("remove", false);
+		aproto.setPropertyIsEnumerable("iterator", false);
+		var cca = String.prototype.charCodeAt;
+		String.prototype.charCodeAt = function(i) {
+			var x = cca.call(this,i);
+			if( __global__["isNaN"](x) )
+				return null;
+			return x;
+		};
+	}
+
 }