private bool IsFullMatch(JSFunctionCode funcCode, ref mdr.DFunctionSignature signature) { ///We might have a case that for example, 2 out of 4 parameters was passed before, but now, we have all parameters passed ///but the first 2 matches the previous ones. Therefore, we check to make sure passed signature matches exactly with ///funcCode (found in code cache). bool isFullMatch; isFullMatch = (funcCode != null) && (funcCode.Signature.Value == (signature.Value & SignatureMask.Value)); return(isFullMatch); }
ILGen.BaseILGenerator CreateStub(JSFunctionCode funcCode, bool enableSpeculation) { var ilGen = JSRuntime.Instance.AsmGenerator.GetILGenerator(); if (enableSpeculation) { var methodName = string.Format("{0}_{1}_s_", FullName, FuncId++); funcCode.SpecializedMethodHandle = ilGen.BeginJittedMethod(methodName); } else { var methodName = string.Format("{0}_{1}", FullName, FuncId++); funcCode.GenericMethodHandle = ilGen.BeginJittedMethod(methodName); } return(ilGen); }
JSFunctionCode Jit(ref mdr.DFunctionSignature signature, out bool isFullMatch) { var config = JSRuntime.Instance.Configuration; lock (this) { var useGenericJITInsteadOfInterpreter = false; var funcCode = Cache.Get(ref signature); var oldFuncCode = funcCode; //This is to keep a second copy in case we wanted to change the funcCode but return this result isFullMatch = IsFullMatch(funcCode, ref signature); if (isFullMatch) { if (funcCode.SpecializedMethod != null) //Everything is already done { return(funcCode); } if (funcCode.GenericMethod != null && //Already has a generic method jitted that we can use !funcCode.IsHot) //Not ready to do specialized JIT yet { return(funcCode); } if (config.EnableInterpreter) { if (!funcCode.IsHot) //Not ready to JIT yet { return(funcCode); } if (funcCode.SpecializedMethodHandle != null) //IsHot and specializing JIT is already in progress { Trace.Write("Interpreting {0} instead of waiting", Declaration); //Instead of waiting, we can just run another round with interpreter return(funcCode); } if (!config.EnableJIT) //IsHot but JIT disabled, Not a common case { return(funcCode); } } else if (funcCode.SpecializedMethodHandle != null) { Debug.Assert(funcCode.GenericMethod != null && funcCode.IsHot, "Invalid situation, this is only reason we could be here!"); //this is for unliketly case that we disable interpreter and enable parallel JIT ///The JIT must have started on it already, but it's .Method was not ready when we where checking above. Trace.Assert(_task != null, "Invalid situation, {0} must have already a compilation task", Declaration); //We not have to wait for this JIT to finish since we don't have any other choice. Trace.Write("Waiting for JIT of {0} to finish", Declaration); _task.Wait(); return(funcCode); } } else { //this menas, we have not seen this signature before and we should start the process for this one again var funcSignature = signature; funcSignature.Value &= SignatureMask.Value; funcCode = new JSFunctionCode(this, ref funcSignature); Cache.Add(funcCode); useGenericJITInsteadOfInterpreter = //We should add all heuristics here Scope.HasLoop || IsBlackListed ; if (config.EnableInterpreter && ( !config.EnableJIT || !useGenericJITInsteadOfInterpreter || !config.EnableRecursiveInterpreter ) ) { isFullMatch = true; //In other words, when interpreter is enabled, we always return full match if (!config.EnableRecursiveInterpreter) { CodeGen.CodeGeneratorWithInlineCache.Execute(this); } return(funcCode); } } Debug.Assert( funcCode != null && //already in Cache config.EnableJIT && //We can jit funcCode.SpecializedMethodHandle == null && //no previous JIT started (!config.EnableInterpreter || //We could not interpret useGenericJITInsteadOfInterpreter || //We do not want to interpret funcCode.IsHot //Time to start the JIT for this function ) , "Invalid situation!"); CurrentStatus = Status.Jitting; Debug.WriteLine("Jitting {0} with sig=0x{1:X}-->{2} from 0x{3:X}", Declaration, funcCode.Signature.Value, string.Join(",", funcCode.Signature.Types), signature.Value); var enableSpeculation = JSRuntime.Instance.Configuration.EnableSpeculativeJIT && funcCode.Profiler != null && funcCode.IsHot && !IsBlackListed; ///During code generation, we may again want to refer this same function (e.g. recursive) ///Therefore, we first add the funcCode to the Cache, and then generate code. ///Also, .MethodInfo of the funcCode should be assigned before the code gen begins (or at the begining) ///so a look up in the cache will return all thre result that we might need during the code geration itself. var ilGen = CreateStub(funcCode, enableSpeculation); if (config.EnableParallelJit && !useGenericJITInsteadOfInterpreter && (config.EnableInterpreter || oldFuncCode != funcCode)//otherwise, there is no point in creating background task and then waiting //&& (funcCode != null || !isNeededForImmediateExecution) ) { ///In this case we either have some result to return, or no one is going to immediately need the results ///therefore, we can create background tasks for compilation. //TODO: if interpreter is enabled, we should disable profiler to make sure it is not changed during JIT var runtime = JSRuntime.Instance; var currTask = _task; if (currTask != null) { _task = currTask.ContinueWith(t => { mdr.Runtime.Instance = JSRuntime.Instance = runtime; GenerateCode(funcCode, ilGen, enableSpeculation); }); //TODO: do we need to make sure while setting up continuation, currTask did not finish and leave us hanging? } else { _task = System.Threading.Tasks.Task.Factory.StartNew(() => { mdr.Runtime.Instance = JSRuntime.Instance = runtime; GenerateCode(funcCode, ilGen, enableSpeculation); }); } if (!config.EnableInterpreter) { return(oldFuncCode); } } else { GenerateCode(funcCode, ilGen, enableSpeculation); isFullMatch = true; //We generated a full match } CurrentStatus = Status.Jitted; return(funcCode); } }
void GenerateCode(JSFunctionCode funcCode, ILGen.BaseILGenerator ilGen, bool enableSpeculation) { var cgInfo = new CodeGenerationInfo(this, funcCode, ilGen); ///This is where we are giong to make different decistions aboud different Phases and passes if (JSRuntime.Instance.Configuration.EnableLightCompiler) { CodeGeneratorLight.Execute(cgInfo); } else { if (JSRuntime.Instance.Configuration.EnableFunctionInlining) { FunctionInliner.Execute(cgInfo); } if (EnableTypeInference) { TypeInferer.Execute(cgInfo); } if (enableSpeculation && !IsBlackListed) { CodeGen.CodeGeneratorWithInlineCache.Execute(this); try { CodeGeneratorWithSpecialization.Execute(cgInfo); } catch (JSDeoptFailedException e) { IsBlackListed = true; ilGen = CreateStub(funcCode, false); cgInfo = new CodeGenerationInfo(this, funcCode, ilGen); funcCode.Profiler = null; if (EnableTypeInference) { TypeInferer.Execute(cgInfo); } CodeGenerator.Execute(cgInfo); } } else { if (this.EnableProfiling && !IsBlackListed) { CodeGeneratorWithProfiling.Execute(cgInfo); } else { CodeGenerator.Execute(cgInfo); } } var method = ilGen.EndJittedMethod(this, funcCode); if (enableSpeculation && !IsBlackListed) { funcCode.SpecializedMethod = method; } else { funcCode.GenericMethod = method; } } }
JSFunctionCode Jit(ref mdr.DFunctionSignature signature, out bool isFullMatch) { var config = JSRuntime.Instance.Configuration; lock (this) { var useGenericJITInsteadOfInterpreter = false; var funcCode = Cache.Get(ref signature); var oldFuncCode = funcCode; //This is to keep a second copy in case we wanted to change the funcCode but return this result isFullMatch = IsFullMatch(funcCode, ref signature); if (isFullMatch) { if (funcCode.SpecializedMethod != null) //Everything is already done return funcCode; if (funcCode.GenericMethod != null //Already has a generic method jitted that we can use && !funcCode.IsHot) //Not ready to do specialized JIT yet return funcCode; if (config.EnableInterpreter) { if (!funcCode.IsHot) //Not ready to JIT yet return funcCode; if (funcCode.SpecializedMethodHandle != null) //IsHot and specializing JIT is already in progress { Trace.Write("Interpreting {0} instead of waiting", Declaration); //Instead of waiting, we can just run another round with interpreter return funcCode; } if (!config.EnableJIT) //IsHot but JIT disabled, Not a common case return funcCode; } else if (funcCode.SpecializedMethodHandle != null) { Debug.Assert(funcCode.GenericMethod != null && funcCode.IsHot, "Invalid situation, this is only reason we could be here!"); //this is for unliketly case that we disable interpreter and enable parallel JIT ///The JIT must have started on it already, but it's .Method was not ready when we where checking above. Trace.Assert(_task != null, "Invalid situation, {0} must have already a compilation task", Declaration); //We not have to wait for this JIT to finish since we don't have any other choice. Trace.Write("Waiting for JIT of {0} to finish", Declaration); _task.Wait(); return funcCode; } } else { //this menas, we have not seen this signature before and we should start the process for this one again var funcSignature = signature; funcSignature.Value &= SignatureMask.Value; funcCode = new JSFunctionCode(this, ref funcSignature); Cache.Add(funcCode); useGenericJITInsteadOfInterpreter = //We should add all heuristics here Scope.HasLoop || IsBlackListed ; if (config.EnableInterpreter && ( !config.EnableJIT || !useGenericJITInsteadOfInterpreter || !config.EnableRecursiveInterpreter ) ) { isFullMatch = true; //In other words, when interpreter is enabled, we always return full match if (!config.EnableRecursiveInterpreter) CodeGen.CodeGeneratorWithInlineCache.Execute(this); return funcCode; } } Debug.Assert( funcCode != null //already in Cache && config.EnableJIT //We can jit && funcCode.SpecializedMethodHandle == null //no previous JIT started && (!config.EnableInterpreter //We could not interpret || useGenericJITInsteadOfInterpreter //We do not want to interpret || funcCode.IsHot //Time to start the JIT for this function ) , "Invalid situation!"); CurrentStatus = Status.Jitting; Debug.WriteLine("Jitting {0} with sig=0x{1:X}-->{2} from 0x{3:X}", Declaration, funcCode.Signature.Value, string.Join(",", funcCode.Signature.Types), signature.Value); var enableSpeculation = JSRuntime.Instance.Configuration.EnableSpeculativeJIT && funcCode.Profiler != null && funcCode.IsHot && !IsBlackListed; ///During code generation, we may again want to refer this same function (e.g. recursive) ///Therefore, we first add the funcCode to the Cache, and then generate code. ///Also, .MethodInfo of the funcCode should be assigned before the code gen begins (or at the begining) ///so a look up in the cache will return all thre result that we might need during the code geration itself. var ilGen = CreateStub(funcCode, enableSpeculation); if (config.EnableParallelJit && !useGenericJITInsteadOfInterpreter && (config.EnableInterpreter || oldFuncCode != funcCode)//otherwise, there is no point in creating background task and then waiting //&& (funcCode != null || !isNeededForImmediateExecution) ) { ///In this case we either have some result to return, or no one is going to immediately need the results ///therefore, we can create background tasks for compilation. //TODO: if interpreter is enabled, we should disable profiler to make sure it is not changed during JIT var runtime = JSRuntime.Instance; var currTask = _task; if (currTask != null) { _task = currTask.ContinueWith(t => { mdr.Runtime.Instance = JSRuntime.Instance = runtime; GenerateCode(funcCode, ilGen, enableSpeculation); }); //TODO: do we need to make sure while setting up continuation, currTask did not finish and leave us hanging? } else _task = System.Threading.Tasks.Task.Factory.StartNew(() => { mdr.Runtime.Instance = JSRuntime.Instance = runtime; GenerateCode(funcCode, ilGen, enableSpeculation); }); if (!config.EnableInterpreter) return oldFuncCode; } else { GenerateCode(funcCode, ilGen, enableSpeculation); isFullMatch = true; //We generated a full match } CurrentStatus = Status.Jitted; return funcCode; } }
void GenerateCode(JSFunctionCode funcCode, ILGen.BaseILGenerator ilGen, bool enableSpeculation) { var cgInfo = new CodeGenerationInfo(this, funcCode, ilGen); ///This is where we are giong to make different decistions aboud different Phases and passes if (JSRuntime.Instance.Configuration.EnableLightCompiler) { CodeGeneratorLight.Execute(cgInfo); } else { if (JSRuntime.Instance.Configuration.EnableFunctionInlining) FunctionInliner.Execute(cgInfo); if (EnableTypeInference) TypeInferer.Execute(cgInfo); if (enableSpeculation && !IsBlackListed) { CodeGen.CodeGeneratorWithInlineCache.Execute(this); try { CodeGeneratorWithSpecialization.Execute(cgInfo); } catch(JSDeoptFailedException e) { IsBlackListed = true; ilGen = CreateStub(funcCode, false); cgInfo = new CodeGenerationInfo(this, funcCode, ilGen); funcCode.Profiler = null; if (EnableTypeInference) TypeInferer.Execute(cgInfo); CodeGenerator.Execute(cgInfo); } } else { if (this.EnableProfiling && !IsBlackListed) CodeGeneratorWithProfiling.Execute(cgInfo); else CodeGenerator.Execute(cgInfo); } var method = ilGen.EndJittedMethod(this, funcCode); if (enableSpeculation && !IsBlackListed) funcCode.SpecializedMethod = method; else funcCode.GenericMethod = method; } }
ILGen.BaseILGenerator CreateStub(JSFunctionCode funcCode, bool enableSpeculation) { var ilGen = JSRuntime.Instance.AsmGenerator.GetILGenerator(); if (enableSpeculation) { var methodName = string.Format("{0}_{1}_s_", FullName, FuncId++); funcCode.SpecializedMethodHandle = ilGen.BeginJittedMethod(methodName); } else { var methodName = string.Format("{0}_{1}", FullName, FuncId++); funcCode.GenericMethodHandle = ilGen.BeginJittedMethod(methodName); } return ilGen; }
private bool IsFullMatch(JSFunctionCode funcCode, ref mdr.DFunctionSignature signature) { ///We might have a case that for example, 2 out of 4 parameters was passed before, but now, we have all parameters passed ///but the first 2 matches the previous ones. Therefore, we check to make sure passed signature matches exactly with ///funcCode (found in code cache). bool isFullMatch; isFullMatch = (funcCode != null) && (funcCode.Signature.Value == (signature.Value & SignatureMask.Value)); return isFullMatch; }