/// <summary>
        /// Prepare() is called once before the first execution of function.
        /// </summary>
        void Prepare()
        {
            if (CurrentStatus < Status.Preparing)
            {
                Analyze();

                var configuration = JSRuntime.Instance.Configuration;

                CurrentStatus = Status.Preparing;

                ParametersMask.Value = mdr.DFunctionSignature.GetMask(ParametersCount);

                //TODO: heuristic to disable TypeInference, we can also see if the func does not have any argument AND the "arguments" variable is not referenced in the functiob body
                EnableTypeInference =
                    configuration.EnableTypeInference &&
                    configuration.EnableJIT &&
                    (ParametersCount <= mdr.DFunctionSignature.TypesPerElement) &&
                    (Scope.HasLoop || Scope.Symbols.Count > 0)
                ;

                //if (ParametersCount <= mdr.DFunctionSignature.TypesPerElement)
                if (EnableTypeInference)
                {
                    SignatureMask.Value = ParametersMask.Value;
                }
                else
                {
                    SignatureMask.Value = mdr.DFunctionSignature.EmptySignature.Value;
                }


                //TODO: make this a configuration parameter.
                EnableProfiling = configuration.EnableProfiling && !IsBlackListed;

                FunctionDeclarationHoister.Execute(this);

                if (configuration.EnableMethodCallResolution)
                {
                    MethodResolver.Execute(this);
                }

                EnableInlineCache = configuration.EnableInlineCache;

                var timer =
                    configuration.ProfileFunctionTime
          ? JSRuntime.StartTimer(configuration.ProfileJitTime, "JS/SymInit/" + Declaration)
          : JSRuntime.StartTimer(configuration.ProfileJitTime, "JS/SymInit");
                try
                {
                    var symbols = Scope.Symbols;

                    for (var i = symbols.Count - 1; i >= 0; --i)
                    {
                        var symbol = symbols[i];

                        if (symbol.SymbolType == JSSymbol.SymbolTypes.ClosedOnLocal ||
                            symbol.SymbolType == JSSymbol.SymbolTypes.ParentLocal ||
                            symbol.SymbolType == JSSymbol.SymbolTypes.Global ||
                            symbol.SymbolType == JSSymbol.SymbolTypes.Unknown
                            )
                        {
                            symbol.AssignFieldId();
                        }
                        Debug.Assert(
                            !symbol.IsParameter
                            ||
                            (symbol.Index == i &&
                             (
                                 (symbol.ParameterIndex == i && (Scope.IsFunctionDeclaration || FunctionIR.Name == null)) ||
                                 (symbol.ParameterIndex == (i - 1) && !Scope.IsFunctionDeclaration && FunctionIR.Name != null)
                             )
                            )
                            , "Invalid situation!, symbol {0} should be paramter with parameter index {1} instead of {2}", symbol.Name, i, symbol.ParameterIndex);
                    }
                }
                finally
                {
                    JSRuntime.StopTimer(timer);
                }

                CurrentStatus = Status.Prepared;
            }
        }