/// <summary>
        /// Saves the given generated method and returns an ID.  For internal use only.
        /// </summary>
        /// <param name="generatedMethod"> The generated method to save. </param>
        /// <returns> The ID that was associated with the generated method. </returns>
        public static long Save(GeneratedMethod generatedMethod)
        {
            if (generatedMethod == null)
                throw new ArgumentNullException("generatedMethod");
            lock (cacheLock)
            {
                // Create a cache (if it hasn't already been created).
                if (generatedMethodCache == null)
                    generatedMethodCache = new Dictionary<long, WeakReference>();

                // Create a weak reference to the generated method and add it to the cache.
                long id = generatedMethodID;
                var weakReference = new WeakReference(generatedMethod);
                generatedMethodCache.Add(id, weakReference);

                // Increment the ID for next time.
                generatedMethodID++;

                // Every X calls to this method, compact the cache by removing any weak references that
                // point to objects that have been collected.
                if (generatedMethodID % compactGeneratedCacheCount == 0)
                {
                    // Remove any weak references that have expired.
                    var expiredIDs = new List<long>();
                    foreach (var pair in generatedMethodCache)
                        if (pair.Value.Target == null)
                            expiredIDs.Add(pair.Key);
                    foreach (int expiredID in expiredIDs)
                        generatedMethodCache.Remove(expiredID);
                }

                // Return the ID that was allocated.
                return id;
            }
        }
 /// <summary>
 /// Creates a new instance of a user-defined function.
 /// </summary>
 /// <param name="prototype"> The next object in the prototype chain. </param>
 /// <param name="name"> The name of the function. </param>
 /// <param name="argumentNames"> The names of the arguments. </param>
 /// <param name="parentScope"> The scope at the point the function is declared. </param>
 /// <param name="bodyText"> The source code for the function body. </param>
 /// <param name="generatedMethod"> A delegate which represents the body of the function plus any dependencies. </param>
 /// <param name="strictMode"> <c>true</c> if the function body is strict mode; <c>false</c> otherwise. </param>
 public UserDefinedFunction(ObjectInstance prototype, string name, IList<string> argumentNames, Scope parentScope, string bodyText, GeneratedMethod generatedMethod, bool strictMode)
     : base(prototype)
 {
     Init(name, argumentNames, parentScope, bodyText, generatedMethod, strictMode, true);
 }
 /// <summary>
 /// Compiles the function (if it hasn't already been compiled) and returns a delegate
 /// representing the compiled function.
 /// </summary>
 private FunctionDelegate Compile()
 {
     if (this.body == null)
     {
         // Compile the function.
         var scope = DeclarativeScope.CreateFunctionScope(this.Engine.CreateGlobalScope(), this.Name, this.ArgumentNames);
         var functionGenerator = new FunctionMethodGenerator(this.Engine, scope, this.Name, this.ArgumentNames, this.BodyText, new CompilerOptions());
         functionGenerator.GenerateCode();
         this.generatedMethod = functionGenerator.GeneratedMethod;
         this.body = (FunctionDelegate)this.generatedMethod.GeneratedDelegate;
     }
     return this.body;
 }
        /// <summary>
        /// Initializes a user-defined function.
        /// </summary>
        /// <param name="name"> The name of the function. </param>
        /// <param name="argumentNames"> The names of the arguments. </param>
        /// <param name="parentScope"> The scope at the point the function is declared. </param>
        /// <param name="bodyText"> The source code for the function body. </param>
        /// <param name="generatedMethod"> A delegate which represents the body of the function, plus any dependencies. </param>
        /// <param name="strictMode"> <c>true</c> if the function body is strict mode; <c>false</c> otherwise. </param>
        /// <param name="hasInstancePrototype"> <c>true</c> if the function should have a valid
        /// "prototype" property; <c>false</c> if the "prototype" property should be <c>null</c>. </param>
        private void Init(string name, IList<string> argumentNames, Scope parentScope, string bodyText, GeneratedMethod generatedMethod, bool strictMode, bool hasInstancePrototype)
        {
            if (name == null)
                throw new ArgumentNullException("name");
            if (argumentNames == null)
                throw new ArgumentNullException("argumentNames");
            if (bodyText == null)
                throw new ArgumentNullException("bodyText");
            if (generatedMethod == null)
                throw new ArgumentNullException("generatedMethod");
            if (parentScope == null)
                throw new ArgumentNullException("parentScope");
            this.ArgumentNames = new System.Collections.ObjectModel.ReadOnlyCollection<string>(argumentNames);
            this.BodyText = bodyText;
            this.generatedMethod = generatedMethod;
            this.body = (FunctionDelegate)this.generatedMethod.GeneratedDelegate;
            this.ParentScope = parentScope;
            this.StrictMode = strictMode;

            // Add function properties.
            this.FastSetProperty("name", name);
            this.FastSetProperty("length", argumentNames.Count);

            // The empty function doesn't have an instance prototype.
            if (hasInstancePrototype == true)
            {
                this.FastSetProperty("prototype", this.Engine.Object.Construct(), PropertyAttributes.Writable);
                this.InstancePrototype.FastSetProperty("constructor", this, PropertyAttributes.NonEnumerable);
            }
        }
        /// <summary>
        /// Generates IL for the script.
        /// </summary>
        public void GenerateCode()
        {
            // Generate the abstract syntax tree if it hasn't already been generated.
            if (this.AbstractSyntaxTree == null)
            {
                Parse();
                Optimize();
            }

            // Initialize global code-gen information.
            var optimizationInfo = new OptimizationInfo(this.Engine);
            optimizationInfo.AbstractSyntaxTree = this.AbstractSyntaxTree;
            optimizationInfo.StrictMode = this.StrictMode;
            optimizationInfo.MethodOptimizationHints = this.MethodOptimizationHints;
            optimizationInfo.FunctionName = this.GetStackName();
            optimizationInfo.Source = this.Source;

            ILGenerator generator;
            if (this.Options.EnableDebugging == false)
            {
                // DynamicMethod requires full trust because of generator.LoadMethodPointer in the
                // FunctionExpression class.

                // Create a new dynamic method.
                System.Reflection.Emit.DynamicMethod dynamicMethod;
#if !SILVERLIGHT
                if (ScriptEngine.LowPrivilegeEnvironment == false)
                {
                    // High privilege path.
                    dynamicMethod = new System.Reflection.Emit.DynamicMethod(
                        GetMethodName(),                                        // Name of the generated method.
                        typeof(object),                                         // Return type of the generated method.
                        GetParameterTypes(),                                    // Parameter types of the generated method.
                        typeof(MethodGenerator),                                // Owner type.
                        true);                                                  // Skip visibility checks.
                    // TODO: Figure out why long methods give BadImageFormatException in .NET 3.5 when generated using DynamicILInfo.
                    if (Environment.Version.Major >= 4)
                        generator = new DynamicILGenerator(dynamicMethod);
                    else
                        generator = new ReflectionEmitILGenerator(dynamicMethod.GetILGenerator());
                }
                else
                {
#endif
                // Low privilege path.
                dynamicMethod = new System.Reflection.Emit.DynamicMethod(
                    GetMethodName(),                                        // Name of the generated method.
                    typeof(object),                                         // Return type of the generated method.
                    GetParameterTypes());                                   // Parameter types of the generated method.
                generator = new ReflectionEmitILGenerator(dynamicMethod.GetILGenerator());
#if !SILVERLIGHT
                }
#endif

                if (this.Engine.EnableILAnalysis == true)
                {
                    // Replace the generator with one that logs.
                    generator = new LoggingILGenerator(generator);
                }

                // Initialization code will appear to come from line 1.
                optimizationInfo.MarkSequencePoint(generator, new SourceCodeSpan(1, 1, 1, 1));

                // Generate the IL.
                GenerateCode(generator, optimizationInfo);
                generator.Complete();

                // Create a delegate from the method.
                this.GeneratedMethod = new GeneratedMethod(dynamicMethod.CreateDelegate(GetDelegate()), optimizationInfo.NestedFunctions);

            }
            else
            {
#if WINDOWS_PHONE
                throw new NotImplementedException();
#else
                // Debugging or low trust path.
                ScriptEngine.ReflectionEmitModuleInfo reflectionEmitInfo = this.Engine.ReflectionEmitInfo;
                if (reflectionEmitInfo == null)
                {
                    reflectionEmitInfo = new ScriptEngine.ReflectionEmitModuleInfo();

                    // Create a dynamic assembly and module.
                    reflectionEmitInfo.AssemblyBuilder = System.Threading.Thread.GetDomain().DefineDynamicAssembly(
                        new System.Reflection.AssemblyName("Jurassic Dynamic Assembly"), System.Reflection.Emit.AssemblyBuilderAccess.Run);

                    // Mark the assembly as debuggable.  This must be done before the module is created.
                    var debuggableAttributeConstructor = typeof(System.Diagnostics.DebuggableAttribute).GetConstructor(
                        new Type[] { typeof(System.Diagnostics.DebuggableAttribute.DebuggingModes) });
                    reflectionEmitInfo.AssemblyBuilder.SetCustomAttribute(
                        new System.Reflection.Emit.CustomAttributeBuilder(debuggableAttributeConstructor,
                            new object[] { 
                                System.Diagnostics.DebuggableAttribute.DebuggingModes.DisableOptimizations | 
                                System.Diagnostics.DebuggableAttribute.DebuggingModes.Default }));

                    // Create a dynamic module.
                    reflectionEmitInfo.ModuleBuilder = reflectionEmitInfo.AssemblyBuilder.DefineDynamicModule("Module", this.Options.EnableDebugging);

                    this.Engine.ReflectionEmitInfo = reflectionEmitInfo;
                }

                // Create a new type to hold our method.
                var typeBuilder = reflectionEmitInfo.ModuleBuilder.DefineType("JavaScriptClass" + reflectionEmitInfo.TypeCount.ToString(), System.Reflection.TypeAttributes.Public | System.Reflection.TypeAttributes.Class);
                reflectionEmitInfo.TypeCount++;

                // Create a method.
                var methodBuilder = typeBuilder.DefineMethod(this.GetMethodName(),
                    System.Reflection.MethodAttributes.HideBySig | System.Reflection.MethodAttributes.Static | System.Reflection.MethodAttributes.Public,
                    typeof(object), GetParameterTypes());

                // Generate the IL for the method.
                generator = new ReflectionEmitILGenerator(methodBuilder.GetILGenerator());

                if (this.Engine.EnableILAnalysis == true)
                {
                    // Replace the generator with one that logs.
                    generator = new LoggingILGenerator(generator);
                }

                if (this.Source.Path != null && this.Options.EnableDebugging == true)
                {
                    // Initialize the debugging information.
                    optimizationInfo.DebugDocument = reflectionEmitInfo.ModuleBuilder.DefineDocument(this.Source.Path, COMHelpers.LanguageType, COMHelpers.LanguageVendor, COMHelpers.DocumentType);
                    methodBuilder.DefineParameter(1, System.Reflection.ParameterAttributes.None, "scriptEngine");
                    methodBuilder.DefineParameter(2, System.Reflection.ParameterAttributes.None, "scope");
                    methodBuilder.DefineParameter(3, System.Reflection.ParameterAttributes.None, "thisValue");
                }
                optimizationInfo.MarkSequencePoint(generator, new SourceCodeSpan(1, 1, 1, 1));
                GenerateCode(generator, optimizationInfo);
                generator.Complete();

                // Bake it.
                var type = typeBuilder.CreateType();
                var methodInfo = type.GetMethod(this.GetMethodName());
                this.GeneratedMethod = new GeneratedMethod(Delegate.CreateDelegate(GetDelegate(), methodInfo), optimizationInfo.NestedFunctions);
#endif //WINDOWS_PHONE
            }

            if (this.Engine.EnableILAnalysis == true)
            {
                // Store the disassembled IL so it can be retrieved for analysis purposes.
                this.GeneratedMethod.DisassembledIL = generator.ToString();
            }
        }
        /// <summary>
        /// Generates IL for the script.
        /// </summary>
        public void GenerateCode()
        {
            // Generate the abstract syntax tree if it hasn't already been generated.
            if (this.AbstractSyntaxTree == null)
            {
                Parse();
                Optimize();
            }

            // Initialize global code-gen information.
            var optimizationInfo = new OptimizationInfo();

            optimizationInfo.AbstractSyntaxTree      = this.AbstractSyntaxTree;
            optimizationInfo.StrictMode              = this.StrictMode;
            optimizationInfo.MethodOptimizationHints = this.MethodOptimizationHints;
            optimizationInfo.FunctionName            = this.GetStackName();
            optimizationInfo.Source = this.Source;

            ILGenerator generator;

            if (this.Options.EnableDebugging == false)
            {
                // DynamicMethod requires full trust because of generator.LoadMethodPointer in the
                // FunctionExpression class.

                // Create a new dynamic method.
                System.Reflection.Emit.DynamicMethod dynamicMethod = new System.Reflection.Emit.DynamicMethod(
                    GetMethodName(),                                        // Name of the generated method.
                    typeof(object),                                         // Return type of the generated method.
                    GetParameterTypes(),                                    // Parameter types of the generated method.
                    typeof(MethodGenerator),                                // Owner type.
                    true);                                                  // Skip visibility checks.
#if __MonoCS__
                generator = new ReflectionEmitILGenerator(dynamicMethod.GetILGenerator());
#else
                generator = new DynamicILGenerator(dynamicMethod);
#endif

                if (this.Options.EnableILAnalysis == true)
                {
                    // Replace the generator with one that logs.
                    generator = new LoggingILGenerator(generator);
                }

                // Initialization code will appear to come from line 1.
                optimizationInfo.MarkSequencePoint(generator, new SourceCodeSpan(1, 1, 1, 1));

                // Generate the IL.
                GenerateCode(generator, optimizationInfo);
                generator.Complete();

                // Create a delegate from the method.
                this.GeneratedMethod = new GeneratedMethod(dynamicMethod.CreateDelegate(GetDelegate()), optimizationInfo.NestedFunctions);
            }
            else
            {
#if WINDOWS_PHONE
                throw new NotImplementedException();
#else
                // Debugging or low trust path.
                ReflectionEmitModuleInfo reflectionEmitInfo = ReflectionEmitInfo;
                if (reflectionEmitInfo == null)
                {
                    reflectionEmitInfo = new ReflectionEmitModuleInfo();

                    // Create a dynamic assembly and module.
                    reflectionEmitInfo.AssemblyBuilder = System.Threading.Thread.GetDomain().DefineDynamicAssembly(
                        new System.Reflection.AssemblyName("Jurassic Dynamic Assembly"), System.Reflection.Emit.AssemblyBuilderAccess.Run);

                    // Mark the assembly as debuggable.  This must be done before the module is created.
                    var debuggableAttributeConstructor = typeof(System.Diagnostics.DebuggableAttribute).GetConstructor(
                        new Type[] { typeof(System.Diagnostics.DebuggableAttribute.DebuggingModes) });
                    reflectionEmitInfo.AssemblyBuilder.SetCustomAttribute(
                        new System.Reflection.Emit.CustomAttributeBuilder(debuggableAttributeConstructor,
                                                                          new object[] {
                        System.Diagnostics.DebuggableAttribute.DebuggingModes.DisableOptimizations |
                        System.Diagnostics.DebuggableAttribute.DebuggingModes.Default
                    }));

                    // Create a dynamic module.
                    reflectionEmitInfo.ModuleBuilder = reflectionEmitInfo.AssemblyBuilder.DefineDynamicModule("Module", this.Options.EnableDebugging);

                    ReflectionEmitInfo = reflectionEmitInfo;
                }

                // Create a new type to hold our method.
                var typeBuilder = reflectionEmitInfo.ModuleBuilder.DefineType("JavaScriptClass" + reflectionEmitInfo.TypeCount.ToString(), System.Reflection.TypeAttributes.Public | System.Reflection.TypeAttributes.Class);
                reflectionEmitInfo.TypeCount++;

                // Create a method.
                var methodBuilder = typeBuilder.DefineMethod(this.GetMethodName(),
                                                             System.Reflection.MethodAttributes.HideBySig | System.Reflection.MethodAttributes.Static | System.Reflection.MethodAttributes.Public,
                                                             typeof(object), GetParameterTypes());

                // Generate the IL for the method.
                generator = new ReflectionEmitILGenerator(methodBuilder.GetILGenerator());

                if (this.Options.EnableILAnalysis == true)
                {
                    // Replace the generator with one that logs.
                    generator = new LoggingILGenerator(generator);
                }

                if (this.Source.Path != null && this.Options.EnableDebugging == true)
                {
                    // Initialize the debugging information.
                    optimizationInfo.DebugDocument = reflectionEmitInfo.ModuleBuilder.DefineDocument(this.Source.Path, COMHelpers.LanguageType, COMHelpers.LanguageVendor, COMHelpers.DocumentType);
                    methodBuilder.DefineParameter(1, System.Reflection.ParameterAttributes.None, "scriptEngine");
                    methodBuilder.DefineParameter(2, System.Reflection.ParameterAttributes.None, "scope");
                    methodBuilder.DefineParameter(3, System.Reflection.ParameterAttributes.None, "thisValue");
                }
                optimizationInfo.MarkSequencePoint(generator, new SourceCodeSpan(1, 1, 1, 1));
                GenerateCode(generator, optimizationInfo);
                generator.Complete();

                // Bake it.
                var type       = typeBuilder.CreateType();
                var methodInfo = type.GetMethod(this.GetMethodName());
                this.GeneratedMethod = new GeneratedMethod(Delegate.CreateDelegate(GetDelegate(), methodInfo), optimizationInfo.NestedFunctions);
#endif //WINDOWS_PHONE
            }

            if (this.Options.EnableILAnalysis == true)
            {
                // Store the disassembled IL so it can be retrieved for analysis purposes.
                this.GeneratedMethod.DisassembledIL = generator.ToString();
            }
        }
        /// <summary>
        /// Generates IL for the script.
        /// </summary>
        public void GenerateCode()
        {
            // Generate the abstract syntax tree if it hasn't already been generated.
            if (this.AbstractSyntaxTree == null)
            {
                Parse();
                Optimize();
            }

            // Initialize global code-gen information.
            var optimizationInfo = new OptimizationInfo();

            optimizationInfo.AbstractSyntaxTree      = this.AbstractSyntaxTree;
            optimizationInfo.StrictMode              = this.StrictMode;
            optimizationInfo.MethodOptimizationHints = this.MethodOptimizationHints;
            optimizationInfo.FunctionName            = this.GetStackName();
            optimizationInfo.Source = this.Source;

            // DynamicMethod requires full trust because of generator.LoadMethodPointer in the
            // FunctionExpression class.

            // Create a new dynamic method.
            System.Reflection.Emit.DynamicMethod dynamicMethod = new System.Reflection.Emit.DynamicMethod(
                GetMethodName(),                                        // Name of the generated method.
                typeof(object),                                         // Return type of the generated method.
                GetParameterTypes(),                                    // Parameter types of the generated method.
                typeof(MethodGenerator),                                // Owner type.
                true);                                                  // Skip visibility checks.
#if USE_DYNAMIC_IL_INFO
            ILGenerator generator = new DynamicILGenerator(dynamicMethod);
#else
            ILGenerator generator = new ReflectionEmitILGenerator(dynamicMethod, emitDebugInfo: false);
#endif

            ILGenerator loggingILGenerator = null;
            if (this.Options.EnableILAnalysis)
            {
                // Replace the generator with one that logs.
                generator = loggingILGenerator = new LoggingILGenerator(generator);
            }

#if DEBUG
            // Replace the generator with one that verifies correctness.
            generator = new VerifyingILGenerator(generator);
#endif

            // Initialization code will appear to come from line 1.
            optimizationInfo.MarkSequencePoint(generator, new SourceCodeSpan(1, 1, 1, 1));

            // Generate the IL.
            GenerateCode(generator, optimizationInfo);
            generator.Complete();

            // Create a delegate from the method.
            this.GeneratedMethod = new GeneratedMethod(dynamicMethod.CreateDelegate(GetDelegate()), optimizationInfo.NestedFunctions);

            if (loggingILGenerator != null)
            {
                // Store the disassembled IL so it can be retrieved for analysis purposes.
                this.GeneratedMethod.DisassembledIL = loggingILGenerator.ToString();
            }
        }
