Browse Source

moved features from typer to common (allow setting features during compilation for later retrieval)
added @:defineFeature that will set a feature when typed (even if inlined)
make sure that has_enum is only set if an enum is actually compiled (after DCE)
remove __class__ in JS when no super, no members, no constructor

Nicolas Cannasse 13 năm trước cách đây
mục cha
commit
60c4391d9a
10 tập tin đã thay đổi với 59 bổ sung65 xóa
  1. 27 0
      common.ml
  2. 7 31
      genjs.ml
  3. 1 0
      std/flash8/_std/Std.hx
  4. 3 3
      std/js/Boot.hx
  5. 2 0
      std/js/_std/Reflect.hx
  6. 1 0
      std/neko/Boot.hx
  7. 1 0
      std/neko/_std/Std.hx
  8. 0 13
      typecore.ml
  9. 1 1
      typeload.ml
  10. 16 17
      typer.ml

+ 27 - 0
common.ml

@@ -78,6 +78,7 @@ type context = {
 	(* output *)
 	mutable file : string;
 	mutable flash_version : float;
+	mutable features : (string,bool) Hashtbl.t;
 	mutable modules : Type.module_def list;
 	mutable main : Type.texpr option;
 	mutable types : Type.module_type list;
@@ -113,6 +114,7 @@ let create v args =
 		display = !display_default;
 		verbose = false;
 		foptimize = true;
+		features = Hashtbl.create 0;
 		dead_code_elimination = false;
 		platform = Cross;
 		print = print_string;
@@ -225,6 +227,31 @@ let init_platform com pf =
 	| _ -> com.package_rules <- PMap.add "sys" Forbidden com.package_rules);
 	define com name
 
+let add_feature com f =
+	Hashtbl.replace com.features f true
+
+let rec has_feature com f =
+	try
+		Hashtbl.find com.features f
+	with Not_found ->
+		if com.types = [] then defined com "all_features" else
+		match List.rev (ExtString.String.nsplit f ".") with
+		| [] -> assert false
+		| [cl] -> has_feature com (cl ^ ".*") 
+		| meth :: cl :: pack ->
+			let r = (try
+				let path = List.rev pack, cl in
+				(match List.find (fun t -> t_path t = path) com.types with
+				| t when meth = "*" -> (not com.dead_code_elimination) || has_meta ":?used" (t_infos t).mt_meta
+				| TClassDecl c -> PMap.exists meth c.cl_statics || PMap.exists meth c.cl_fields
+				| _ -> false)
+			with Not_found ->
+				false
+			) in
+			let r = r || defined com "all_features" in
+			Hashtbl.add com.features f r;
+			r
+
 let error msg p = raise (Abort (msg,p))
 
 let platform ctx p = ctx.platform = p

+ 7 - 31
genjs.ml

@@ -40,9 +40,7 @@ type ctx = {
 	buf : Buffer.t;
 	packages : (string list,unit) Hashtbl.t;
 	smap : sourcemap;
-	js_modern : bool;
-	all_features : bool;
-	mutable features : (string, bool) PMap.t;
+	js_modern : bool;	
 	mutable boot_init : texpr option;
 	mutable current : tclass;
 	mutable statics : (tclass * string * texpr) list;
@@ -87,28 +85,8 @@ let field s = if Hashtbl.mem kwds s then "[\"" ^ s ^ "\"]" else "." ^ s
 let ident s = if Hashtbl.mem kwds s then "$" ^ s else s
 let anon_field s = if Hashtbl.mem kwds s || not (valid_js_ident s) then "'" ^ s ^ "'" else s
 
-let has_feature ctx f =
-	if ctx.all_features then true else
-	try
-		PMap.find f ctx.features
-	with Not_found ->
-		match List.rev (ExtString.String.nsplit f ".") with
-		| [] | _ :: [] -> assert false
-		| meth :: cl :: pack ->
-			let r = (try
-				let path = List.rev pack, cl in
-				(match List.find (fun t -> t_path t = path) ctx.com.types with
-				| t when meth = "*" -> (not ctx.com.dead_code_elimination) || has_meta ":?used" (t_infos t).mt_meta
-				| TClassDecl c -> PMap.exists meth c.cl_statics || PMap.exists meth c.cl_fields
-				| _ -> false)
-			with Not_found ->
-				false
-			) in
-			ctx.features <- PMap.add f r ctx.features;
-			r
-
-let add_feature ctx f =
-	ctx.features <- PMap.add f true ctx.features
+let has_feature ctx = Common.has_feature ctx.com
+let add_feature ctx = Common.add_feature ctx.com
 
 let handle_newlines ctx str =
 	if ctx.com.debug then
@@ -394,7 +372,7 @@ let rec gen_call ctx e el in_value =
 		) (Hashtbl.fold (fun name data acc -> (name,data) :: acc) ctx.com.resources []);
 		spr ctx "]";
 	| TLocal { v_name = "`trace" }, [e;infos] ->
