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); }
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); } }
/// <summary> /// The following is called if we know about the signature or we know a function is going to be hot in advance /// In this case, we are only interested in the full match case /// </summary> public JSFunctionCode JitSpeculatively(ref mdr.DFunctionSignature signature) { Debug.Warning("This is not yet implemented!"); return(null); }
public JSFunctionCode(JSFunctionMetadata funcMetadata, ref mdr.DFunctionSignature signature) : base(ref signature) { Metadata = funcMetadata; }