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);
 }
Beispiel #4
0
 public JSFunctionCode(JSFunctionMetadata funcMetadata, ref mdr.DFunctionSignature signature)
     : base(ref signature)
 {
     Metadata = funcMetadata;
 }