Exemple #8
0
        /// <summary>
        /// Generates CIL for the expression.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        public override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Generate a new method.
            this.context.GenerateCode();

            // Add the generated method to the nested function list.
            if (optimizationInfo.NestedFunctions == null)
            {
                optimizationInfo.NestedFunctions = new List <GeneratedMethod>();
            }
            optimizationInfo.NestedFunctions.Add(this.context.GeneratedMethod);

            // Add all the nested methods to the parent list.
            if (this.context.GeneratedMethod.Dependencies != null)
            {
                foreach (var nestedFunctionExpression in this.context.GeneratedMethod.Dependencies)
                {
                    optimizationInfo.NestedFunctions.Add(nestedFunctionExpression);
                }
            }

            // Store the generated method in the cache.
            long generatedMethodID = GeneratedMethod.Save(this.context.GeneratedMethod);

            // Create a UserDefinedFunction.

            // prototype
            EmitHelpers.LoadScriptEngine(generator);
            generator.Call(ReflectionHelpers.ScriptEngine_Function);
            generator.Call(ReflectionHelpers.FunctionInstance_InstancePrototype);

            // name
            string prefix = null;

            if (Name.IsGetter)
            {
                prefix = "get ";
            }
            else if (Name.IsSetter)
            {
                prefix = "set ";
            }
            if (Name.HasStaticName)
            {
                generator.LoadString(prefix + Name.StaticName);
            }
            else
            {
                // Compute the name at runtime.
                if (prefix != null)
                {
                    generator.LoadString(prefix);
                }
                Name.ComputedName.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToString(generator, Name.ComputedName.ResultType);
                if (prefix != null)
                {
                    generator.CallStatic(ReflectionHelpers.String_Concat_String_String);
                }
            }

            // argumentNames
            generator.LoadInt32(this.Arguments.Count);
            generator.NewArray(typeof(string));
            for (int i = 0; i < this.Arguments.Count; i++)
            {
                generator.Duplicate();
                generator.LoadInt32(i);
                generator.LoadString(this.Arguments[i].Name);
                generator.StoreArrayElement(typeof(string));
            }

            // scope
            Scope.GenerateReference(generator, optimizationInfo);

            // bodyText
            generator.LoadString(this.BodyText);

            // body
            generator.LoadInt64(generatedMethodID);
            generator.Call(ReflectionHelpers.GeneratedMethod_Load);

            // strictMode
            generator.LoadBoolean(this.context.StrictMode);

            // container
            if (ContainerVariable != null)
            {
                generator.LoadVariable(ContainerVariable);
            }
            else
            {
                generator.LoadNull();
            }

            // CreateFunction(ObjectInstance prototype, string name, IList<string> argumentNames,
            //   RuntimeScope scope, Func<Scope, object, object[], object> body,
            //   bool strictMode, FunctionInstance container)
            generator.CallStatic(ReflectionHelpers.ReflectionHelpers_CreateFunction);
        }
