The Labs \ Source Viewer \ SSCLI \ Microsoft.JScript \ FunctionExpression

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. namespace Microsoft.JScript
  16. {
  17.    
  18.     using Microsoft.JScript.Vsa;
  19.     using System;
  20.     using System.Reflection;
  21.     using System.Reflection.Emit;
  22.     using System.Globalization;
  23.    
  24.     public sealed class FunctionExpression : AST
  25.     {
  26.         private FunctionObject func;
  27.         private string name;
  28.         private JSVariableField field;
  29.         private LocalBuilder func_local;
  30.         private static int uniqueNumber = 0;
  31.        
  32.         internal FunctionExpression(Context context, AST id, ParameterDeclaration[] formal_parameters, TypeExpression return_type, Block body, FunctionScope own_scope, FieldAttributes attributes) : base(context)
  33.         {
  34.             if (attributes != (FieldAttributes)0) {
  35.                 this.context.HandleError(JSError.SyntaxError);
  36.                 attributes = (FieldAttributes)0;
  37.             }
  38.             ScriptObject enclosingScope = Globals.ScopeStack.Peek();
  39.             this.name = id.ToString();
  40.             if (this.name.Length == 0)
  41.                 this.name = "anonymous " + (uniqueNumber++).ToString(CultureInfo.InvariantCulture);
  42.             else
  43.                 this.AddNameTo(enclosingScope);
  44.             this.func = new FunctionObject(this.name, formal_parameters, return_type, body, own_scope, enclosingScope, this.context, MethodAttributes.Static | MethodAttributes.Public);
  45.         }
  46.        
  47.         void AddNameTo(ScriptObject enclosingScope)
  48.         {
  49.             while (enclosingScope is WithObject)
  50.                 //Can only happen at run time and only if there is an eval
  51.                 enclosingScope = enclosingScope.GetParent();
  52.             FieldInfo field = ((IActivationObject)enclosingScope).GetLocalField(this.name);
  53.             if (field != null)
  54.                 return;
  55.             if (enclosingScope is ActivationObject)
  56.                 if (enclosingScope is FunctionScope)
  57.                     field = ((ActivationObject)enclosingScope).AddNewField(this.name, null, FieldAttributes.Public);
  58.                 else
  59.                     field = ((ActivationObject)enclosingScope).AddNewField(this.name, null, FieldAttributes.Public | FieldAttributes.Static);
  60.             else
  61.                 field = ((StackFrame)enclosingScope).AddNewField(this.name, null, FieldAttributes.Public);
  62.             JSLocalField lfield = field as JSLocalField;
  63.             if (lfield != null) {
  64.                 // emit debug info for the local only if this block of code is in a section that has debug set
  65.                 lfield.debugOn = this.context.document.debugOn;
  66.                 lfield.isDefined = true;
  67.             }
  68.             this.field = (JSVariableField)field;
  69.         }
  70.        
  71.         internal override object Evaluate()
  72.         {
  73.             if (VsaEngine.executeForJSEE)
  74.                 throw new JScriptException(JSError.NonSupportedInDebugger);
  75.             ScriptObject enclosingScope = Globals.ScopeStack.Peek();
  76.             this.func.own_scope.SetParent(enclosingScope);
  77.             Closure result = new Closure(this.func);
  78.             if (this.field != null)
  79.                 this.field.value = result;
  80.             return result;
  81.         }
  82.        
  83.         internal override IReflect InferType(JSField inference_target)
  84.         {
  85.             return Typeob.ScriptFunction;
  86.         }
  87.        
  88.         public static FunctionObject JScriptFunctionExpression(RuntimeTypeHandle handle, string name, string method_name, string[] formal_params, JSLocalField[] fields, bool must_save_stack_locals, bool hasArgumentsObject, string text, VsaEngine engine)
  89.         {
  90.             Type t = Type.GetTypeFromHandle(handle);
  91.             FunctionObject result = new FunctionObject(t, name, method_name, formal_params, fields, must_save_stack_locals, hasArgumentsObject, text, engine);
  92.             return result;
  93.         }
  94.        
  95.         internal override AST PartiallyEvaluate()
  96.         {
  97.             ScriptObject enclosingScope = Globals.ScopeStack.Peek();
  98.             if (ClassScope.ScopeOfClassMemberInitializer(enclosingScope) != null) {
  99.                 this.context.HandleError(JSError.MemberInitializerCannotContainFuncExpr);
  100.                 return this;
  101.             }
  102.             ScriptObject scope = enclosingScope;
  103.             while (scope is WithObject || scope is BlockScope)
  104.                 scope = scope.GetParent();
  105.             FunctionScope fscope = scope as FunctionScope;
  106.             if (fscope != null)
  107.                 fscope.closuresMightEscape = true;
  108.             if (scope != enclosingScope)
  109.                 this.func.own_scope.SetParent(new WithObject(new JSObject(), this.func.own_scope.GetGlobalScope()));
  110.             this.func.PartiallyEvaluate();
  111.             return this;
  112.         }
  113.        
  114.         internal override void TranslateToIL(ILGenerator il, Type rtype)
  115.         {
  116.             //This is executed every time the function expression is executed and constructs a new closure for every execution.
  117.             if (rtype == Typeob.Void)
  118.                 return;
  119.             il.Emit(OpCodes.Ldloc, this.func_local);
  120.             il.Emit(OpCodes.Newobj, CompilerGlobals.closureConstructor);
  121.             Convert.Emit(this, il, Typeob.Closure, rtype);
  122.             if (this.field != null) {
  123.                 il.Emit(OpCodes.Dup);
  124.                 object tok = this.field.GetMetaData();
  125.                 if (tok is LocalBuilder)
  126.                     il.Emit(OpCodes.Stloc, (LocalBuilder)tok);
  127.                 else
  128.                     il.Emit(OpCodes.Stsfld, (FieldInfo)tok);
  129.             }
  130.         }
  131.        
  132.         internal override void TranslateToILInitializer(ILGenerator il)
  133.         {
  134.             //This is executed only once for a given scope. It creates a FunctionObject and stores it in a private local.
  135.             //The FunctionObject is then used to construct a new closure every time the function expression is evaluated.
  136.             //This way, what is a method to IL, ends up as a ScriptFunction object that behaves just like an ECMAScript function.
  137.             this.func.TranslateToIL(compilerGlobals);
  138.             this.func_local = il.DeclareLocal(Typeob.FunctionObject);
  139.             il.Emit(OpCodes.Ldtoken, this.func.classwriter);
  140.             il.Emit(OpCodes.Ldstr, this.name);
  141.             il.Emit(OpCodes.Ldstr, this.func.GetName());
  142.             int n = this.func.formal_parameters.Length;
  143.             ConstantWrapper.TranslateToILInt(il, n);
  144.             il.Emit(OpCodes.Newarr, Typeob.String);
  145.             for (int i = 0; i < n; i++) {
  146.                 il.Emit(OpCodes.Dup);
  147.                 ConstantWrapper.TranslateToILInt(il, i);
  148.                 il.Emit(OpCodes.Ldstr, this.func.formal_parameters[i]);
  149.                 il.Emit(OpCodes.Stelem_Ref);
  150.             }
  151.             n = this.func.fields.Length;
  152.             ConstantWrapper.TranslateToILInt(il, n);
  153.             il.Emit(OpCodes.Newarr, Typeob.JSLocalField);
  154.             for (int i = 0; i < n; i++) {
  155.                 JSLocalField field = this.func.fields[i];
  156.                 il.Emit(OpCodes.Dup);
  157.                 ConstantWrapper.TranslateToILInt(il, i);
  158.                 il.Emit(OpCodes.Ldstr, field.Name);
  159.                 il.Emit(OpCodes.Ldtoken, field.FieldType);
  160.                 ConstantWrapper.TranslateToILInt(il, field.slotNumber);
  161.                 il.Emit(OpCodes.Newobj, CompilerGlobals.jsLocalFieldConstructor);
  162.                 il.Emit(OpCodes.Stelem_Ref);
  163.             }
  164.             if (this.func.must_save_stack_locals)
  165.                 il.Emit(OpCodes.Ldc_I4_1);
  166.             else
  167.                 il.Emit(OpCodes.Ldc_I4_0);
  168.             if (this.func.hasArgumentsObject)
  169.                 il.Emit(OpCodes.Ldc_I4_1);
  170.             else
  171.                 il.Emit(OpCodes.Ldc_I4_0);
  172.             il.Emit(OpCodes.Ldstr, this.func.ToString());
  173.             this.EmitILToLoadEngine(il);
  174.             il.Emit(OpCodes.Call, CompilerGlobals.jScriptFunctionExpressionMethod);
  175.             il.Emit(OpCodes.Stloc, this.func_local);
  176.         }
  177.     }
  178. }

Developer Fusion