Переглянути джерело

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 роки тому
батько
коміт
60c4391d9a
10 змінених файлів з 59 додано та 65 видалено
  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 = [];