Exemple #9
0
        //     CODE-GEN METHODS
        //_________________________________________________________________________________________

        /// <summary>
        /// Creates a new instance of a user-defined function.
        /// </summary>
        /// <param name="prototype"> The next object in the prototype chain. </param>
        /// <param name="name"> The name of the function. </param>
        /// <param name="argumentNames"> The names of the arguments. </param>
        /// <param name="parentScope"> The scope at the point the function is declared. </param>
        /// <param name="bodyText"> The source code for the function body. </param>
        /// <param name="generatedMethod"> A delegate which represents the body of the function plus any dependencies. </param>
        /// <param name="strictMode"> <c>true</c> if the function body is strict mode; <c>false</c> otherwise. </param>
        /// <param name="container"> A reference to the containing class prototype or object literal (or <c>null</c>). </param>
        /// <remarks> This is used by functions declared in JavaScript code (including getters and setters). </remarks>
        public static UserDefinedFunction CreateFunction(ObjectInstance prototype, string name, IList <string> argumentNames,
                                                         RuntimeScope parentScope, string bodyText, GeneratedMethod generatedMethod, bool strictMode, ObjectInstance container)
        {
            return(new UserDefinedFunction(prototype, name, argumentNames, parentScope, bodyText, generatedMethod, strictMode, container));
        }
