Browse Source

make inliner thread-safe (#12115)

Simon Krajewski 4 months ago
parent
commit
489e722dbb

+ 4 - 1
src/context/safeCom.ml

@@ -146,4 +146,7 @@ let run_expression_filters_safe scom detail_times filters t =
 			TClass.set_cl_init c (run scom (Some identifier) e))
 	| TEnumDecl _ -> ()
 	| TTypeDecl _ -> ()
-	| TAbstractDecl _ -> ()
+	| TAbstractDecl _ -> ()
+
+let needs_inline scom c cf =
+	cf.cf_kind = Method MethInline && (scom.doinline || Typecore.is_forced_inline c cf)

+ 7 - 3
src/core/tFunctions.ml

@@ -307,15 +307,19 @@ let null_abstract = {
 let create_dependency mdep origin =
 	{md_sign = mdep.m_extra.m_sign; md_path = mdep.m_path; md_kind = mdep.m_extra.m_kind; md_origin = origin}
 
+let add_dependency_mutex = Mutex.create ()
+
 let add_dependency ?(skip_postprocess=false) m mdep = function
 	(* These module dependency origins should not add as a dependency *)
 	| MDepFromMacroInclude -> ()
 
 	| origin ->
 		if m != null_module && mdep != null_module && (m.m_path != mdep.m_path || m.m_extra.m_sign != mdep.m_extra.m_sign) then begin
-			m.m_extra.m_deps <- PMap.add mdep.m_id (create_dependency mdep origin) m.m_extra.m_deps;
-			(* In case the module is cached, we'll have to run post-processing on it again (issue #10635) *)
-			if not skip_postprocess then m.m_extra.m_processed <- 0
+			Mutex.protect add_dependency_mutex (fun () ->
+				m.m_extra.m_deps <- PMap.add mdep.m_id (create_dependency mdep origin) m.m_extra.m_deps;
+				(* In case the module is cached, we'll have to run post-processing on it again (issue #10635) *)
+				if not skip_postprocess then m.m_extra.m_processed <- 0
+			)
 		end
 
 let arg_name (a,_) = a.v_name

+ 2 - 2
src/filters/filters.ml

@@ -440,6 +440,8 @@ let run tctx ectx main before_destruction =
 		"check_local_vars_init",CheckVarInit.check_local_vars_init;
 		"check_abstract_as_value",SafeFilters.check_abstract_as_value;
 		"Tre",if defined com Define.AnalyzerOptimize then Tre.run else (fun _ e -> e);
+		"reduce_expression",Optimizer.reduce_expression;
+		"inline_constructors",InlineConstructors.inline_constructors;
 	] in
 	Parallel.run_in_new_pool com.timer_ctx (fun pool ->
 		SafeCom.run_with_scom com scom pool (fun () ->
@@ -448,8 +450,6 @@ let run tctx ectx main before_destruction =
 	);
 
 	let filters = [
-		"reduce_expression",Optimizer.reduce_expression;
-		"inline_constructors",InlineConstructors.inline_constructors;
 		"Exceptions_filter",(fun _ -> Exceptions.filter ectx);
 	] in
 	List.iter (run_expression_filters tctx detail_times filters) new_types;

+ 77 - 44
src/optimization/inline.ml

@@ -2,7 +2,6 @@ open Globals
 open Ast
 open Type
 open OptimizerTexpr
-open Common
 open Typecore
 open Error
 
@@ -93,10 +92,25 @@ let api_inline2 basic platform c field params p =
 	| _ ->
 		None
 
-let api_inline ctx c field params p =
+type inline_context = {
+	scom : SafeCom.t;
+	typer : typer option;
+}
+
+let context_of_typer typer = {
+	scom = SafeCom.of_typer typer;
+	typer = Some typer;
+}
+
+let context_of_scom scom = {
+	scom = scom;
+	typer = None;
+}
+
+let api_inline (scom : SafeCom.t) c field params p =
 	let mk_typeexpr path =
-		let m = (try ctx.com.module_lut#find path with Not_found -> die "" __LOC__) in
-		add_dependency ctx.m.curmod m MDepFromTyping;
+		let m = (try scom.find_module path with Not_found -> die "" __LOC__) in
+		add_dependency scom.curclass.cl_module m MDepFromTyping;
 		Option.get (ExtList.List.find_map (function
 			| TClassDecl cl when cl.cl_path = path -> Some (Texpr.Builder.make_static_this cl p)
 			| _ -> None
@@ -106,12 +120,12 @@ let api_inline ctx c field params p =
 	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
+	let tstring = scom.basic.tstring in
+	let tbool = scom.basic.tbool in
+	let tint = scom.basic.tint in
 
 	match c.cl_path, field, params with
-	| ([],"Std"),("is" | "isOfType"),[o;t] | (["js"],"Boot"),"__instanceof",[o;t] when ctx.com.platform = Js ->
+	| ([],"Std"),("is" | "isOfType"),[o;t] | (["js"],"Boot"),"__instanceof",[o;t] when scom.platform = Js ->
 		let is_trivial e =
 			match e.eexpr with
 			| TConst _ | TLocal _ -> true
@@ -141,7 +155,7 @@ let api_inline ctx c field params p =
 		| TTypeExpr (TClassDecl ({ cl_path = [],"Array" })) ->
 			(* generate (o instanceof Array) && o.__enum__ == null check *)
 			let iof = Texpr.Builder.fcall (eJsSyntax()) "instanceof" [o;t] tbool p in
-			if not (Common.defined ctx.com Define.JsEnumsAsArrays) then
+			if not (Define.defined scom.defines Define.JsEnumsAsArrays) then
 				Some iof
 			else begin
 				let enum = mk (TField (o, FDynamic "__enum__")) t_dynamic p in
@@ -156,13 +170,13 @@ let api_inline ctx c field params p =
 				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 ->
+	| (["js"],"Boot"),"__downcastCheck",[o; {eexpr = TTypeExpr (TClassDecl cls) } as t] when scom.platform = Js ->
 		if (has_class_flag cls CInterface) then
 			Some (Texpr.Builder.fcall (Texpr.Builder.make_static_this c p) "__implements" [o;t] tbool p)
 		else
 			Some (Texpr.Builder.fcall (eJsSyntax()) "instanceof" [o;t] tbool p)
 	| (["haxe";"ds";"_Vector"],"Vector_Impl_"),("fromArrayCopy"),[{ eexpr = TArrayDecl args } as edecl] -> (try
-			let platf = match ctx.com.platform with
+			let platf = match scom.platform with
 				| Jvm -> "jvm"
 				| _ -> raise Exit
 			in
@@ -172,7 +186,7 @@ let api_inline ctx c field params p =
 				([platf],"NativeArray")
 			in
 
-			let m = ctx.g.do_load_module ctx mpath null_pos in
+			let m = scom.find_module mpath in
 			let main = List.find (function | TClassDecl _ | TAbstractDecl _ -> true | _ -> false) m.m_types in
 			let t = match follow edecl.etype, main with
 				| TInst({ cl_path = [],"Array" }, [t]), TClassDecl(cl) ->
@@ -185,7 +199,7 @@ let api_inline ctx c field params p =
 		with | Exit ->
 			None)
 	| _ ->
-		api_inline2 ctx.com.basic ctx.com.platform c field params p
+		api_inline2 scom.basic scom.platform c field params p
 
 type in_local = {
 	i_var : tvar;
@@ -259,7 +273,9 @@ let inline_metadata e meta =
 	in
 	List.fold_left inline_meta e meta
 
-class inline_state ctx ethis params cf f p = object(self)
+class inline_state (ictx : inline_context) ethis params cf f p =
+	let scom = ictx.scom in
+object(self)
 	val locals = Hashtbl.create 0
 	val checker = create_affection_checker()
 	val mutable _inlined_vars = []
@@ -424,7 +440,7 @@ class inline_state ctx ethis params cf f p = object(self)
 					if we pass a Null<T> var to an inlined method that needs a T.
 					we need to force a local var to be created on some platforms.
 				*)
-				if ctx.com.config.pf_static && not (is_nullable v.v_type) && is_null e.etype then l.i_force_temp <- true;
+				if scom.platform_config.pf_static && not (is_nullable v.v_type) && is_null e.etype then l.i_force_temp <- true;
 				(*
 					if we cast from Dynamic, create a local var as well to do the cast
 					once and allow DCE to perform properly.
@@ -436,7 +452,7 @@ class inline_state ctx ethis params cf f p = object(self)
 					| TConst TNull , Some c ->
 						(* issue #9357 *)
 						{c with epos = e.epos}
-					| _ , Some c when (match c.eexpr with TConst TNull -> false | _ -> true) && (not ctx.com.config.pf_static || is_nullable v.v_type) ->
+					| _ , Some c when (match c.eexpr with TConst TNull -> false | _ -> true) && (not scom.platform_config.pf_static || is_nullable v.v_type) ->
 						l.i_force_temp <- true;
 						l.i_default_value <- Some {c with epos = e.epos};
 						e
@@ -529,7 +545,7 @@ class inline_state ctx ethis params cf f p = object(self)
 		in
 		let e = (if PMap.is_empty subst then e else inline_params false false e) in
 		let init = match vars with [] -> None | l -> Some l in
-		let md = ctx.c.curclass.cl_module.m_extra.m_display in
+		let md = scom.curclass.cl_module.m_extra.m_display in
 		md.m_inline_calls <- (cf.cf_name_pos,{p with pmax = p.pmin + String.length cf.cf_name}) :: md.m_inline_calls;
 		let wrap e =
 			(* we can't mute the type of the expression because it is not correct to do so *)
@@ -541,7 +557,7 @@ class inline_state ctx ethis params cf f p = object(self)
 				| TAbstract ({ a_path = [],"Void" },_) -> e
 				| _ -> raise (Unify_error []))
 			| _ ->
-				type_eq (if ctx.com.config.pf_static then EqDoNotFollowNull else EqStrict) etype tret;
+				type_eq (if scom.platform_config.pf_static then EqDoNotFollowNull else EqStrict) etype tret;
 				e)
 			with Unify_error _ ->
 				mk (TCast (e,None)) tret e.epos
@@ -561,10 +577,10 @@ class inline_state ctx ethis params cf f p = object(self)
 				let el = DynArray.create () in
 				let add = DynArray.add el in
 				List.iter (fun (v,eo) ->
-					add (mk (TVar (v,eo)) ctx.t.tvoid e.epos);
+					add (mk (TVar (v,eo)) scom.basic.tvoid e.epos);
 				) vl;
 				List.iter (fun (l,e) -> match l.i_default_value with
-					| Some e when l.i_read > 0 -> add (Texpr.set_default ctx.com.basic l.i_subst e e.epos)
+					| Some e when l.i_read > 0 -> add (Texpr.set_default scom.basic l.i_subst e e.epos)
 					| _ -> ()
 				) _inlined_vars;
 				begin match e.eexpr with
@@ -589,6 +605,12 @@ class inline_state ctx ethis params cf f p = object(self)
 			| _ -> unify_func());
 		end;
 		let vars = Hashtbl.create 0 in
+		let maybe_reapply_overload_call = match ictx.typer with
+			| Some ctx ->
+				(!maybe_reapply_overload_call_ref) ctx
+			| None ->
+				(fun e -> e)
+		in
 		let rec map_var map_type v =
 			if not (Hashtbl.mem vars v.v_id) then begin
 				Hashtbl.add vars v.v_id ();
@@ -612,7 +634,7 @@ class inline_state ctx ethis params cf f p = object(self)
 				else map_type
 			in
 			let e = Type.map_expr_type (map_expr_type map_type) map_type (map_var map_type) e in
-			(!maybe_reapply_overload_call_ref) ctx e
+			maybe_reapply_overload_call e
 		in
 		let e = map_expr_type map_type e in
 		let rec drop_unused_vars e =
@@ -630,21 +652,25 @@ class inline_state ctx ethis params cf f p = object(self)
 		drop_unused_vars e
 end
 
-let rec type_inline ctx cf f ethis params tret config p ?(self_calling_closure=false) force =
-	(* perform some specific optimization before we inline the call since it's not possible to detect at final optimization time *)
+let rec type_inline (ictx : inline_context) cf f ethis params tret config p ?(self_calling_closure=false) force =
+	let scom = ictx.scom in
 	try
 		let cl = (match follow ethis.etype with
 			| TInst (c,_) -> c
 			| TAnon a -> (match !(a.a_status) with ClassStatics c -> c | _ -> raise Exit)
 			| _ -> raise Exit
 		) in
-		(match api_inline ctx cl cf.cf_name params p with
-		| None -> raise Exit
-		| Some e -> e)
+		begin match api_inline scom cl cf.cf_name params p with
+			| None -> raise Exit
+			| Some e -> e
+		end
 	with Exit ->
 	let has_params,map_type = match config with Some config -> config | None -> inline_default_config cf ethis.etype in
-	let params = inline_rest_params ctx f params map_type p in
-	let state = new inline_state ctx ethis params cf f p in
+	let params = match ictx.typer with
+		| Some ctx -> inline_rest_params ctx f params map_type p
+		| None -> params
+	in
+	let state = new inline_state ictx ethis params cf f p in
 	let vthis_opt = state#initialize in
 	let opt f = function
 		| None -> None
@@ -655,13 +681,17 @@ let rec type_inline ctx cf f ethis params tret config p ?(self_calling_closure=f
 		(* If the function return is Dynamic or Void, stick to it. *)
 		if follow f.tf_type == t_dynamic || ExtType.is_void (follow f.tf_type) then f.tf_type
 		(* If the expression is Void, find common type of its branches. *)
-		else if ExtType.is_void t then unify_min ctx el
+		else if ExtType.is_void t then UnifyMin.unify_min_raise scom.basic el
 		else t
 	in
 	let map_pos =
-		if self_calling_closure || Common.defined ctx.com Define.KeepInlinePositions then (fun e -> e)
+		if self_calling_closure || Define.defined scom.defines Define.KeepInlinePositions then (fun e -> e)
 		else (fun e -> { e with epos = p })
 	in
+	let save_locals = match ictx.typer with
+		| Some ctx -> (fun () -> save_locals ctx)
+		| None -> (fun () -> fun() -> ())
+	in
 	let rec map term in_call e =
 		let po = e.epos in
 		let e = map_pos e in
@@ -732,7 +762,7 @@ let rec type_inline ctx cf f ethis params tret config p ?(self_calling_closure=f
 				lv,e
 			) catches); etype = t }
 		| TBlock l ->
-			let old = save_locals ctx in
+			let old = save_locals () in
 			let t = ref e.etype in
 			let rec has_term_return e =
 				let rec loop e =
@@ -797,7 +827,7 @@ let rec type_inline ctx cf f ethis params tret config p ?(self_calling_closure=f
 					{e with eexpr = TObjectDecl fl}
 			end
 		| TFunction f ->
-			let old = save_locals ctx in
+			let old = save_locals () in
 			let args = List.map (function(v,c) -> (state#declare v).i_subst, c) f.tf_args in
 			let restore = state#enter_local_fun in
 			let expr = map false false f.tf_expr in
@@ -808,7 +838,7 @@ let rec type_inline ctx cf f ethis params tret config p ?(self_calling_closure=f
 			state#set_side_effect;
 			begin match follow t with
 			| TInst({ cl_constructor = Some ({cf_kind = Method MethInline; cf_expr = Some ({eexpr = TFunction tf})} as cf)} as c,_) ->
-				let e = type_inline_ctor ctx c cf tf ethis el po in
+				let e = type_inline_ctor ictx c cf tf ethis el po in
 				map term false e
 			| _ -> raise_typing_error "Cannot inline function containing super" po
 			end
@@ -842,19 +872,22 @@ let rec type_inline ctx cf f ethis params tret config p ?(self_calling_closure=f
 	in
 	let tl = arg_types params f.tf_args in
 	let e = state#finalize e tl tret has_params map_type p in
-	if Meta.has (Meta.Custom ":inlineDebug") ctx.f.meta then begin
-		let se t = s_expr_ast true t (s_type (print_context())) in
-		print_endline (Printf.sprintf "Inline %s:\n\tArgs: %s\n\tExpr: %s\n\tResult: %s"
-			cf.cf_name
-			(String.concat "" (List.map (fun (i,e) -> Printf.sprintf "\n\t\t%s<%i> = %s" (i.i_subst.v_name) (i.i_subst.v_id) (se "\t\t" e)) state#inlined_vars))
-			(se "\t" f.tf_expr)
-			(se "\t" e)
-		);
+	begin match ictx.typer with
+		| Some ctx when Meta.has (Meta.Custom ":inlineDebug") ctx.f.meta ->
+			let se t = s_expr_ast true t (s_type (print_context())) in
+			print_endline (Printf.sprintf "Inline %s:\n\tArgs: %s\n\tExpr: %s\n\tResult: %s"
+				cf.cf_name
+				(String.concat "" (List.map (fun (i,e) -> Printf.sprintf "\n\t\t%s<%i> = %s" (i.i_subst.v_name) (i.i_subst.v_id) (se "\t\t" e)) state#inlined_vars))
+				(se "\t" f.tf_expr)
+				(se "\t" e)
+			);
+		| _ ->
+			()
 	end;
 	e
 
 (* Same as type_inline, but modifies the function body to add field inits *)
-and type_inline_ctor ctx c cf tf ethis el po =
+and type_inline_ctor ictx c cf tf ethis el po =
 	let field_inits =
 		let cparams = extract_param_types c.cl_params in
 		let ethis = mk (TConst TThis) (TInst (c,cparams)) c.cl_pos in
@@ -872,9 +905,9 @@ and type_inline_ctor ctx c cf tf ethis el po =
 		if field_inits = [] then tf
 		else
 			let bl = match tf.tf_expr with {eexpr = TBlock b } -> b | x -> [x] in
-			{tf with tf_expr = mk (TBlock (field_inits @ bl)) ctx.t.tvoid c.cl_pos}
+			{tf with tf_expr = mk (TBlock (field_inits @ bl)) ictx.scom.basic.tvoid c.cl_pos}
 	in
-	type_inline ctx cf tf ethis el ctx.t.tvoid None po true
+	type_inline ictx cf tf ethis el ictx.scom.basic.tvoid None po true
 
 and inline_rest_params ctx f params map_type p =
 	if not ctx.com.config.pf_supports_rest_args then

+ 18 - 18
src/optimization/inlineConstructors.ml

@@ -18,9 +18,9 @@
  *)
 
 open Ast
-open Type
-open Common
 open Typecore
+open SafeCom
+open Type
 open Error
 open Globals
 
@@ -116,7 +116,7 @@ and inline_expression_handled =
 	| IEHIgnored (* The result of the expression will not be used *)
 	| IEHNotHandled (* Cases that are not handled (usually leads to cancelling inlining *)
 
-let inline_constructors ctx original_e =
+let inline_constructors (scom : SafeCom.t) original_e =
 	let inline_objs = ref IntMap.empty in
 	let vars = ref IntMap.empty in
 	let scoped_ivs = ref [] in
@@ -131,7 +131,7 @@ let inline_constructors ctx original_e =
 			| IOKCtor(ioc) ->
 				List.iter (fun v -> if v.v_id < 0 then cancel_v v p) io.io_dependent_vars;
 				if ioc.ioc_forced then begin
-					display_error_ext ctx.com (make_error (Custom "Forced inline constructor could not be inlined") ~sub:([
+					SafeCom.add_error scom (make_error (Custom "Forced inline constructor could not be inlined") ~sub:([
 						(make_error ~depth:1 (Custom (compl_msg "Cancellation happened here")) p)
 					]) io.io_pos);
 				end
@@ -183,7 +183,7 @@ let inline_constructors ctx original_e =
 	let get_io_field (io:inline_object) (s:string) : inline_var =
 		PMap.find s io.io_fields
 	in
-	let alloc_io_field_full (io:inline_object) (fname:string) (constexpr_option:texpr option) (t:t) (p:pos) : inline_var =
+	let alloc_io_field_full (io:inline_object) (fname:string) (constexpr_option:texpr option) (t:Type.t) (p:pos) : inline_var =
 		let v = alloc_var VInlined fname t p in
 		let iv = add v (IVKField (io,fname,constexpr_option)) in
 		io.io_fields <- PMap.add fname iv io.io_fields;
@@ -201,7 +201,7 @@ let inline_constructors ctx original_e =
 	in
 	let is_extern_ctor c cf = (has_class_flag c CExtern) || has_class_field_flag cf CfExtern in
 	let make_expr_for_list (el:texpr list) (t:t) (p:pos): texpr = match el with
-		| [] -> mk (TBlock[]) ctx.t.tvoid p
+		| [] -> mk (TBlock[]) scom.basic.tvoid p
 		| [e] -> e
 		| _ -> mk (TBlock (el)) t p
 	in
@@ -222,7 +222,7 @@ let inline_constructors ctx original_e =
 			| TNew _, true ->
 				true, false
 			| TNew({ cl_constructor = Some ({cf_kind = Method MethInline; cf_expr = Some ({eexpr = TFunction _})} as cf)} as c,_,_), _ ->
-				needs_inline ctx (Some c) cf, false
+				needs_inline scom (Some c) cf, false
 			| _ -> false, false
 		in
 		is_ctor || Type.check_expr (check_for_ctors ~force_inline:is_meta_inline) e
@@ -247,7 +247,7 @@ let inline_constructors ctx original_e =
 			| TNew _, true ->
 				mark()
 			| TNew({ cl_constructor = Some ({cf_kind = Method MethInline; cf_expr = Some ({eexpr = TFunction _})} as cf)} as c,_,_), _ ->
-				if needs_inline ctx (Some c) cf then mark()
+				if needs_inline scom (Some c) cf then mark()
 				else e
 			| _ -> e
 	in
@@ -295,7 +295,7 @@ let inline_constructors ctx original_e =
 					let f = PMap.find fname ctor.ioc_class.cl_fields in
 					begin match f.cf_params, f.cf_kind, f.cf_expr with
 					| [], Method MethInline, Some({eexpr = TFunction tf}) ->
-						if needs_inline ctx (Some ctor.ioc_class) f then
+						if needs_inline scom (Some ctor.ioc_class) f then
 							Some (ctor.ioc_class, ctor.ioc_tparams, f, tf)
 						else
 							None
@@ -327,7 +327,7 @@ let inline_constructors ctx original_e =
 						if is_lvalue && iv_is_const fiv then raise Not_found;
 						if fiv.iv_closed then raise Not_found;
 						if not is_lvalue && fiv.iv_state == IVSUnassigned then (
-							warning ctx WConstructorInliningCancelled ("Constructor inlining cancelled because of use of uninitialized member field " ^ fname) ethis.epos;
+							SafeCom.add_warning scom WConstructorInliningCancelled ("Constructor inlining cancelled because of use of uninitialized member field " ^ fname) ethis.epos;
 							raise Not_found
 						);
 						if captured == IEHNotHandled then cancel_iv fiv efield.epos;
@@ -365,7 +365,7 @@ let inline_constructors ctx original_e =
 					| TConst _ -> loop (vs, e::es) el
 					| _ ->
 						let v = alloc_var VGenerated "arg" e.etype e.epos in
-						let decle = mk (TVar(v, Some e)) ctx.t.tvoid e.epos in
+						let decle = mk (TVar(v, Some e)) scom.basic.tvoid e.epos in
 						ignore(analyze_aliases IEHIgnored decle);
 						let mde = (Meta.InlineConstructorArgument (v.v_id, 0)), [], e.epos in
 						let e = mk (TMeta(mde, e)) e.etype e.epos in
@@ -383,7 +383,7 @@ let inline_constructors ctx original_e =
 					let argvs, pl = analyze_call_args pl in
 					let _, cname = c.cl_path in
 					let v = alloc_var VGenerated ("inl"^cname) e.etype e.epos in
-					let inlined_expr = Inline.type_inline_ctor ctx c cf tf (mk (TLocal v) (TInst (c,tl)) e.epos) pl e.epos in
+					let inlined_expr = Inline.type_inline_ctor (Inline.context_of_scom scom) c cf tf (mk (TLocal v) (TInst (c,tl)) e.epos) pl e.epos in
 					let inlined_expr = mark_ctors inlined_expr in
 					let has_untyped = (Meta.has Meta.HasUntyped cf.cf_meta) in
 					let forced = is_extern_ctor c cf || force_inline in
@@ -417,7 +417,7 @@ let inline_constructors ctx original_e =
 					let e = mk (TBinop(OpAssign,ef,e)) e.etype e.epos in
 					e
 				) fl in
-				let io_expr = make_expr_for_list el ctx.t.tvoid e.epos in
+				let io_expr = make_expr_for_list el scom.basic.tvoid e.epos in
 				let io = mk_io (IOKStructure) io_id io_expr in
 				List.iter (fun ((s,_,_),e) -> ignore(alloc_io_field io s e.etype v.v_pos)) fl;
 				let iv = add v IVKLocal in
@@ -432,9 +432,9 @@ let inline_constructors ctx original_e =
 					let ef = mk (TArray(ev,(mk (TConst(TInt (Int32.of_int i))) e.etype e.epos))) elemtype e.epos in
 					mk (TBinop(OpAssign,ef,e)) elemtype e.epos
 				) el in
-				let io_expr = make_expr_for_list el ctx.t.tvoid e.epos in
+				let io_expr = make_expr_for_list el scom.basic.tvoid e.epos in
 				let io = mk_io (IOKArray(len)) io_id io_expr in
-				ignore(alloc_const_io_field io "length" (mk (TConst(TInt (Int32.of_int len))) ctx.t.tint e.epos));
+				ignore(alloc_const_io_field io "length" (mk (TConst(TInt (Int32.of_int len))) scom.basic.tint e.epos));
 				for i = 0 to len-1 do ignore(alloc_io_field io (int_field_name i) elemtype v.v_pos) done;
 				let iv = add v IVKLocal in
 				set_iv_alias iv io;
@@ -505,7 +505,7 @@ let inline_constructors ctx original_e =
 				let argvs, pl = analyze_call_args call_args in
 				io.io_dependent_vars <- io.io_dependent_vars @ argvs;
 				io.io_has_untyped <- io.io_has_untyped || (Meta.has Meta.HasUntyped cf.cf_meta);
-				let e = Inline.type_inline ctx cf tf (mk (TLocal io_var.iv_var) (TInst (c,tl)) e.epos) pl e.etype None e.epos true in
+				let e = Inline.type_inline (Inline.context_of_scom scom) cf tf (mk (TLocal io_var.iv_var) (TInst (c,tl)) e.epos) pl e.etype None e.epos true in
 				let e = mark_ctors e in
 				io.io_inline_methods <- io.io_inline_methods @ [e];
 				begin match analyze_aliases captured e with
@@ -561,7 +561,7 @@ let inline_constructors ctx original_e =
 		| {iv_kind = IVKField(_,_,Some _)} -> []
 		| {iv_state = IVSCancelled} ->
 			let v = iv.iv_var in
-			[(mk (TVar(v,None)) ctx.t.tvoid v.v_pos)]
+			[(mk (TVar(v,None)) scom.basic.tvoid v.v_pos)]
 		| _ -> []
 	and get_io_var_decls (io:inline_object) : texpr list =
 		if io.io_declared then [] else begin
@@ -728,7 +728,7 @@ let inline_constructors ctx original_e =
 		original_e
 	end else begin
 		let el,_ = final_map e in
-		let cf = ctx.f.curfield in
+		let cf = scom.curfield in
 		if !included_untyped && not (Meta.has Meta.HasUntyped cf.cf_meta) then cf.cf_meta <- (Meta.HasUntyped,[],mk_zero_range_pos e.epos) :: cf.cf_meta;
 		let e = make_expr_for_rev_list el e.etype e.epos in
 		let rec get_pretty_name iv : string list = match iv.iv_kind with

+ 29 - 30
src/optimization/optimizer.ml

@@ -19,7 +19,7 @@
 
 open Ast
 open Type
-open Common
+open SafeCom
 open Typecore
 open OptimizerTexpr
 open Error
@@ -130,11 +130,10 @@ let reduce_control_flow platform e = match e.eexpr with
 	| _ ->
 		e
 
-open Sanitize
-
-let rec reduce_loop ctx stack e =
-	let e = Type.map_expr (reduce_loop ctx stack) e in
-	sanitize_expr ctx.com.config (match e.eexpr with
+let rec reduce_loop (scom : SafeCom.t) stack e =
+	let e = Type.map_expr (reduce_loop scom stack) e in
+	let reduce_expr = Sanitize.reduce_expr in
+	Sanitize.sanitize_expr scom.platform_config (match e.eexpr with
 	| TCall(e1,el) ->
 		begin match Texpr.skip e1 with
 			| { eexpr = TFunction func } as ef ->
@@ -142,68 +141,68 @@ let rec reduce_loop ctx stack e =
 				let ethis = mk (TConst TThis) t_dynamic e.epos in
 				let rt = (match follow ef.etype with TFun (_,rt) -> rt | _ -> die "" __LOC__) in
 				begin try
-					let e = type_inline ctx cf func ethis el rt None e.epos ~self_calling_closure:true false in
-					reduce_loop ctx stack e
+					let e = type_inline (context_of_scom scom) cf func ethis el rt None e.epos ~self_calling_closure:true false in
+					reduce_loop scom stack e
 				with Error { err_message = Custom _ } ->
-					reduce_expr ctx e
+					reduce_expr scom e
 				end;
-			| {eexpr = TField(ef,(FStatic(cl,cf) | FInstance(cl,_,cf)))} when needs_inline ctx (Some cl) cf && not (rec_stack_memq cf stack) ->
+			| {eexpr = TField(ef,(FStatic(cl,cf) | FInstance(cl,_,cf)))} when SafeCom.needs_inline scom (Some cl) cf && not (rec_stack_memq cf stack) ->
 				begin match cf.cf_expr with
 				| Some {eexpr = TFunction tf} ->
 					let config = inline_config (Some cl) cf el e.etype in
 					let rt = (match Abstract.follow_with_abstracts e1.etype with TFun (_,rt) -> rt | _ -> die "" __LOC__) in
 					begin try
-						let e = type_inline ctx cf tf ef el rt config e.epos false in
-						rec_stack_default stack cf (fun cf' -> cf' == cf) (fun () -> reduce_loop ctx stack e) e
+						let e = type_inline (context_of_scom scom) cf tf ef el rt config e.epos false in
+						rec_stack_default stack cf (fun cf' -> cf' == cf) (fun () -> reduce_loop scom stack e) e
 					with Error { err_message = Custom _ } ->
-						reduce_expr ctx e
+						reduce_expr scom e
 					end
 				| _ ->
-					reduce_expr ctx e
+					reduce_expr scom e
 				end
 			| { eexpr = TField ({ eexpr = TTypeExpr (TClassDecl c) },field) } ->
-				(match api_inline ctx c (field_name field) el e.epos with
-				| None -> reduce_expr ctx e
-				| Some e -> reduce_loop ctx stack e)
+				(match api_inline scom c (field_name field) el e.epos with
+				| None -> reduce_expr scom e
+				| Some e -> reduce_loop scom stack e)
 			| _ ->
-				reduce_expr ctx e
+				reduce_expr scom e
 		end
 	| _ ->
-		reduce_expr ctx (reduce_control_flow ctx.com.platform e))
+		reduce_expr scom (reduce_control_flow scom.platform e))
 
-let reduce_expression ctx e =
-	if ctx.com.foptimize then begin
+let reduce_expression scom e =
+	if scom.foptimize then begin
 		(* We go through rec_stack_default here so that the current field is on inline_stack. This prevents self-recursive
 		   inlining (#7569). *)
 		let stack = new_rec_stack() in
-		rec_stack_default stack ctx.f.curfield (fun cf' -> cf' == ctx.f.curfield) (fun () -> reduce_loop ctx stack e) e
+		rec_stack_default stack scom.curfield (fun cf' -> cf' == scom.curfield) (fun () -> reduce_loop scom stack e) e
 	end else
 		e
 
-let rec make_constant_expression ctx stack ?(concat_strings=false) e =
-	let e = reduce_loop ctx stack e in
+let rec make_constant_expression scom stack ?(concat_strings=false) e =
+	let e = reduce_loop scom stack e in
 	match e.eexpr with
 	| TConst _ -> Some e
 	| TField({eexpr = TTypeExpr _},FEnum _) -> Some e
-	| TBinop ((OpAdd|OpSub|OpMult|OpDiv|OpMod|OpShl|OpShr|OpUShr|OpOr|OpAnd|OpXor) as op,e1,e2) -> (match make_constant_expression ctx stack e1,make_constant_expression ctx stack e2 with
+	| TBinop ((OpAdd|OpSub|OpMult|OpDiv|OpMod|OpShl|OpShr|OpUShr|OpOr|OpAnd|OpXor) as op,e1,e2) -> (match make_constant_expression scom stack e1,make_constant_expression scom stack e2 with
 		| Some ({eexpr = TConst (TString s1)}), Some ({eexpr = TConst (TString s2)}) when concat_strings ->
-			Some (mk (TConst (TString (s1 ^ s2))) ctx.com.basic.tstring (punion e1.epos e2.epos))
+			Some (mk (TConst (TString (s1 ^ s2))) scom.basic.tstring (punion e1.epos e2.epos))
 		| Some e1, Some e2 -> Some (mk (TBinop(op, e1, e2)) e.etype e.epos)
 		| _ -> None)
-	| TUnop((Neg | NegBits) as op,Prefix,e1) -> (match make_constant_expression ctx stack e1 with
+	| TUnop((Neg | NegBits) as op,Prefix,e1) -> (match make_constant_expression scom stack e1 with
 		| Some e1 -> Some (mk (TUnop(op,Prefix,e1)) e.etype e.epos)
 		| None -> None)
 	| TCast (e1, None) ->
-		(match make_constant_expression ctx stack e1 with
+		(match make_constant_expression scom stack e1 with
 		| None -> None
 		| Some e1 -> Some {e with eexpr = TCast(e1,None)})
 	| TParenthesis e1 ->
-		begin match make_constant_expression ctx stack ~concat_strings e1 with
+		begin match make_constant_expression scom stack ~concat_strings e1 with
 			| None -> None
 			| Some e1 -> Some {e with eexpr = TParenthesis e1}
 		end
 	| TMeta(m,e1) ->
-		begin match make_constant_expression ctx stack ~concat_strings e1 with
+		begin match make_constant_expression scom stack ~concat_strings e1 with
 			| None -> None
 			| Some e1 -> Some {e with eexpr = TMeta(m,e1)}
 		end

+ 2 - 2
src/typing/calls.ml

@@ -65,10 +65,10 @@ let make_call ctx e params t ?(force_inline=false) p =
 						raise_typing_error ("Abstract 'this' value can only be modified inside an inline function. '" ^ f.cf_name ^ "' modifies 'this'") p;
 			| _ -> ()
 		);
-		let params = List.map (Optimizer.reduce_expression ctx) params in
+		let params = List.map (Optimizer.reduce_expression (SafeCom.of_typer ctx)) params in
 		let force_inline = is_forced_inline cl f in
 		let inline fd =
-			Inline.type_inline ctx f fd ethis params t config p force_inline
+			Inline.type_inline (Inline.context_of_typer ctx) f fd ethis params t config p force_inline
 		in
 		begin match f.cf_expr_unoptimized with
 		| Some {eexpr = TFunction fd} ->

+ 1 - 1
src/typing/functionArguments.ml

@@ -23,7 +23,7 @@ let type_function_arg_value ctx t c do_display =
 		| Some e ->
 			let p = pos e in
 			let e = if do_display then Display.preprocess_expr ctx.com e else e in
-			let e = Optimizer.reduce_expression ctx (type_expr ctx e (WithType.with_type t)) in
+			let e = Optimizer.reduce_expression (SafeCom.of_typer ctx) (type_expr ctx e (WithType.with_type t)) in
 			unify ctx e.etype t p;
 			let rec loop e = match e.eexpr with
 				| TConst _ -> Some e

+ 1 - 1
src/typing/macroContext.ml

@@ -645,7 +645,7 @@ and flush_macro_context mint mctx =
 			in
 			if apply_native then Native.apply_native_paths t
 		in
-		let scom = SafeCom.of_com mctx.com in
+		let scom = SafeCom.of_typer mctx in
 		let cv_wrapper_impl = CapturedVars.get_wrapper_implementation mctx.com in
 		let expr_filters = [
 			"handle_abstract_casts",AbstractCast.handle_abstract_casts;

+ 1 - 1
src/typing/operators.ml

@@ -720,7 +720,7 @@ let handle_assign_op ctx api e1 e2 with_type p =
 			(* bind complex keys to a variable so they do not make it into the output twice *)
 			let save = save_locals ctx in
 			let vr = new value_reference ctx in
-			let maybe_bind_to_temp name e = match Optimizer.make_constant_expression ctx e with
+			let maybe_bind_to_temp name e = match Optimizer.make_constant_expression (SafeCom.of_typer ctx) e with
 				| Some e -> e
 				| None -> vr#as_var name e
 			in

+ 1 - 1
src/typing/typeloadFields.ml

@@ -761,7 +761,7 @@ module TypeBinding = struct
 					| _ -> !analyzer_run_on_expr_ref ctx.com (Printf.sprintf "%s.%s" (s_type_path cctx.tclass.cl_path) cf.cf_name) e
 				in
 				let require_constant_expression e msg =
-					match Optimizer.make_constant_expression ctx (maybe_run_analyzer e) with
+					match Optimizer.make_constant_expression (SafeCom.of_typer ctx) (maybe_run_analyzer e) with
 					| Some e -> e
 					| None -> display_error ctx.com msg p; e
 				in