Просмотр исходного кода

[js] improve downcasting generation

Dan Korostelev 6 лет назад
Родитель
Сommit
ce90b80e72
5 измененных файлов с 52 добавлено и 36 удалено
  1. 6 6
      src/generators/genjs.ml
  2. 31 18
      src/optimization/inline.ml
  3. 13 10
      std/js/Boot.hx
  4. 1 1
      std/js/_std/Std.hx
  5. 1 1
      std/js/_std/Type.hx

+ 6 - 6
src/generators/genjs.ml

@@ -49,7 +49,7 @@ type ctx = {
 	js_modern : bool;
 	js_flatten : bool;
 	has_resolveClass : bool;
-	has_instanceof : bool;
+	has_interface_check : bool;
 	es_version : int;
 	mutable current : tclass;
 	mutable statics : (tclass * string * texpr) list;
@@ -1113,7 +1113,7 @@ let generate_class_es3 ctx c =
 	generate_class___name__ ctx c;
 	generate_class___isInterface__ ctx c;
 
-	if ctx.has_instanceof then
+	if ctx.has_interface_check then
 		(match c.cl_implements with
 		| [] -> ()
 		| l ->
@@ -1268,7 +1268,7 @@ let generate_class_es6 ctx c =
 	generate_class___name__ ctx c;
 	generate_class___isInterface__ ctx c;
 
-	if ctx.has_instanceof then
+	if ctx.has_interface_check then
 		(match c.cl_implements with
 		| [] -> ()
 		| l ->
@@ -1294,7 +1294,7 @@ let generate_class_es6 ctx c =
 
 	(match c.cl_super with
 	| Some (csup,_) ->
-		if ctx.has_instanceof || has_feature ctx "Type.getSuperClass" then begin
+		if ctx.has_interface_check || has_feature ctx "Type.getSuperClass" then begin
 			let psup = ctx.type_accessor (TClassDecl csup) in
 			print ctx "%s.__super__ = %s" p psup;
 			newline ctx
@@ -1471,7 +1471,7 @@ let generate_require ctx path meta =
 
 let need_to_generate_interface ctx cl_iface =
 	ctx.has_resolveClass (* generate so we can resolve it for whatever reason *)
-	|| ctx.has_instanceof (* generate because we need __interfaces__ for run-time type checks *)
+	|| ctx.has_interface_check (* generate because we need __interfaces__ for run-time type checks *)
 	|| is_directly_used ctx.com cl_iface.cl_meta (* generate because it's just directly accessed in code *)
 
 let generate_type ctx = function
@@ -1529,7 +1529,7 @@ let alloc_ctx com es_version =
 		js_modern = not (Common.defined com Define.JsClassic);
 		js_flatten = not (Common.defined com Define.JsUnflatten);
 		has_resolveClass = Common.has_feature com "Type.resolveClass";
-		has_instanceof = Common.has_feature com "js.Boot.__instanceof";
+		has_interface_check = Common.has_feature com "js.Boot.__interfLoop";
 		es_version = es_version;
 		statics = [];
 		inits = [];

+ 31 - 18
src/optimization/inline.ml

@@ -106,20 +106,25 @@ let api_inline2 com c field params p =
 	| _ ->
 		None
 
-let api_inline ctx c field params p = match c.cl_path, field, params with
-	| ([],"Std"),"is",[o;t] | (["js"],"Boot"),"__instanceof",[o;t] when ctx.com.platform = Js ->
-		let tstring = ctx.com.basic.tstring in
-		let tbool = ctx.com.basic.tbool in
-		let tint = ctx.com.basic.tint in
+let api_inline ctx c field params p =
+	let mk_typeexpr path =
+		let m = (try Hashtbl.find ctx.g.modules path with Not_found -> assert false) in
+		add_dependency ctx.m.curmod m;
+		ExtList.List.find_map (function
+			| TClassDecl cl when cl.cl_path = path -> Some (make_static_this cl p)
+			| _ -> None
+		) m.m_types
+	in
 
-		let esyntax () =
-			let m = (try Hashtbl.find ctx.g.modules (["js"],"Syntax") with Not_found -> assert false) in
-			add_dependency ctx.m.curmod m;
-			ExtList.List.find_map (function
-				| TClassDecl ({ cl_path = ["js"],"Syntax" } as cl) -> Some (make_static_this cl p)
-				| _ -> None
-			) m.m_types
-		in
+	let eJsSyntax () = mk_typeexpr (["js"],"Syntax") in
+	let eJsBoot () = mk_typeexpr (["js"],"Boot") in
+
+	let tstring = ctx.com.basic.tstring in
+	let tbool = ctx.com.basic.tbool in
+	let tint = ctx.com.basic.tint in
+
+	match c.cl_path, field, params with
+	| ([],"Std"),"is",[o;t] | (["js"],"Boot"),"__instanceof",[o;t] when ctx.com.platform = Js ->
 		let is_trivial e =
 			match e.eexpr with
 			| TConst _ | TLocal _ -> true
@@ -127,7 +132,7 @@ let api_inline ctx c field params p = match c.cl_path, field, params with
 		in
 
 		let typeof t =
-			let tof = Texpr.Builder.fcall (esyntax()) "typeof" [o] tstring p in
+			let tof = Texpr.Builder.fcall (eJsSyntax()) "typeof" [o] tstring p in
 			mk (TBinop (Ast.OpEq, tof, (mk (TConst (TString t)) tstring p))) tbool p
 		in
 
@@ -139,19 +144,27 @@ let api_inline ctx c field params p = match c.cl_path, field, params with
 		| TTypeExpr (TAbstractDecl ({ a_path = [],"Int" })) when is_trivial o ->
 			(* generate typeof(o) == "number" && (o|0) === o check *)
 			let lhs = mk (TBinop (Ast.OpOr, o, mk (TConst (TInt Int32.zero)) tint p)) tint p in
-			let jscheck = Texpr.Builder.fcall (esyntax()) "strictEq" [lhs;o] tbool p in
+			let jscheck = Texpr.Builder.fcall (eJsSyntax()) "strictEq" [lhs;o] tbool p in
 			Some(mk (TBinop (Ast.OpBoolAnd, typeof "number", jscheck)) tbool p)
 		| TTypeExpr (TClassDecl ({ cl_path = [],"Array" })) ->
 			(* generate (o instanceof Array) && o.__enum__ == null check *)
-			let iof = Texpr.Builder.fcall (esyntax()) "instanceof" [o;t] tbool p in
+			let iof = Texpr.Builder.fcall (eJsSyntax()) "instanceof" [o;t] tbool p in
 			let enum = mk (TField (o, FDynamic "__enum__")) (mk_mono()) p in
 			let null = mk (TConst TNull) (mk_mono()) p in
 			let not_enum = mk (TBinop (Ast.OpEq, enum, null)) tbool p in
 			Some (mk (TBinop (Ast.OpBoolAnd, iof, not_enum)) tbool p)
-		| TTypeExpr (TClassDecl cls) when not cls.cl_interface ->
-			Some (Texpr.Builder.fcall (esyntax()) "instanceof" [o;t] tbool p)
+		| TTypeExpr (TClassDecl cls) ->
+			if cls.cl_interface then
+				Some (Texpr.Builder.fcall (eJsBoot()) "__implements" [o;t] tbool p)
+			else
+				Some (Texpr.Builder.fcall (eJsSyntax()) "instanceof" [o;t] tbool p)
 		| _ ->
 			None)
+	| (["js"],"Boot"),"__downcastCheck",[o; {eexpr = TTypeExpr (TClassDecl cls) } as t] when ctx.com.platform = Js ->
+		if cls.cl_interface then
+			Some (Texpr.Builder.fcall (make_static_this c p) "__implements" [o;t] tbool p)
+		else
+			Some (Texpr.Builder.fcall (eJsSyntax()) "instanceof" [o;t] tbool p)
 	| (["cs" | "java"],"Lib"),("nativeArray"),[{ eexpr = TArrayDecl args } as edecl; _]
 	| (["haxe";"ds";"_Vector"],"Vector_Impl_"),("fromArrayCopy"),[{ eexpr = TArrayDecl args } as edecl] -> (try
 			let platf = match ctx.com.platform with

+ 13 - 10
std/js/Boot.hx

@@ -57,10 +57,12 @@ class Boot {
 		return untyped __define_feature__("js.Boot.isEnum", e.__ename__);
 	}
 
-	static function getClass(o:Dynamic) : Dynamic {
-		if (Std.is(o, Array))
+	static function getClass(o:Null<Dynamic>) : Null<Dynamic> {
+		if (o == null) {
+			return null;
+		} else if (Std.is(o, Array)) {
 			return Array;
-		else {
+		} else {
 			var cl = untyped __define_feature__("js.Boot.getClass", o.__class__);
 			if (cl != null)
 				return cl;
@@ -194,12 +196,9 @@ class Boot {
 			if( o != null ) {
 				// Check if o is an instance of a Haxe class or a native JS object
 				if( js.Syntax.typeof(cl) == "function" ) {
-					if( js.Syntax.instanceof(o, cl) )
-						return true;
-					if( __interfLoop(getClass(o),cl) )
+					if (__downcastCheck(o, cl))
 						return true;
-				}
-				else if ( js.Syntax.typeof(cl) == "object" && __isNativeObj(cl) ) {
+				} else if ( js.Syntax.typeof(cl) == "object" && __isNativeObj(cl) ) {
 					if( js.Syntax.instanceof(o, cl) )
 						return true;
 				}
@@ -217,8 +216,12 @@ class Boot {
 		}
 	}
 
-	static inline function __implements(o : Dynamic, t : Class<Dynamic>) : Bool {
-		return o != null && isInterface(t) && __interfLoop(getClass(o), t);
+	static function __downcastCheck(o : Dynamic, cl : Class<Dynamic>) : Bool {
+		return js.Syntax.instanceof(o, cl) || (isInterface(cl) && inline __implements(o, cl));
+	}
+
+	static function __implements(o : Dynamic, iface : Class<Dynamic>) : Bool {
+		return __interfLoop(getClass(o), iface);
 	}
 
 	@:ifFeature("typed_cast") private static function __cast(o : Dynamic, t : Dynamic) {

+ 1 - 1
std/js/_std/Std.hx

@@ -29,7 +29,7 @@ import js.Boot;
 	}
 
 	public static inline function downcast<T:{},S:T>( value : T, c : Class<S> ) : S @:privateAccess {
-		return js.Syntax.instanceof(value, c) || Boot.__implements(value, c) ? cast value : null;
+		return if (js.Boot.__downcastCheck(value, c)) cast value else null;
 	}
 
 	@:deprecated('Std.instance() is deprecated. Use Std.downcast() instead.')

+ 1 - 1
std/js/_std/Type.hx

@@ -33,7 +33,7 @@ enum ValueType {
 
 @:coreApi class Type {
 	public static inline function getClass<T>(o:T):Class<T> {
-		return if (o == null) null else @:privateAccess js.Boot.getClass(o);
+		return @:privateAccess js.Boot.getClass(o);
 	}
 
 	public static function getEnum(o:EnumValue):Enum<Dynamic>