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

  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.Collections;
  21.     using System.Reflection;
  22.     using System.Reflection.Emit;
  23.    
  24.     internal class Call : AST
  25.     {
  26.         internal AST func;
  27.         private ASTList args;
  28.         private object[] argValues;
  29.         private int outParameterCount;
  30.         internal bool isConstructor;
  31.         internal bool inBrackets;
  32.         private FunctionScope enclosingFunctionScope;
  33.         private bool alreadyPartiallyEvaluated;
  34.         private bool isAssignmentToDefaultIndexedProperty;
  35.        
  36.         internal Call(Context context, AST func, ASTList args, bool inBrackets) : base(context)
  37.         {
  38.             this.func = func;
  39.             this.args = args == null ? new ASTList(context) : args;
  40.             this.argValues = null;
  41.             this.outParameterCount = 0;
  42.             for (int i = 0int n = this.args.count; i < n; i++)
  43.                 if (this.args[i] is AddressOf)
  44.                     this.outParameterCount++;
  45.             this.isConstructor = false;
  46.             this.inBrackets = inBrackets;
  47.             this.enclosingFunctionScope = null;
  48.             this.alreadyPartiallyEvaluated = false;
  49.             this.isAssignmentToDefaultIndexedProperty = false;
  50.             ScriptObject scope = Globals.ScopeStack.Peek();
  51.             while (!(scope is FunctionScope)) {
  52.                 scope = scope.GetParent();
  53.                 if (scope == null)
  54.                     return;
  55.             }
  56.             this.enclosingFunctionScope = (FunctionScope)scope;
  57.         }
  58.        
  59.         private bool AllParamsAreMissing()
  60.         {
  61.             for (int i = 0int n = this.args.count; i < n; i++) {
  62.                 AST p = this.args[i];
  63.                 if (!(p is ConstantWrapper) || ((ConstantWrapper)p).value != System.Reflection.Missing.Value)
  64.                     return false;
  65.             }
  66.             return true;
  67.         }
  68.        
  69.         private IReflect[] ArgIRs()
  70.         {
  71.             int n = this.args.count;
  72.             IReflect[] argIRs = new IReflect[n];
  73.             for (int i = 0; i < n; i++) {
  74.                 AST arg = this.args[i];
  75.                 IReflect ir = argIRs[i] = arg.InferType(null);
  76.                 if (arg is AddressOf) {
  77.                     if (ir is ClassScope)
  78.                         ir = ((ClassScope)ir).GetBakedSuperType();
  79.                     //this should change if ever JS can declare out params
  80.                     argIRs[i] = Convert.ToType("&", Convert.ToType(ir));
  81.                 }
  82.             }
  83.             return argIRs;
  84.         }
  85.        
  86.         // the parser may invoke this function in error condition to change this call to a function declaration
  87.         internal bool CanBeFunctionDeclaration()
  88.         {
  89.             bool canBeFunc = this.func is Lookup && this.outParameterCount == 0;
  90.             if (canBeFunc) {
  91.                 for (int i = 0int n = this.args.count; i < n; i++) {
  92.                     AST item = this.args[i];
  93.                     canBeFunc = item is Lookup;
  94.                     if (!canBeFunc)
  95.                         break;
  96.                 }
  97.             }
  98.             return canBeFunc;
  99.         }
  100.        
  101.         internal override void CheckIfOKToUseInSuperConstructorCall()
  102.         {
  103.             this.func.CheckIfOKToUseInSuperConstructorCall();
  104.         }
  105.        
  106.         internal override bool Delete()
  107.         {
  108.             object[] actual_arguments = this.args == null ? null : this.args.EvaluateAsArray();
  109.             int n = actual_arguments.Length;
  110.             object ob = this.func.Evaluate();
  111.             if (ob == null)
  112.                 return true;
  113.             //As per the standard, not backwards compatible with JS5
  114.             if (n == 0)
  115.                 return true;
  116.             Type obType = ob.GetType();
  117.             MethodInfo deleteOp = obType.GetMethod("op_Delete", BindingFlags.ExactBinding | BindingFlags.Public | BindingFlags.Static, null, new Type[] {obType, Typeob.ArrayOfObject}, null);
  118.             if (deleteOp == null || (deleteOp.Attributes & MethodAttributes.SpecialName) == 0 || deleteOp.ReturnType != Typeob.Boolean)
  119.                 return LateBinding.DeleteMember(ob, Convert.ToString(actual_arguments[n - 1]));
  120.             else {
  121.                 deleteOp = new JSMethodInfo(deleteOp);
  122.                 return (bool)deleteOp.Invoke(null, new object[] {ob, actual_arguments});
  123.             }
  124.         }
  125.        
  126.         internal override object Evaluate()
  127.         {
  128.             if (this.outParameterCount > 0 && VsaEngine.executeForJSEE)
  129.                 throw new JScriptException(JSError.RefParamsNonSupportedInDebugger);
  130.             LateBinding funcref = this.func.EvaluateAsLateBinding();
  131.             object[] actual_arguments = this.args == null ? null : this.args.EvaluateAsArray();
  132.             Globals.CallContextStack.Push(new CallContext(this.context, funcref, actual_arguments));
  133.             try {
  134.                 try {
  135.                     object result = null;
  136.                     CallableExpression cexpr = this.func as CallableExpression;
  137.                     if (cexpr == null || !(cexpr.expression is Call))
  138.                         result = funcref.Call(actual_arguments, this.isConstructor, this.inBrackets, this.Engine);
  139.                     else
  140.                         result = LateBinding.CallValue(funcref.obj, actual_arguments, this.isConstructor, this.inBrackets, this.Engine, cexpr.GetObject2(), JSBinder.ob, null, null);
  141.                     if (this.outParameterCount > 0)
  142.                         for (int i = 0int n = this.args.count; i < n; i++)
  143.                             if (this.args[i] is AddressOf)
  144.                                 this.args[i].SetValue(actual_arguments[i]);
  145.                     return result;
  146.                 }
  147.                 catch (TargetInvocationException e) {
  148.                     JScriptException se;
  149.                     if (e.InnerException is JScriptException) {
  150.                         se = (JScriptException)e.InnerException;
  151.                         if (se.context == null)
  152.                             if (((uint)se.Number) == (2148139008u | (uint)JSError.ObjectExpected))
  153.                                 se.context = this.func.context;
  154.                             else
  155.                                 se.context = this.context;
  156.                     }
  157.                     else
  158.                         se = new JScriptException(e.InnerException, this.context);
  159.                     throw se;
  160.                 }
  161.                 catch (JScriptException e) {
  162.                     if (e.context == null) {
  163.                         if (((uint)e.Number) == (2148139008u | (uint)JSError.ObjectExpected))
  164.                             e.context = this.func.context;
  165.                         else
  166.                             e.context = this.context;
  167.                     }
  168.                     throw e;
  169.                 }
  170.                 catch (Exception e) {
  171.                     throw new JScriptException(e, this.context);
  172.                 }
  173.                 catch {
  174.                     throw new JScriptException(JSError.NonClsException, this.context);
  175.                 }
  176.             }
  177.             finally {
  178.                 Globals.CallContextStack.Pop();
  179.             }
  180.         }
  181.        
  182.         internal void EvaluateIndices()
  183.         {
  184.             this.argValues = this.args.EvaluateAsArray();
  185.         }
  186.        
  187.         // the parser may invoke this function in error condition to change this call to a function declaration
  188.         internal IdentifierLiteral GetName()
  189.         {
  190.             Debug.Assert(this.func is Lookup && this.outParameterCount == 0);
  191.             return new IdentifierLiteral(this.func.ToString(), this.func.context);
  192.         }
  193.        
  194.         // the parser may invoke this function in error condition to change this call to a function declaration
  195.         internal void GetParameters(ArrayList parameters)
  196.         {
  197.             Debug.Assert(this.func is Lookup && this.outParameterCount == 0);
  198.             for (int i = 0int n = this.args.count; i < n; i++) {
  199.                 AST item = this.args[i];
  200.                 parameters.Add(new ParameterDeclaration(item.context, item.ToString(), null, null));
  201.             }
  202.         }
  203.        
  204.         internal override IReflect InferType(JSField inference_target)
  205.         {
  206.             if (this.func is Binding)
  207.                 return ((Binding)this.func).InferTypeOfCall(inference_target, this.isConstructor);
  208.             else if (this.func is ConstantWrapper) {
  209.                 object value = ((ConstantWrapper)this.func).value;
  210.                 if (value is Type || value is ClassScope || value is TypedArray)
  211.                     return (IReflect)value;
  212.             }
  213.             return Typeob.Object;
  214.         }
  215.        
  216.         private JSLocalField[] LocalsThatWereOutParameters()
  217.         {
  218.             int n = this.outParameterCount;
  219.             if (n == 0)
  220.                 return null;
  221.             JSLocalField[] result = new JSLocalField[n];
  222.             int m = 0;
  223.             for (int i = 0; i < n; i++) {
  224.                 AST arg = this.args[i];
  225.                 if (arg is AddressOf) {
  226.                     FieldInfo field = ((AddressOf)arg).GetField();
  227.                     if (field is JSLocalField)
  228.                         result[m++] = (JSLocalField)field;
  229.                 }
  230.             }
  231.             return result;
  232.         }
  233.        
  234.         internal void MakeDeletable()
  235.         {
  236.             if (this.func is Binding) {
  237.                 Binding b = (Binding)this.func;
  238.                 b.InvalidateBinding();
  239.                 b.PartiallyEvaluateAsCallable();
  240.                 b.ResolveLHValue();
  241.             }
  242.         }
  243.        
  244.         internal override AST PartiallyEvaluate()
  245.         {
  246.             if (this.alreadyPartiallyEvaluated)
  247.                 return this;
  248.             this.alreadyPartiallyEvaluated = true;
  249.             if (this.inBrackets && this.AllParamsAreMissing()) {
  250.                 if (this.isConstructor)
  251.                     this.args.context.HandleError(JSError.TypeMismatch);
  252.                 IReflect ir = ((TypeExpression)(new TypeExpression(this.func)).PartiallyEvaluate()).ToIReflect();
  253.                 return new ConstantWrapper(new TypedArray(ir, this.args.count + 1), this.context);
  254.             }
  255.             this.func = this.func.PartiallyEvaluateAsCallable();
  256.             this.args = (ASTList)this.args.PartiallyEvaluate();
  257.             IReflect[] argIRs = this.ArgIRs();
  258.             this.func.ResolveCall(this.args, argIRs, this.isConstructor, this.inBrackets);
  259.             if (!this.isConstructor && !this.inBrackets && this.func is Binding && this.args.count == 1) {
  260.                 Binding b = (Binding)this.func;
  261.                 if (b.member is Type) {
  262.                     Type t = (Type)b.member;
  263.                     ConstantWrapper arg0 = this.args[0] as ConstantWrapper;
  264.                     if (arg0 != null) {
  265.                         try {
  266.                             if (arg0.value == null || arg0.value is DBNull)
  267.                                 return this;
  268.                             else if (arg0.isNumericLiteral && (t == Typeob.Decimal || t == Typeob.Int64 || t == Typeob.UInt64 || t == Typeob.Single))
  269.                                 return new ConstantWrapper(Convert.CoerceT(arg0.context.GetCode(), t, true), this.context);
  270.                             else
  271.                                 return new ConstantWrapper(Convert.CoerceT(arg0.Evaluate(), t, true), this.context);
  272.                         }
  273.                         catch {
  274.                             arg0.context.HandleError(JSError.TypeMismatch);
  275.                         }
  276.                     }
  277.                     else {
  278.                         if (!Binding.AssignmentCompatible(t, this.args[0], argIRs[0], false))
  279.                             this.args[0].context.HandleError(JSError.ImpossibleConversion);
  280.                     }
  281.                 }
  282.                 else if (b.member is JSVariableField) {
  283.                     JSVariableField field = (JSVariableField)b.member;
  284.                     if (field.IsLiteral) {
  285.                         if (field.value is ClassScope) {
  286.                             ClassScope csc = (ClassScope)field.value;
  287.                             IReflect ut = csc.GetUnderlyingTypeIfEnum();
  288.                             if (ut != null) {
  289.                                 if (!Convert.IsPromotableTo(argIRs[0], ut) && !Convert.IsPromotableTo(ut, argIRs[0]) && (argIRs[0] != Typeob.String || ut == csc))
  290.                                     this.args[0].context.HandleError(JSError.ImpossibleConversion);
  291.                             }
  292.                             else {
  293.                                 if (!Convert.IsPromotableTo(argIRs[0], csc) && !Convert.IsPromotableTo(csc, argIRs[0]))
  294.                                     this.args[0].context.HandleError(JSError.ImpossibleConversion);
  295.                             }
  296.                         }
  297.                         else if (field.value is TypedArray) {
  298.                             TypedArray ta = (TypedArray)field.value;
  299.                             if (!Convert.IsPromotableTo(argIRs[0], ta) && !Convert.IsPromotableTo(ta, argIRs[0]))
  300.                                 this.args[0].context.HandleError(JSError.ImpossibleConversion);
  301.                         }
  302.                     }
  303.                 }
  304.             }
  305.             return this;
  306.         }
  307.        
  308.         internal override AST PartiallyEvaluateAsReference()
  309.         {
  310.             this.func = this.func.PartiallyEvaluateAsCallable();
  311.             this.args = (ASTList)this.args.PartiallyEvaluate();
  312.             return this;
  313.         }
  314.        
  315.         internal override void SetPartialValue(AST partial_value)
  316.         {
  317.             if (this.isConstructor)
  318.                 this.context.HandleError(JSError.IllegalAssignment);
  319.             else if (this.func is Binding)
  320.                 ((Binding)this.func).SetPartialValue(this.args, this.ArgIRs(), partial_value, this.inBrackets);
  321.             else if (this.func is ThisLiteral)
  322.                 ((ThisLiteral)this.func).ResolveAssignmentToDefaultIndexedProperty(this.args, this.ArgIRs(), partial_value);
  323.         }
  324.        
  325.         internal override void SetValue(object value)
  326.         {
  327.             LateBinding prop = this.func.EvaluateAsLateBinding();
  328.             try {
  329.                 prop.SetIndexedPropertyValue(this.argValues != null ? this.argValues : this.args.EvaluateAsArray(), value);
  330.             }
  331.             catch (JScriptException e) {
  332.                 if (e.context == null)
  333.                     e.context = this.func.context;
  334.                 throw e;
  335.             }
  336.             catch (Exception e) {
  337.                 throw new JScriptException(e, this.func.context);
  338.             }
  339.             catch {
  340.                 throw new JScriptException(JSError.NonClsException, this.context);
  341.             }
  342.         }
  343.        
  344.         internal override void TranslateToIL(ILGenerator il, Type rtype)
  345.         {
  346.             if (this.context.document.debugOn)
  347.                 il.Emit(OpCodes.Nop);
  348.             bool restoreLocals = true;
  349.             if (this.enclosingFunctionScope != null && this.enclosingFunctionScope.owner != null) {
  350.                 Binding b = this.func as Binding;
  351.                 if (b != null && !this.enclosingFunctionScope.closuresMightEscape) {
  352.                     if (b.member is JSLocalField)
  353.                         this.enclosingFunctionScope.owner.TranslateToILToSaveLocals(il);
  354.                     else
  355.                         restoreLocals = false;
  356.                 }
  357.                 else
  358.                     this.enclosingFunctionScope.owner.TranslateToILToSaveLocals(il);
  359.             }
  360.             this.func.TranslateToILCall(il, rtype, this.args, this.isConstructor, this.inBrackets);
  361.             if (restoreLocals && this.enclosingFunctionScope != null && this.enclosingFunctionScope.owner != null)
  362.                 if (this.outParameterCount == 0)
  363.                     this.enclosingFunctionScope.owner.TranslateToILToRestoreLocals(il);
  364.                 else
  365.                     this.enclosingFunctionScope.owner.TranslateToILToRestoreLocals(il, this.LocalsThatWereOutParameters());
  366.         }
  367.        
  368.         internal CustomAttribute ToCustomAttribute()
  369.         {
  370.             return new CustomAttribute(this.context, this.func, this.args);
  371.         }
  372.        
  373.         internal override void TranslateToILDelete(ILGenerator il, Type rtype)
  374.         {
  375.             IReflect ir = this.func.InferType(null);
  376.             Type obType = Convert.ToType(ir);
  377.             this.func.TranslateToIL(il, obType);
  378.             this.args.TranslateToIL(il, Typeob.ArrayOfObject);
  379.             if (this.func is Binding) {
  380.                 MethodInfo deleteOp;
  381.                 if (ir is ClassScope)
  382.                     deleteOp = ((ClassScope)ir).owner.deleteOpMethod;
  383.                 else
  384.                     deleteOp = ir.GetMethod("op_Delete", BindingFlags.ExactBinding | BindingFlags.Public | BindingFlags.Static, null, new Type[] {obType, Typeob.ArrayOfObject}, null);
  385.                 if (deleteOp != null && (deleteOp.Attributes & MethodAttributes.SpecialName) != 0 && deleteOp.ReturnType == Typeob.Boolean) {
  386.                     il.Emit(OpCodes.Call, deleteOp);
  387.                     Convert.Emit(this, il, Typeob.Boolean, rtype);
  388.                     return;
  389.                 }
  390.             }
  391.             ConstantWrapper.TranslateToILInt(il, this.args.count - 1);
  392.             il.Emit(OpCodes.Ldelem_Ref);
  393.             Convert.Emit(this, il, Typeob.Object, Typeob.String);
  394.             il.Emit(OpCodes.Call, CompilerGlobals.deleteMemberMethod);
  395.             Convert.Emit(this, il, Typeob.Boolean, rtype);
  396.         }
  397.        
  398.         internal override void TranslateToILInitializer(ILGenerator il)
  399.         {
  400.             this.func.TranslateToILInitializer(il);
  401.             this.args.TranslateToILInitializer(il);
  402.         }
  403.        
  404.         internal override void TranslateToILPreSet(ILGenerator il)
  405.         {
  406.             this.func.TranslateToILPreSet(il, this.args);
  407.         }
  408.        
  409.         internal override void TranslateToILPreSet(ILGenerator il, ASTList args)
  410.         {
  411.             this.isAssignmentToDefaultIndexedProperty = true;
  412.             base.TranslateToILPreSet(il, args);
  413.         }
  414.        
  415.         internal override void TranslateToILPreSetPlusGet(ILGenerator il)
  416.         {
  417.             this.func.TranslateToILPreSetPlusGet(il, this.args, this.inBrackets);
  418.         }
  419.        
  420.         internal override void TranslateToILSet(ILGenerator il, AST rhvalue)
  421.         {
  422.             if (this.isAssignmentToDefaultIndexedProperty)
  423.                 base.TranslateToILSet(il, rhvalue);
  424.             else
  425.                 this.func.TranslateToILSet(il, rhvalue);
  426.         }
  427.     }
  428. }

Developer Fusion