Exemple #10
0
        /// <summary>
        /// Load the generatedMethodCache from an Assembly, instead of compiling the methods
        /// </summary>
        /// <param name="assembly">The assembly to load the methods from</param>
        /// <param name="prefix">Prefix name for generated types</param>
        public static void LoadCacheFromType(Type type, string prefix)
        {
            generatedMethodCache = new Dictionary<long, WeakReference>();
            protectedMethodList = new List<GeneratedMethod>();

            foreach (System.Reflection.MethodInfo method in type.GetMethods())
            {
                if (method.Name.StartsWith(prefix))
                {
                    long id = Convert.ToInt64(method.Name.Substring(prefix.Length));

                    var delegateMethod = Delegate.CreateDelegate(typeof(Library.FunctionDelegate), method);
                    var generatedMethod = new GeneratedMethod(delegateMethod, new List<GeneratedMethod>());

                    var weakReference = new WeakReference(generatedMethod);
                    generatedMethodCache.Add(id, weakReference);
                    protectedMethodList.Add(generatedMethod); // Protect from GC
                }
            }
        }
        /// <summary>
        /// Generates CIL for the expression.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        public override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Generate a new method.
            this.context.GenerateCode();

            // Add the generated method to the nested function list.
            if (optimizationInfo.NestedFunctions == null)
            {
                optimizationInfo.NestedFunctions = new List <GeneratedMethod>();
            }
            optimizationInfo.NestedFunctions.Add(this.context.GeneratedMethod);

            // Add all the nested methods to the parent list.
            if (this.context.GeneratedMethod.Dependencies != null)
            {
                foreach (var nestedFunctionExpression in this.context.GeneratedMethod.Dependencies)
                {
                    optimizationInfo.NestedFunctions.Add(nestedFunctionExpression);
                }
            }

            // Store the generated method in the cache.
            long generatedMethodID = GeneratedMethod.Save(this.context.GeneratedMethod);

            // Create a UserDefinedFunction.

            // prototype
            EmitHelpers.LoadScriptEngine(generator);
            generator.Call(ReflectionHelpers.ScriptEngine_Function);
            generator.Call(ReflectionHelpers.FunctionInstance_InstancePrototype);

            // name
            generator.LoadString(this.FunctionName);

            // argumentNames
            generator.LoadInt32(this.ArgumentNames.Count);
            generator.NewArray(typeof(string));
            for (int i = 0; i < this.ArgumentNames.Count; i++)
            {
                generator.Duplicate();
                generator.LoadInt32(i);
                generator.LoadString(this.ArgumentNames[i]);
                generator.StoreArrayElement(typeof(string));
            }

            // scope
            EmitHelpers.LoadScope(generator);

            // bodyText
            generator.LoadString(this.BodyText);

            // body
            generator.LoadInt64(generatedMethodID);
            generator.Call(ReflectionHelpers.GeneratedMethod_Load);


            // strictMode
            generator.LoadBoolean(this.context.StrictMode);

            // new UserDefinedFunction(ObjectInstance prototype, string name, IList<string> argumentNames, DeclarativeScope scope, Func<Scope, object, object[], object> body, bool strictMode)
            generator.NewObject(ReflectionHelpers.UserDefinedFunction_Constructor);
        }