فهرست منبع

Disable fusion for impure externs (#10432)

* Disable fusion for impure externs

* Actual fix

* Add test

* Make test run

* Use PurityState
RblSb 3 سال پیش
والد
کامیت
c50774b32a
2فایلهای تغییر یافته به همراه67 افزوده شده و 2 حذف شده
  1. 12 2
      src/optimization/analyzerTexpr.ml
  2. 55 0
      tests/optimization/src/issues/Issue9943.hx

+ 12 - 2
src/optimization/analyzerTexpr.ml

@@ -590,14 +590,24 @@ module Fusion = struct
 			let can_be_used_as_value = can_be_used_as_value com e in
 			let is_compiler_generated = match v.v_kind with VUser _ | VInlined -> false | _ -> true in
 			let has_type_params = match v.v_extra with Some ve when ve.v_params <> [] -> true | _ -> false in
+			let rec is_impure_extern e = match e.eexpr with
+				| TField(ef,(FStatic(cl,cf) | FInstance(cl,_,cf))) when has_class_flag cl CExtern ->
+					not (
+						Meta.has Meta.CoreApi cl.cl_meta ||
+						PurityState.is_pure cl cf
+					)
+				| _ -> check_expr is_impure_extern e
+			in
 			let b = num_uses <= 1 &&
 			        num_writes = 0 &&
 			        can_be_used_as_value &&
 					not (
 						ExtType.has_variable_semantics v.v_type &&
 						(match e.eexpr with TLocal { v_kind = VUser _ } -> false | _ -> true)
-					) &&
-			        (is_compiler_generated || config.optimize && config.fusion && config.user_var_fusion && not has_type_params)
+					) && (
+						is_compiler_generated || config.optimize &&
+						config.fusion && config.user_var_fusion && not has_type_params && not (is_impure_extern e)
+					)
 			in
 			if config.fusion_debug then begin
 				print_endline (Printf.sprintf "\nFUSION: %s\n\tvar %s<%i> = %s" (if b then "true" else "false") v.v_name v.v_id (s_expr_pretty e));

+ 55 - 0
tests/optimization/src/issues/Issue9943.hx

@@ -0,0 +1,55 @@
+package issues;
+
+private extern class Element {
+	static function get():Element;
+	var offset(default,null) : Int;
+	var style(default,null) : CSSStyleDeclaration;
+}
+@:pure
+private extern class PureElement {
+	static function get():PureElement;
+	var offset(default,null) : Int;
+	var style(default,null) : CSSStyleDeclaration;
+}
+private extern class CSSStyleDeclaration {
+	var verticalAlign : Int;
+}
+
+class Issue9943 {
+	static final foo = Std.random(0);
+
+	@:js('
+		var el = issues._Issue9943.Element.get();
+		var a = el.offset + issues_Issue9943.foo;
+		el.style.verticalAlign = 1;
+		var b = el.offset + issues_Issue9943.foo;
+		el.style.verticalAlign = 2;
+		var c = el.offset + issues_Issue9943.foo;
+		issues_Issue9943.values(a,b,c);
+	')
+	static function test() {
+		final el = Element.get();
+		final a = (el.offset + foo);
+		el.style.verticalAlign = 1;
+		final b = (el.offset + foo);
+		el.style.verticalAlign = 2;
+		final c = (el.offset + foo);
+		values(a, b, c);
+	}
+	@:js('
+		var el = issues._Issue9943.PureElement.get();
+		el.style.verticalAlign = 1;
+		el.style.verticalAlign = 2;
+		issues_Issue9943.values(el.offset + issues_Issue9943.foo,el.offset + issues_Issue9943.foo,el.offset + issues_Issue9943.foo);
+	')
+	static function test2() {
+		final el = PureElement.get();
+		final a = (el.offset + foo);
+		el.style.verticalAlign = 1;
+		final b = (el.offset + foo);
+		el.style.verticalAlign = 2;
+		final c = (el.offset + foo);
+		values(a, b, c);
+	}
+	static function values(a, b, c) trace(a, b, c);
+}