Esempio n. 1
0
        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);
        }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
        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);
            }
        }
Esempio n. 4
0
        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;
                }
            }
        }
Esempio n. 5
0
    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;
      }
    }
Esempio n. 6
0
    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;
      }
    }
Esempio n. 7
0
 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;
 }
Esempio n. 8
0
 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;
 }