-		if has_feature (if ctx.all_features then { ctx with all_features = false } else ctx) "haxe.Log.trace" then begin
+		if has_feature ctx "haxe.Log.trace" then begin
 			let t = (try List.find (fun t -> t_path t = (["haxe"],"Log")) ctx.com.types with _ -> assert false) in
 			spr ctx (ctx.type_accessor t);
 			spr ctx ".trace(";
@@ -1000,7 +978,7 @@ let generate_class ctx c =
 
 	List.iter (gen_class_static_field ctx c) c.cl_ordered_statics;
 
-	let has_class = has_feature ctx "js.Boot.getClass" in
+	let has_class = has_feature ctx "js.Boot.getClass" && (c.cl_super <> None || c.cl_ordered_fields <> [] || c.cl_constructor <> None) in
 	let has_prototype = c.cl_super <> None || has_class || List.exists (can_gen_class_field ctx) c.cl_ordered_fields in
 	if has_prototype then begin
 		(match c.cl_super with
@@ -1098,7 +1076,6 @@ let alloc_ctx com =
 		com = com;
 		buf = Buffer.create 16000;
 		packages = Hashtbl.create 0;
-		features = PMap.empty;
 		smap = {
 			source_last_line = 0;
 			source_last_col = 0;
@@ -1110,7 +1087,6 @@ let alloc_ctx com =
 			sources_hash = Hashtbl.create 0;
 			mappings = Buffer.create 16;
 		};
-		all_features = Common.defined com "all_features";
 		js_modern = Common.defined com "js_modern";
 		statics = [];
 		inits = [];
@@ -1142,8 +1118,8 @@ let generate com =
 	| None ->
 	let ctx = alloc_ctx com in
 
-	if has_feature ctx "Class.*" || has_feature ctx "Type.getClassName" then add_feature ctx "js.Boot.isClass";
-	if has_feature ctx "Enum.*" || has_feature ctx "Type.getEnumName" then add_feature ctx "js.Boot.isEnum";
+	if has_feature ctx "Class" || has_feature ctx "Type.getClassName" then add_feature ctx "js.Boot.isClass";
+	if has_feature ctx "Enum" || has_feature ctx "Type.getEnumName" then add_feature ctx "js.Boot.isEnum";
 
 	if ctx.js_modern then begin
 		(* Additional ES5 strict mode keywords. *)

+ 1 - 0
std/flash8/_std/Std.hx

@@ -25,6 +25,7 @@
 
 @:core_api class Std {
 
+	@:feature("typed_cast")
 	public static function is( v : Dynamic, t : Dynamic ) : Bool {
 		return untyped flash.Boot.__instanceof(v,t);
 	}

+ 3 - 3
std/js/Boot.hx

@@ -59,15 +59,15 @@ class Boot {
 		}
 	}
 
-	static inline function isClass(o:Dynamic) : Bool {
+	@:defineFeature static inline function isClass(o:Dynamic) : Bool {
 		return o.__name__;
 	}
 
-	static inline function isEnum(e:Dynamic) : Bool {
+	@:defineFeature static inline function isEnum(e:Dynamic) : Bool {
 		return e.__ename__;
 	}
 
-	static inline function getClass(o:Dynamic) : Dynamic {
+	@:defineFeature static inline function getClass(o:Dynamic) : Dynamic {
 		return o.__class__;
 	}
 

+ 2 - 0
std/js/_std/Reflect.hx

@@ -42,11 +42,13 @@
 		o[field] = value;
 	}
 
+	@:defineFeature
 	public static inline function getProperty( o : Dynamic, field : String ) : Dynamic untyped {
 		var tmp;
 		return if( o == null ) null else if( o.__properties__ && (tmp=o.__properties__["get_"+field]) ) o[tmp]() else o[field];
 	}
 
+	@:defineFeature
 	public static inline function setProperty( o : Dynamic, field : String, value : Dynamic ) : Void untyped {
 		var tmp;
 		if( o.__properties__ && (tmp=o.__properties__["set_"+field]) ) o[tmp](value) else o[field] = value;

+ 1 - 0
std/neko/Boot.hx

@@ -67,6 +67,7 @@ class Boot {
 		return __interfLoop(cc.__super__,cl);
 	}
 
+	@:feature("typed_catch")
 	private static function __instanceof(o,cl) {
 		untyped {
 			if( cl == Dynamic )

+ 1 - 0
std/neko/_std/Std.hx

@@ -25,6 +25,7 @@
 
 @:core_api class Std {
 
+	@:feature("typed_cast")
 	public static function is( v : Dynamic, t : Dynamic ) : Bool {
 		return untyped neko.Boot.__instanceof(v,t);
 	}

+ 0 - 13
typecore.ml

@@ -36,15 +36,9 @@ type macro_mode =
 	| MBuild
 	| MMacroType
 
-type feature =
-	| FtTypedCast
-	| FtTypedCatch
-	| FtHasEnum
-
 type typer_globals = {
 	types_module : (path, path) Hashtbl.t;
 	modules : (path , module_def) Hashtbl.t;
-	features : (string, feature) Hashtbl.t;
 	mutable delayed : (unit -> unit) list;
 	doinline : bool;
 	mutable core_api : typer option;
@@ -244,10 +238,3 @@ let create_fake_module ctx file =
 	Hashtbl.replace ctx.g.modules mdep.m_path mdep;
 	mdep
 
-let feature_name = function
-	| FtTypedCast -> "typed_cast"
-	| FtTypedCatch -> "typed_catch"
-	| FtHasEnum -> "has_enum"
-
-let activate_feature ctx ft = Hashtbl.replace ctx.g.features (feature_name ft) ft
-let has_feature ctx s = Hashtbl.mem ctx.g.features s

+ 1 - 1
typeload.ml

@@ -1083,6 +1083,7 @@ let init_class ctx c p herits fields =
 						| TBlock [] | TBlock [{ eexpr = TConst _ }] | TConst _ | TObjectDecl [] -> ()
 						| _ -> c.cl_init <- Some e);
 					if not (constr || inline) then mark_used cf;
+					if has_meta ":defineFeature" cf.cf_meta then add_feature ctx.com (s_type_path c.cl_path ^ "." ^ cf.cf_name);
 					cf.cf_expr <- Some (mk (TFunction f) t p);
 					cf.cf_type <- t;
 				end;
@@ -1456,7 +1457,6 @@ let type_module ctx m file tdecls loadp =
 			) (!constructs);
 			e.e_names <- List.rev !names;
 			e.e_extern <- e.e_extern || e.e_names = [];
-			if not e.e_extern then activate_feature ctx FtHasEnum;
 		| ETypedef d ->
 			let t = get_tdef d.d_name in
 			let ctx = { ctx with type_params = t.t_types } in

+ 16 - 17
typer.ml

@@ -1812,7 +1812,7 @@ and type_expr ctx ?(need_val=true) (e,p) =
 					List.iter (fun pt ->
 						if pt != t_dynamic then error "Catch class parameter must be Dynamic" p;
 					) params;
-					activate_feature ctx FtTypedCatch;
+					add_feature ctx.com "typed_catch";
 					(match path with
 					| x :: _ , _ -> x
 					| [] , name -> name)
@@ -1922,15 +1922,7 @@ and type_expr ctx ?(need_val=true) (e,p) =
 		let e = type_expr ctx e in
 		mk (TCast (e,None)) (mk_mono()) p
 	| ECast (e, Some t) ->
-		(* force compilation of class "Std" since we might need it *)
-		activate_feature ctx FtTypedCast;
-		(match ctx.com.platform with
-		| Js | Flash8 | Neko | Flash | Java | Cs ->
-			let std = Typeload.load_type_def ctx p { tpackage = []; tparams = []; tname = "Std"; tsub = None } in
-			(* ensure typing / mark for DCE *)
-			ignore(follow (try PMap.find "is" (match std with TClassDecl c -> c.cl_statics | _ -> assert false) with Not_found -> assert false).cf_type)
-		| Cpp | Php | Cross ->
-			());
+		add_feature ctx.com "typed_cast";
 		let t = Typeload.load_complex_type ctx (pos e) t in
 		let texpr = (match follow t with
 		| TInst (_,params) | TEnum (_,params) ->
@@ -2054,7 +2046,7 @@ and type_call ctx e el t p =
 		else
 		let params = (match el with [] -> [] | _ -> ["customParams",(EArrayDecl el , p)]) in
 		let infos = mk_infos ctx p params in
-		if platform ctx.com Js && el = [] then
+		if platform ctx.com Js && el = [] && not (defined ctx.com "all_features") then
 			let e = type_expr ctx e in
 			let infos = type_expr ctx infos in
 			mk (TCall (mk (TLocal (alloc_var "`trace" t_dynamic)) t_dynamic p,[e;infos])) ctx.t.tvoid p
@@ -2191,7 +2183,7 @@ let dce_check_metadata ctx meta =
 		| ":keep",_ ->
 			true
  		| ":feature",el ->
-			List.exists (fun e -> match e with (EConst(String s),_) when has_feature ctx s -> true | _ -> false) el
+			List.exists (fun e -> match e with (EConst(String s),_) -> has_feature ctx.com s | _ -> false) el
 		| _ -> false
 	) meta
 
@@ -2215,6 +2207,13 @@ let dce_check_class ctx c =
 	make sure that all things we are supposed to keep are correctly typed
 *)
 let dce_finalize ctx =
+	let feature_changed = ref false in
+	let add_feature f =
+		if not (has_feature ctx.com f) then begin
+			add_feature ctx.com f;
+			feature_changed := true;
+		end
+	in
 	let check_class c =
 		let keep = dce_check_class ctx c in
 		let check stat f = if keep stat f then ignore(follow f.cf_type) in
@@ -2227,10 +2226,12 @@ let dce_finalize ctx =
 			match t with
 			| TClassDecl c -> check_class c
 			| TEnumDecl e ->
-				if not (dce_check_metadata ctx e.e_meta) then e.e_extern <- true
+				if not (dce_check_metadata ctx e.e_meta) then e.e_extern <- true;
+				if not e.e_extern then add_feature "has_enum";
 			| _ -> ()
 		) m.m_types
-	) ctx.g.modules
+	) ctx.g.modules;
+	not !feature_changed
 
 (*
 	remove unused fields and mark unused classes as extern
@@ -2297,8 +2298,7 @@ let rec finalize ctx =
 	match delays with
 	| [] when ctx.com.dead_code_elimination ->
 		ignore(get_main ctx);
-		dce_finalize ctx;
-		if ctx.g.delayed = [] then dce_optimize ctx else finalize ctx
+		if dce_finalize ctx && ctx.g.delayed = [] then dce_optimize ctx else finalize ctx
 	| [] ->
 		(* at last done *)
 		()
@@ -2900,7 +2900,6 @@ let rec create com =
 			modules = Hashtbl.create 0;
 			types_module = Hashtbl.create 0;
 			type_patches = Hashtbl.create 0;
-			features = Hashtbl.create 0;
 			delayed = [];
 			doinline = not (Common.defined com "no_inline" || com.display);
 			hook_generate = [];