/// <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(); } }
/// <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); }
// 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)); }
/// <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); }