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

  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.Diagnostics;
  21.     using System.Collections;
  22.     using System.Globalization;
  23.     using System.Reflection;
  24.     using System.Runtime.InteropServices;
  25.     using System.Runtime.InteropServices.Expando;
  26.    
  27.     public sealed class LateBinding
  28.     {
  29.         private object last_ir;
  30.         internal MemberInfo last_member;
  31.         internal MemberInfo[] last_members;
  32.         internal object last_object;
  33.         private string name;
  34.         //If this is null, the default indexed property should be called
  35.         public object obj;
  36.         private bool checkForDebugger;
  37.        
  38.         public LateBinding(string name) : this(name, null, false)
  39.         {
  40.         }
  41.        
  42.         public LateBinding(string name, object obj) : this(name, obj, false)
  43.         {
  44.         }
  45.        
  46.         internal LateBinding(string name, object obj, bool checkForDebugger)
  47.         {
  48.             this.last_ir = null;
  49.             this.last_member = null;
  50.             this.last_members = null;
  51.             this.last_object = null;
  52.             this.name = name;
  53.             this.obj = obj;
  54.             this.checkForDebugger = checkForDebugger;
  55.         }
  56.        
  57.         internal MemberInfo BindToMember()
  58.         {
  59.             Debug.Assert(this.obj != null && this.name != null);
  60.             if (this.obj == this.last_object && this.last_member != null)
  61.                 return this.last_member;
  62.             BindingFlags flags = BindingFlags.Instance | BindingFlags.Public;
  63.             object obj = this.obj;
  64.             Type t = obj.GetType();
  65.             TypeReflector tr = TypeReflector.GetTypeReflectorFor(t);
  66.             IReflect ir = null;
  67.             if (tr.ImplementsIReflect()) {
  68.                 ir = obj as ScriptObject;
  69.                 if (ir != null) {
  70.                     if (obj is ClassScope)
  71.                         flags = BindingFlags.Static | BindingFlags.Public;
  72.                 }
  73.                 else {
  74.                     ir = obj as Type;
  75.                     if (ir != null)
  76.                         flags = BindingFlags.Static | BindingFlags.Public;
  77.                     else
  78.                         ir = (IReflect)obj;
  79.                 }
  80.             }
  81.             else
  82.                 ir = tr;
  83.             this.last_object = this.obj;
  84.             this.last_ir = ir;
  85.             MemberInfo[] members = this.last_members = ir.GetMember(this.name, flags);
  86.             this.last_member = LateBinding.SelectMember(members);
  87.             if (this.obj is Type) {
  88.                 //Add instance members of type Type to the member list
  89.                 MemberInfo[] tmembers = typeof(Type).GetMember(this.name, BindingFlags.Instance | BindingFlags.Public);
  90.                 int n = 0;
  91.                 int m = 0;
  92.                 if (tmembers != null && (n = tmembers.Length) > 0) {
  93.                     if (members == null || (m = members.Length) == 0)
  94.                         this.last_member = LateBinding.SelectMember(this.last_members = tmembers);
  95.                     else {
  96.                         MemberInfo[] jmembers = new MemberInfo[n + m];
  97.                         ArrayObject.Copy(members, 0, jmembers, 0, m);
  98.                         ArrayObject.Copy(tmembers, 0, jmembers, m, n);
  99.                         this.last_member = LateBinding.SelectMember(this.last_members = jmembers);
  100.                     }
  101.                 }
  102.             }
  103.             return this.last_member;
  104.         }
  105.        
  106.         #if !DEBUG
  107.         [DebuggerStepThroughAttribute()]
  108.         [DebuggerHiddenAttribute()]
  109.         #endif
  110.         public object Call(object[] arguments, bool construct, bool brackets, VsaEngine engine)
  111.         {
  112.             try {
  113.                 if (this.name == null)
  114.                     return LateBinding.CallValue(this.obj, arguments, construct, brackets, engine, ((IActivationObject)engine.ScriptObjectStackTop()).GetDefaultThisObject(), JSBinder.ob, null, null);
  115.                 else
  116.                     //Happens when (non simple expr)(args) is evaluated from Eval or the Debugger
  117.                     return this.Call(JSBinder.ob, arguments, null, null, null, construct, brackets, engine);
  118.             }
  119.             catch (TargetInvocationException e) {
  120.                 throw e.InnerException;
  121.             }
  122.         }
  123.        
  124.         #if !DEBUG
  125.         [DebuggerStepThroughAttribute()]
  126.         [DebuggerHiddenAttribute()]
  127.         #endif
  128.         internal object Call(Binder binder, object[] arguments, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters, bool construct, bool brackets, VsaEngine engine)
  129.         {
  130.             MemberInfo member = this.BindToMember();
  131.             //Do a GetMember call and remember the result of the lookup for next time around
  132.            
  133.             //On ScriptObjects, fields/properties pre-empt everything else. Call whatever is the value of the field/property. If it is junk, throw an exception.
  134.             if (this.obj is ScriptObject || this.obj is GlobalObject) {
  135.                 //Handle WithObjects that wrap COMObjects specially
  136.                 if (this.obj is WithObject) {
  137.                     object wob = ((WithObject)this.obj).contained_object;
  138.                     if (!(wob is ScriptObject)) {
  139.                         IReflect irw = LateBinding.GetIRForObjectThatRequiresInvokeMember(wob, VsaEngine.executeForJSEE);
  140.                         if (irw != null)
  141.                             return LateBinding.CallCOMObject(irw, this.name, wob, binder, arguments, modifiers, culture, namedParameters, construct, brackets,
  142.                             engine);
  143.                     }
  144.                 }
  145.                
  146.                 if (member is FieldInfo)
  147.                     return LateBinding.CallValue(((FieldInfo)member).GetValue(this.obj), arguments, construct, brackets, engine, this.obj, JSBinder.ob, null, null);
  148.                 else if (member is PropertyInfo && !(member is JSProperty)) {
  149.                     //JSProperty comes up when running the evaluator and using proper properties.
  150.                     if (!brackets) {
  151.                         JSWrappedPropertyAndMethod propAndMethod = member as JSWrappedPropertyAndMethod;
  152.                         if (propAndMethod != null) {
  153.                             BindingFlags flags = arguments == null || arguments.Length == 0 ? BindingFlags.InvokeMethod : BindingFlags.InvokeMethod | BindingFlags.GetProperty;
  154.                             return propAndMethod.Invoke(this.obj, flags, JSBinder.ob, arguments, null);
  155.                         }
  156.                     }
  157.                     return LateBinding.CallValue(JSProperty.GetValue((PropertyInfo)member, this.obj, null), arguments, construct, brackets, engine, this.obj, JSBinder.ob, null, null);
  158.                 }
  159.                 //The code paths below happen because Lookup and Member set last_member. Without the cache, BindToMember will not deliver a MethodInfo.
  160.                 else if (member is MethodInfo) {
  161.                     if (member is JSMethod)
  162.                         if (construct)
  163.                             return ((JSMethod)member).Construct(arguments);
  164.                         else
  165.                             return ((JSMethod)member).Invoke(this.obj, this.obj, (BindingFlags)0, JSBinder.ob, arguments, null);
  166.                     else {
  167.                         Type dt = member.DeclaringType;
  168.                         if (dt == typeof(object))
  169.                             return LateBinding.CallMethod((MethodInfo)member, arguments, this.obj, binder, culture, namedParameters);
  170.                         else if (dt == typeof(string))
  171.                             return LateBinding.CallMethod((MethodInfo)member, arguments, Convert.ToString(this.obj), binder, culture, namedParameters);
  172.                         else if (Convert.IsPrimitiveNumericType(dt))
  173.                             return LateBinding.CallMethod((MethodInfo)member, arguments, Convert.CoerceT(this.obj, dt), binder, culture, namedParameters);
  174.                         else if (dt == typeof(bool))
  175.                             return LateBinding.CallMethod((MethodInfo)member, arguments, Convert.ToBoolean(this.obj), binder, culture, namedParameters);
  176.                         else if (dt == typeof(StringObject) || dt == typeof(BooleanObject) || dt == typeof(NumberObject) || brackets)
  177.                             return LateBinding.CallMethod((MethodInfo)member, arguments, Convert.ToObject(this.obj, engine), binder, culture, namedParameters);
  178.                         else if (dt == typeof(GlobalObject) && ((MethodInfo)member).IsSpecialName)
  179.                             return LateBinding.CallValue(((MethodInfo)member).Invoke(this.obj, null), arguments, construct, false, engine, this.obj, JSBinder.ob, null, null);
  180.                         else if (!(this.obj is ClassScope)) {
  181.                             if (CustomAttribute.IsDefined(member, typeof(JSFunctionAttribute), false)) {
  182.                                 FieldInfo f = LateBinding.SelectMember(this.last_members) as FieldInfo;
  183.                                 if (f != null) {
  184.                                     //Field holds a closure, call the closure
  185.                                     object obj = this.obj;
  186.                                     if (!(obj is Closure))
  187.                                         obj = f.GetValue(this.obj);
  188.                                     return LateBinding.CallValue(obj, arguments, construct, brackets, engine, this.obj, JSBinder.ob, null, null);
  189.                                 }
  190.                             }
  191.                             return LateBinding.CallValue(new BuiltinFunction(this.obj, (MethodInfo)member), arguments, construct, false, engine, this.obj, JSBinder.ob, null, null);
  192.                         }
  193.                     }
  194.                 }
  195.             }
  196.            
  197.             MethodInfo meth = member as MethodInfo;
  198.             if (meth != null)
  199.                 //Inside the evaluator, and dealing with an early bound method
  200.                 //Get here because of EvaluateAsLateBinding in Lookup and Member. BindToMember will not have set this.member to be a method
  201.                 return LateBinding.CallMethod(meth, arguments, this.obj, binder, culture, namedParameters);
  202.             JSConstructor jscons = member as JSConstructor;
  203.             if (jscons != null)
  204.                 //Inside the evaluator, and dealing with an early bound constructor
  205.                 return LateBinding.CallValue(jscons.cons, arguments, construct, brackets, engine, this.obj, JSBinder.ob, null, null);
  206.             if (member is Type)
  207.                 //Inside the evaluator and dealing with early bound conversion
  208.                 return LateBinding.CallValue(member, arguments, construct, brackets, engine, this.obj, JSBinder.ob, null, null);
  209.             if (member is ConstructorInfo)
  210.                 //Inside the evaluator, and dealing with an early bound constructor
  211.                 return LateBinding.CallOneOfTheMembers(new MemberInfo[] {this.last_member}, arguments, true, this.obj, binder, culture, namedParameters, engine);
  212.            
  213.             if (!construct && member is PropertyInfo) {
  214.                 //Might be a parameterless property that results in an object that has a default method or default indexed property that can be called with the params
  215.                 //Need to special case this, otherwise the next if will end up calling the parameterless property getter, discarding the parameters
  216.                 if (((PropertyInfo)member).GetIndexParameters().Length == 0) {
  217.                     Type rtype = ((PropertyInfo)member).PropertyType;
  218.                     if (rtype == typeof(object)) {
  219.                         MethodInfo getter = JSProperty.GetGetMethod((PropertyInfo)member, false);
  220.                         if (getter != null) {
  221.                             object ob = getter.Invoke(this.obj, null);
  222.                             return LateBinding.CallValue(ob, arguments, construct, brackets, engine, this.obj, JSBinder.ob, null, null);
  223.                         }
  224.                     }
  225.                     MemberInfo[] defaultMembers = TypeReflector.GetTypeReflectorFor(rtype).GetDefaultMembers();
  226.                     if (defaultMembers != null && defaultMembers.Length > 0) {
  227.                         MethodInfo getter = JSProperty.GetGetMethod((PropertyInfo)member, false);
  228.                         if (getter != null) {
  229.                             object ob = getter.Invoke(this.obj, null);
  230.                             return LateBinding.CallOneOfTheMembers(defaultMembers, arguments, false, ob, binder, culture, namedParameters, engine);
  231.                         }
  232.                     }
  233.                 }
  234.             }
  235.            
  236.             //Otherwise, if there are members, we give preference to constructors, methods and properties with matching formal parameter lists.
  237.             if (this.last_members != null && this.last_members.Length > 0) {
  238.                 bool memberCalled;
  239.                 object retval = LateBinding.CallOneOfTheMembers(this.last_members, arguments, construct, this.obj, binder, culture, namedParameters, engine, out memberCalled);
  240.                 if (memberCalled)
  241.                     return retval;
  242.                 //Fall through if no suitable constructor or method or property getter because the value of (this.obj).(this.name) might contain a callable thing.
  243.             }
  244.            
  245.             //If the object is an IDispatch(Ex) use InvokeMember to do the call
  246.             //In all other cases we can assume that BindToMember has already found all the members that are to be found.
  247.             IReflect ir = LateBinding.GetIRForObjectThatRequiresInvokeMember(this.obj, VsaEngine.executeForJSEE);
  248.             if (ir != null)
  249.                 return LateBinding.CallCOMObject(ir, this.name, this.obj, binder, arguments, modifiers, culture, namedParameters, construct, brackets,
  250.                 engine);
  251.            
  252.             //If the object has a field or parameterless property called this.name, we have to try and call the value of that field or property
  253.             object value = LateBinding.GetMemberValue(this.obj, this.name, this.last_member, this.last_members);
  254.             if (!(value is Missing))
  255.                 return LateBinding.CallValue(value, arguments, construct, brackets, engine, this.obj, JSBinder.ob, null, null);
  256.            
  257.             //Give up
  258.             if (brackets)
  259.                 if (this.obj is IActivationObject)
  260.                     throw new JScriptException(JSError.ObjectExpected);
  261.                 else
  262.                     throw new JScriptException(JSError.OLENoPropOrMethod);
  263.             else
  264.                 throw new JScriptException(JSError.FunctionExpected);
  265.         }
  266.        
  267.         #if !DEBUG
  268.         [DebuggerStepThroughAttribute()]
  269.         [DebuggerHiddenAttribute()]
  270.         #endif
  271.         private static object CallCOMObject(IReflect ir, string name, object ob, Binder binder, object[] arguments, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters, bool construct, bool brackets,
  272.         VsaEngine engine)
  273.         {
  274.             try {
  275.                 try {
  276.                     LateBinding.Change64bitIntegersToDouble(arguments);
  277.                     BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.OptionalParamBinding;
  278.                     if (construct)
  279.                         return ir.InvokeMember(name, flags | BindingFlags.CreateInstance, binder, ob, arguments, modifiers, culture, namedParameters);
  280.                     else if (brackets) {
  281.                         // Expression like ob.name[args]. First try to invoke as an indexed property. If that
  282.                         // results in a ArgumentException, try to evaluate (ob.name) and then invoke
  283.                         // the default indexed property on the result.
  284.                         try {
  285.                             return ir.InvokeMember(name, flags | BindingFlags.GetProperty | BindingFlags.GetField, binder, ob, arguments, modifiers, culture, namedParameters);
  286.                         }
  287.                         catch (TargetInvocationException) {
  288.                             object ob1 = ir.InvokeMember(name, flags | BindingFlags.GetProperty | BindingFlags.GetField, binder, ob, new object[0], modifiers, culture, new string[0]);
  289.                             return LateBinding.CallValue(ob1, arguments, construct, brackets, engine, ob1, binder, culture, namedParameters);
  290.                         }
  291.                     }
  292.                     else {
  293.                         int length = arguments == null ? 0 : arguments.Length;
  294.                         if (namedParameters != null && namedParameters.Length > 0 && (namedParameters[0].Equals("[DISPID=-613]") || namedParameters[0].Equals("this")))
  295.                             length--;
  296.                         flags |= length > 0 ? BindingFlags.InvokeMethod | BindingFlags.GetProperty : BindingFlags.InvokeMethod;
  297.                         return ir.InvokeMember(name, flags, binder, ob, arguments, modifiers, culture, namedParameters);
  298.                     }
  299.                 }
  300.                 catch (MissingMemberException) {
  301.                     if (brackets)
  302.                         return null;
  303.                     else
  304.                         //ob["x"]. Tried ob.Item()["x"] but failed. So return undefined.
  305.                         //ob("x"). Tried ob.Item()("x") but failed. Complain that ob is not a callable thing.
  306.                         throw new JScriptException(JSError.FunctionExpected);
  307.                 }
  308.                 catch (COMException e) {
  309.                     int code = e.ErrorCode;
  310.                     if (((uint)code) == 2147614726u || ((uint)code) == 2147614723u)
  311.                         if (brackets)
  312.                             return null;
  313.                         else
  314.                         //Unknown name or Member not found
  315.                             throw new JScriptException(JSError.FunctionExpected);
  316.                     if ((code & 4294901760u) == 2148139008u) {
  317.                         string source = e.Source;
  318.                         if (source != null && source.IndexOf("JScript") != -1)
  319.                             throw new JScriptException(e, null);
  320.                     }
  321.                     throw e;
  322.                 }
  323.             }
  324.             catch (JScriptException e) {
  325.                 if ((e.Number & 65535) == (int)JSError.FunctionExpected) {
  326.                     //try to find a method on System.Object
  327.                     MemberInfo[] members = typeof(object).GetMember(name, BindingFlags.Public | BindingFlags.Instance);
  328.                     if (members != null && members.Length > 0)
  329.                         return LateBinding.CallOneOfTheMembers(members, arguments, construct, ob, binder, culture, namedParameters, engine);
  330.                 }
  331.                 throw e;
  332.             }
  333.         }
  334.        
  335.         #if !DEBUG
  336.         [DebuggerStepThroughAttribute()]
  337.         [DebuggerHiddenAttribute()]
  338.         #endif
  339.         private static object CallMethod(MethodInfo method, object[] arguments, object thisob, Binder binder, CultureInfo culture, string[] namedParameters)
  340.         {
  341.             if (namedParameters != null && namedParameters.Length > 0)
  342.                 if (arguments.Length >= namedParameters.Length)
  343.                     arguments = JSBinder.ArrangeNamedArguments(method, arguments, namedParameters);
  344.                 else
  345.                     throw new JScriptException(JSError.MoreNamedParametersThanArguments);
  346.             object[] newargs = LateBinding.LickArgumentsIntoShape(method.GetParameters(), arguments, binder, culture);
  347.             try {
  348.                 object result = method.Invoke(thisob, BindingFlags.SuppressChangeType, null, newargs, null);
  349.                 if (newargs != arguments && newargs != null && arguments != null) {
  350.                     //Copy elements of newargs back to arguments, in case any of them were passed by reference
  351.                     int n = arguments.Length;
  352.                     int m = newargs.Length;
  353.                     if (m < n)
  354.                         n = m;
  355.                     for (int i = 0; i < n; i++)
  356.                         arguments[i] = newargs[i];
  357.                 }
  358.                 return result;
  359.             }
  360.             catch (TargetException e) {
  361.                 ClassScope csc = thisob as ClassScope;
  362.                 if (csc != null)
  363.                     return csc.FakeCallToTypeMethod(method, newargs, e);
  364.                 throw;
  365.             }
  366.         }
  367.        
  368.         #if !DEBUG
  369.         [DebuggerStepThroughAttribute()]
  370.         [DebuggerHiddenAttribute()]
  371.         #endif
  372.         static internal object CallOneOfTheMembers(MemberInfo[] members, object[] arguments, bool construct, object thisob, Binder binder, CultureInfo culture, string[] namedParameters, VsaEngine engine)
  373.         {
  374.             bool memberCalled;
  375.             object retval = LateBinding.CallOneOfTheMembers(members, arguments, construct, thisob, binder, culture, namedParameters, engine, out memberCalled);
  376.             if (!memberCalled)
  377.                 throw new MissingMemberException();
  378.             return retval;
  379.         }
  380.        
  381.         #if !DEBUG
  382.         [DebuggerStepThroughAttribute()]
  383.         [DebuggerHiddenAttribute()]
  384.         #endif
  385.         static internal object CallOneOfTheMembers(MemberInfo[] members, object[] arguments, bool construct, object thisob, Binder binder, CultureInfo culture, string[] namedParameters, VsaEngine engine, out bool memberCalled)
  386.         {
  387.             //Note that SelectConstructor and SelectMethod take care of named parameters
  388.             memberCalled = true;
  389.             if (construct) {
  390.                 ConstructorInfo cons = JSBinder.SelectConstructor(Runtime.TypeRefs, members, ref arguments, namedParameters);
  391.                 if (cons != null) {
  392.                     if (CustomAttribute.IsDefined(cons, typeof(JSFunctionAttribute), false)) {
  393.                         if (thisob is StackFrame)
  394.                             thisob = ((StackFrame)thisob).closureInstance;
  395.                         int n = arguments.Length;
  396.                         object[] newArguments = new object[n + 1];
  397.                         ArrayObject.Copy(arguments, 0, newArguments, 0, n);
  398.                         newArguments[n] = thisob;
  399.                         arguments = newArguments;
  400.                     }
  401.                     object result = null;
  402.                     JSConstructor jscons = cons as JSConstructor;
  403.                     if (jscons != null)
  404.                         result = jscons.Construct(thisob, LateBinding.LickArgumentsIntoShape(cons.GetParameters(), arguments, JSBinder.ob, culture));
  405.                     else
  406.                         result = cons.Invoke(BindingFlags.SuppressChangeType, null, LateBinding.LickArgumentsIntoShape(cons.GetParameters(), arguments, JSBinder.ob, culture), null);
  407.                     if (result is INeedEngine)
  408.                         ((INeedEngine)result).SetEngine(engine);
  409.                     return result;
  410.                 }
  411.             }
  412.             else {
  413.                 object[] originalArguments = arguments;
  414.                 MethodInfo meth = JSBinder.SelectMethod(Runtime.TypeRefs, members, ref arguments, namedParameters);
  415.                 if (meth != null) {
  416.                     if (meth is JSMethod)
  417.                         return ((JSMethod)meth).Invoke(thisob, thisob, (BindingFlags)0, JSBinder.ob, arguments, null);
  418.                     if (CustomAttribute.IsDefined(meth, typeof(JSFunctionAttribute), false)) {
  419.                         //Dealing with a builtin function
  420.                         if (!construct) {
  421.                             JSBuiltin biFunc = ((JSFunctionAttribute)CustomAttribute.GetCustomAttributes(meth, typeof(JSFunctionAttribute), false)[0]).builtinFunction;
  422.                             if (biFunc != 0) {
  423.                                 IActivationObject iaob = thisob as IActivationObject;
  424.                                 if (iaob != null)
  425.                                     thisob = iaob.GetDefaultThisObject();
  426.                                 return BuiltinFunction.QuickCall(arguments, thisob, biFunc, null, engine);
  427.                             }
  428.                         }
  429.                         return LateBinding.CallValue(new BuiltinFunction(thisob, meth), arguments, construct, false, engine, thisob, JSBinder.ob, null, null);
  430.                     }
  431.                     else {
  432.                         object[] args = LateBinding.LickArgumentsIntoShape(meth.GetParameters(), arguments, JSBinder.ob, culture);
  433.                         if (thisob != null && !meth.DeclaringType.IsAssignableFrom(thisob.GetType())) {
  434.                             if (thisob is StringObject)
  435.                                 return meth.Invoke(((StringObject)thisob).value, BindingFlags.SuppressChangeType, null, args, null);
  436.                             if (thisob is NumberObject)
  437.                                 return meth.Invoke(((NumberObject)thisob).value, BindingFlags.SuppressChangeType, null, args, null);
  438.                             if (thisob is BooleanObject)
  439.                                 return meth.Invoke(((BooleanObject)thisob).value, BindingFlags.SuppressChangeType, null, args, null);
  440.                             if (thisob is ArrayWrapper)
  441.                                 return meth.Invoke(((ArrayWrapper)thisob).value, BindingFlags.SuppressChangeType, null, args, null);
  442.                         }
  443.                         object result = meth.Invoke(thisob, BindingFlags.SuppressChangeType, null, args, null);
  444.                         if (args != originalArguments && arguments == originalArguments && args != null && arguments != null) {
  445.                             //Different because of optional parameters or param arrays. Update the original array in case there were call by reference parameters.
  446.                             int n = arguments.Length;
  447.                             int m = args.Length;
  448.                             if (m < n)
  449.                                 n = m;
  450.                             for (int i = 0; i < n; i++)
  451.                                 arguments[i] = args[i];
  452.                         }
  453.                         return result;
  454.                     }
  455.                 }
  456.             }
  457.             memberCalled = false;
  458.             return null;
  459.         }
  460.        
  461.         #if !DEBUG
  462.         [DebuggerStepThroughAttribute()]
  463.         [DebuggerHiddenAttribute()]
  464.         #endif
  465.         public static object CallValue(object thisob, object val, object[] arguments, bool construct, bool brackets, VsaEngine engine)
  466.         {
  467.             try {
  468.                 return LateBinding.CallValue(val, arguments, construct, brackets, engine, thisob, JSBinder.ob, null, null);
  469.             }
  470.             catch (TargetInvocationException e) {
  471.                 throw e.InnerException;
  472.             }
  473.         }
  474.        
  475.         #if !DEBUG
  476.         [DebuggerStepThroughAttribute()]
  477.         [DebuggerHiddenAttribute()]
  478.         #endif
  479.         public static object CallValue2(object val, object thisob, object[] arguments, bool construct, bool brackets, VsaEngine engine)
  480.         {
  481.             try {
  482.                 return LateBinding.CallValue(val, arguments, construct, brackets, engine, thisob, JSBinder.ob, null, null);
  483.             }
  484.             catch (TargetInvocationException e) {
  485.                 throw e.InnerException;
  486.             }
  487.         }
  488.        
  489.         #if !DEBUG
  490.         [DebuggerStepThroughAttribute()]
  491.         [DebuggerHiddenAttribute()]
  492.         #endif
  493.         static internal object CallValue(object val, object[] arguments, bool construct, bool brackets, VsaEngine engine, object thisob, Binder binder, CultureInfo culture, string[] namedParameters)
  494.         {
  495.             if (construct) {
  496.                 if (val is ScriptFunction) {
  497.                     ScriptFunction fun = (ScriptFunction)val;
  498.                     if (!brackets)
  499.                         goto old_style_behavior;
  500.                     object propVal = propVal = fun[arguments];
  501.                     if (propVal != null)
  502.                         return CallValue(propVal, new object[0], true, false, engine, thisob, binder, culture, namedParameters);
  503.                     Type t = (Type)Runtime.TypeRefs.GetPredefinedType(fun.name);
  504.                     if (t != null) {
  505.                         //It is a function that could be used in a type expression
  506.                         int n = arguments.Length;
  507.                         int[] indices = new int[n];
  508.                         n = 0;
  509.                         foreach (object arg in arguments) {
  510.                             if (arg is Int32) {
  511.                                 indices[n++] = (int)arg;
  512.                                 continue;
  513.                             }
  514.                             IConvertible ic = Convert.GetIConvertible(arg);
  515.                             if (ic == null || !Convert.IsPrimitiveNumericTypeCode(ic.GetTypeCode()))
  516.                                 goto old_style_behavior;
  517.                             double d = ic.ToDouble(null);
  518.                             int i = (int)d;
  519.                             if (d != (double)i)
  520.                                 goto old_style_behavior;
  521.                             indices[n++] = i;
  522.                         }
  523.                         return System.Array.CreateInstance(t, indices);
  524.                     }
  525.                     old_style_behavior:
  526.                     FunctionObject func = fun as FunctionObject;
  527.                     if (func != null) {
  528.                         return func.Construct(thisob as JSObject, arguments == null ? new object[0] : arguments);
  529.                     }
  530.                     else {
  531.                         object result = fun.Construct(arguments == null ? new object[0] : arguments);
  532.                         JSObject jsob = result as JSObject;
  533.                         if (jsob != null)
  534.                             jsob.outer_class_instance = thisob as JSObject;
  535.                         return result;
  536.                     }
  537.                 }
  538.                 else if (val is ClassScope) {
  539.                     if (brackets)
  540.                         return System.Array.CreateInstance(typeof(object), LateBinding.ToIndices(arguments));
  541.                     JSObject result = (JSObject)LateBinding.CallOneOfTheMembers(((ClassScope)val).constructors, arguments, construct, thisob, binder, culture, namedParameters, engine);
  542.                     result.noExpando = ((ClassScope)val).noExpando;
  543.                     return result;
  544.                 }
  545.                 else if (val is Type) {
  546.                     Type t = (Type)val;
  547.                     if (brackets)
  548.                         //we have "new val[x, y, z]" where val is a Type, so create an array of val.
  549.                         return System.Array.CreateInstance(t, LateBinding.ToIndices(arguments));
  550.                     ConstructorInfo[] cons = t.GetConstructors();
  551.                     object result = null;
  552.                     if (cons == null || cons.Length == 0)
  553.                         result = Activator.CreateInstance(t, (BindingFlags)0, JSBinder.ob, arguments, null);
  554.                     else
  555.                         //Happens for interop
  556.                         result = LateBinding.CallOneOfTheMembers(cons, arguments, construct, thisob, binder, culture, namedParameters, engine);
  557.                     if (result is INeedEngine)
  558.                         ((INeedEngine)result).SetEngine(engine);
  559.                     return result;
  560.                 }
  561.                 else if (val is TypedArray && brackets)
  562.                     return System.Array.CreateInstance(typeof(object), LateBinding.ToIndices(arguments));
  563.             }
  564.            
  565.             if (brackets) {
  566.                 ScriptObject scrob = val as ScriptObject;
  567.                 if (scrob != null) {
  568.                     object v = scrob[arguments];
  569.                     if (construct)
  570.                         return LateBinding.CallValue(thisob, v, new object[0], true, false, engine);
  571.                     return v;
  572.                 }
  573.             }
  574.             else {
  575.                 if (val is ScriptFunction) {
  576.                     if (thisob is IActivationObject)
  577.                         thisob = ((IActivationObject)thisob).GetDefaultThisObject();
  578.                     return ((ScriptFunction)val).Call(arguments == null ? new object[0] : arguments, thisob, binder, culture);
  579.                 }
  580.                 else if (val is Delegate)
  581.                     return CallMethod(((Delegate)val).Method, arguments, thisob, binder, culture, namedParameters);
  582.                 else if (val is MethodInfo)
  583.                     return CallMethod((MethodInfo)val, arguments, thisob, binder, culture, namedParameters);
  584.                 else if (val is Type && arguments.Length == 1)
  585.                     return Convert.CoerceT(arguments[0], (Type)val, true);
  586.                 else if (val is ClassScope) {
  587.                     if (arguments == null || arguments.Length != 1)
  588.                         throw new JScriptException(JSError.FunctionExpected);
  589.                     if (((ClassScope)val).HasInstance(arguments[0]))
  590.                         return arguments[0];
  591.                     throw new InvalidCastException(null);
  592.                 }
  593.                 else if (val is TypedArray && arguments.Length == 1)
  594.                     return Convert.Coerce(arguments[0], val, true);
  595.                 else if (val is ScriptObject)
  596.                     throw new JScriptException(JSError.FunctionExpected);
  597.                 else if (val is MemberInfo[])
  598.                     return LateBinding.CallOneOfTheMembers((MemberInfo[])val, arguments, construct, thisob, binder, culture, namedParameters, engine);
  599.             }
  600.            
  601.             if (val != null) {
  602.                 System.Array arr = val as System.Array;
  603.                 if (arr != null) {
  604.                     if (arguments.Length != arr.Rank)
  605.                         throw new JScriptException(JSError.IncorrectNumberOfIndices);
  606.                     return arr.GetValue(LateBinding.ToIndices(arguments));
  607.                 }
  608.                 //See if val has a default indexed property that we can call
  609.                 val = Convert.ToObject(val, engine);
  610.                 ScriptObject scrob = val as ScriptObject;
  611.                 if (scrob != null)
  612.                     if (brackets)
  613.                         return scrob[arguments];
  614.                     else {
  615.                         ScriptFunction sf = scrob as ScriptFunction;
  616.                         if (sf != null) {
  617.                             IActivationObject iaob = thisob as IActivationObject;
  618.                             if (iaob != null)
  619.                                 thisob = iaob.GetDefaultThisObject();
  620.                             return sf.Call(arguments == null ? new object[0] : arguments, thisob, binder, culture);
  621.                         }
  622.                         throw new JScriptException(JSError.InvalidCall);
  623.                     }
  624.                 IReflect ir = LateBinding.GetIRForObjectThatRequiresInvokeMember(val, VsaEngine.executeForJSEE);
  625.                 if (ir != null) {
  626.                     if (brackets) {
  627.                         string name = String.Empty;
  628.                         int n = arguments.Length;
  629.                         if (n > 0)
  630.                             name = Convert.ToString(arguments[n - 1]);
  631.                         return CallCOMObject(ir, name, val, binder, null, null, culture, namedParameters, false, true,
  632.                         engine);
  633.                     }
  634.                    
  635.                     if (!(val is IReflect))
  636.                         return CallCOMObject(ir, String.Empty, val, binder, arguments, null, culture, namedParameters, false, brackets,
  637.                         engine);
  638.                    
  639.                     // Pass in the 'this' object as an additional named parameter
  640.                     object[] arguments2 = new object[(arguments != null ? arguments.Length : 0) + 1];
  641.                     arguments2[0] = thisob;
  642.                     if (arguments != null)
  643.                         ArrayObject.Copy(arguments, 0, arguments2, 1, arguments.Length);
  644.                     string[] namedParameters2 = new string[(namedParameters != null ? namedParameters.Length : 0) + 1];
  645.                     namedParameters2[0] = "[DISPID=-613]";
  646.                     if (namedParameters != null)
  647.                         ArrayObject.Copy(namedParameters, 0, namedParameters2, 1, namedParameters.Length);
  648.                     return CallCOMObject(ir, "[DISPID=0]", val, binder, arguments2, null, culture, namedParameters2, false, brackets,
  649.                     engine);
  650.                 }
  651.                
  652.                
  653.                 MemberInfo[] defaultMembers = TypeReflector.GetTypeReflectorFor(val.GetType()).GetDefaultMembers();
  654.                 if (defaultMembers != null && defaultMembers.Length > 0) {
  655.                     MethodInfo meth = JSBinder.SelectMethod(Runtime.TypeRefs, defaultMembers, ref arguments, namedParameters);
  656.                     //This also selects property getters
  657.                     if (meth != null)
  658.                         return LateBinding.CallMethod(meth, arguments, val, binder, culture, namedParameters);
  659.                 }
  660.             }
  661.            
  662.             throw new JScriptException(JSError.FunctionExpected);
  663.         }
  664.        
  665.         private static void Change64bitIntegersToDouble(object[] arguments)
  666.         {
  667.             if (arguments == null)
  668.                 return;
  669.             for (int i = 0int n = arguments.Length; i < n; i++) {
  670.                 object val = arguments[i];
  671.                 IConvertible ic = Convert.GetIConvertible(val);
  672.                 TypeCode code = Convert.GetTypeCode(val, ic);
  673.                 switch (code) {
  674.                     case TypeCode.Int64:
  675.                     case TypeCode.UInt64:
  676.                         arguments[i] = ic.ToDouble(null);
  677.                         break;
  678.                 }
  679.             }
  680.         }
  681.        
  682.         public bool Delete()
  683.         {
  684.             return LateBinding.DeleteMember(this.obj, this.name);
  685.         }
  686.        
  687.         public static bool DeleteMember(object obj, string name)
  688.         {
  689.             if (name == null || obj == null)
  690.                 return false;
  691.             if (obj is ScriptObject)
  692.                 return ((ScriptObject)obj).DeleteMember(name);
  693.             if (obj is IExpando)
  694.                 try {
  695.                     IExpando eob = (IExpando)obj;
  696.                     MemberInfo[] members = eob.GetMember(name, BindingFlags.Instance | BindingFlags.Public);
  697.                     MemberInfo member = LateBinding.SelectMember(members);
  698.                     if (member != null) {
  699.                         eob.RemoveMember(member);
  700.                         return true;
  701.                     }
  702.                     return false;
  703.                 }
  704.                 catch {
  705.                     return false;
  706.                 }
  707.             if (obj is IDictionary) {
  708.                 IDictionary dict = (IDictionary)obj;
  709.                 if (dict.Contains(name)) {
  710.                     dict.Remove(name);
  711.                     return true;
  712.                 }
  713.                 return false;
  714.             }
  715.             Type obType = obj.GetType();
  716.             MethodInfo deleteOp = TypeReflector.GetTypeReflectorFor(obType).GetMethod("op_Delete", BindingFlags.ExactBinding | BindingFlags.Public | BindingFlags.Static, null, new Type[] {obType, typeof(object[])}, null);
  717.             if (deleteOp == null || (deleteOp.Attributes & MethodAttributes.SpecialName) == 0 || deleteOp.ReturnType != typeof(bool))
  718.                 return false;
  719.             else
  720.                 //This is in the spirit of the spec, but not backwards compatible with JS5. The latter throws an exception.
  721.                 return (bool)deleteOp.Invoke(null, new object[] {obj, new object[] {name}});
  722.         }
  723.        
  724.         static internal bool DeleteValueAtIndex(object obj, ulong index)
  725.         {
  726.             if (obj is ArrayObject && index < UInt32.MaxValue)
  727.                 return ((ArrayObject)obj).DeleteValueAtIndex((uint)index);
  728.             return LateBinding.DeleteMember(obj, index.ToString(CultureInfo.InvariantCulture));
  729.         }
  730.        
  731.         private static IReflect GetIRForObjectThatRequiresInvokeMember(object obj, bool checkForDebugger)
  732.         {
  733.             return null;
  734.         }
  735.        
  736.         private static IReflect GetIRForObjectThatRequiresInvokeMember(object obj, bool checkForDebugger, TypeCode tcode)
  737.         {
  738.             return tcode != TypeCode.Object ? null : LateBinding.GetIRForObjectThatRequiresInvokeMember(obj, checkForDebugger);
  739.         }
  740.        
  741.         #if !DEBUG
  742.         [DebuggerStepThroughAttribute()]
  743.         [DebuggerHiddenAttribute()]
  744.         #endif
  745.         static internal object GetMemberValue(object obj, string name)
  746.         {
  747.             if (obj is ScriptObject)
  748.                 return ((ScriptObject)obj).GetMemberValue(name);
  749.             LateBinding lb = new LateBinding(name, obj);
  750.             return lb.GetNonMissingValue();
  751.         }
  752.        
  753.         #if !DEBUG
  754.         [DebuggerStepThroughAttribute()]
  755.         [DebuggerHiddenAttribute()]
  756.         #endif
  757.         static internal object GetMemberValue2(object obj, string name)
  758.         {
  759.             if (obj is ScriptObject)
  760.                 return ((ScriptObject)obj).GetMemberValue(name);
  761.             LateBinding lb = new LateBinding(name, obj);
  762.             return lb.GetValue();
  763.         }
  764.        
  765.         #if !DEBUG
  766.         [DebuggerStepThroughAttribute()]
  767.         [DebuggerHiddenAttribute()]
  768.         #endif
  769.         static internal object GetMemberValue(object obj, string name, MemberInfo member, MemberInfo[] members)
  770.         {
  771.             if (member != null) {
  772.                 try {
  773.                     switch (member.MemberType) {
  774.                         case MemberTypes.Field:
  775.                             object val = ((FieldInfo)member).GetValue(obj);
  776.                             Type et = obj as Type;
  777.                             if (et != null && et.IsEnum)
  778.                                 try {
  779.                                     val = Enum.ToObject(et, ((IConvertible)val).ToUInt64(null));
  780.                                 }
  781.                                 catch {
  782.                                 }
  783.                             return val;
  784.                         case MemberTypes.Property:
  785.                             PropertyInfo prop = (PropertyInfo)member;
  786.                             if (prop.DeclaringType == typeof(ArrayObject)) {
  787.                                 ArrayObject aob = obj as ArrayObject;
  788.                                 if (aob != null)
  789.                                     return aob.length;
  790.                             }
  791.                             else if (prop.DeclaringType == typeof(StringObject)) {
  792.                                 StringObject strob = obj as StringObject;
  793.                                 if (strob != null)
  794.                                     return strob.length;
  795.                             }
  796.                             return JSProperty.GetValue(prop, obj, null);
  797.                         case MemberTypes.Event:
  798.                             return null;
  799.                         case MemberTypes.NestedType:
  800.                             return member;
  801.                     }
  802.                 }
  803.                 catch {
  804.                     if (obj is StringObject)
  805.                         return LateBinding.GetMemberValue(((StringObject)obj).value, name, member, members);
  806.                     if (obj is NumberObject)
  807.                         return LateBinding.GetMemberValue(((NumberObject)obj).value, name, member, members);
  808.                     if (obj is BooleanObject)
  809.                         return LateBinding.GetMemberValue(((BooleanObject)obj).value, name, member, members);
  810.                     if (obj is ArrayWrapper)
  811.                         return LateBinding.GetMemberValue(((ArrayWrapper)obj).value, name, member, members);
  812.                     throw;
  813.                 }
  814.             }
  815.            
  816.             if (members != null && members.Length > 0) {
  817.                 //Special case check for methods on builtin objects
  818.                 if (members.Length == 1 && members[0].MemberType == MemberTypes.Method) {
  819.                     MethodInfo meth = (MethodInfo)members[0];
  820.                     Type dt = meth.DeclaringType;
  821.                     if (dt == typeof(GlobalObject) || (dt != null && dt != typeof(StringObject) && dt != typeof(NumberObject) && dt != typeof(BooleanObject) && dt.IsSubclassOf(typeof(JSObject)))) {
  822.                         //This only happens in fast mode. We could add InitOnly fields to the fast predefined objects and initialize them
  823.                         //with instances of BuiltinFunction objects, in which case we would never get here, but we would like to avoid
  824.                         //the start up cost of allocating these objects, particularly if they end up never being used (the expected common case).
  825.                         return Globals.BuiltinFunctionFor(obj, meth);
  826.                     }
  827.                 }
  828.                
  829.                 return new FunctionWrapper(name, obj, members);
  830.                 //That way function wrappers will preserve object identity
  831.             }
  832.            
  833.             //Check for expando field on ScriptObject, despite the fact that it did not show up in member.
  834.             //This could happen if the object is referred to in a loop and the expando was created after the first time the reference is encountered
  835.             //It is also need to get to the $ properties on RegExp
  836.             if (obj is ScriptObject)
  837.                 return ((ScriptObject)obj).GetMemberValue(name);
  838.            
  839.            
  840.             //A namespace does not implement IReflect and hence cannot deliver a member for the cache. Check it now.
  841.             if (obj is Namespace) {
  842.                 Namespace ns = (Namespace)obj;
  843.                 string qualid = ns.Name + "." + name;
  844.                 Type type = ns.GetType(qualid);
  845.                 if (type != null)
  846.                     return type;
  847.                 return Namespace.GetNamespace(qualid, ns.engine);
  848.             }
  849.            
  850.             //Handle COM objects and IExpando objects.
  851.             IReflect ir = LateBinding.GetIRForObjectThatRequiresInvokeMember(obj, true);
  852.             if (ir != null) {
  853.                 try {
  854.                     const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.OptionalParamBinding | BindingFlags.GetProperty | BindingFlags.GetField;
  855.                     return ir.InvokeMember(name, flags, JSBinder.ob, obj, null, null, null, null);
  856.                 }
  857.                 catch (MissingMemberException) {
  858.                 }
  859.             }
  860.            
  861.             //If we get here the object does not have such a member
  862.             return Missing.Value;
  863.         }
  864.        
  865.         #if !DEBUG
  866.         [DebuggerStepThroughAttribute()]
  867.         [DebuggerHiddenAttribute()]
  868.         #endif
  869.         public object GetNonMissingValue()
  870.         {
  871.             object result = this.GetValue();
  872.             if (result is Missing)
  873.                 return null;
  874.             return result;
  875.         }
  876.        
  877.         #if !DEBUG
  878.         [DebuggerStepThroughAttribute()]
  879.         [DebuggerHiddenAttribute()]
  880.         #endif
  881.         internal object GetValue()
  882.         {
  883.             this.BindToMember();
  884.             //Do a GetMember call and remember the result of the lookup for next time around
  885.             return LateBinding.GetMemberValue(this.obj, this.name, this.last_member, this.last_members);
  886.         }
  887.        
  888.         #if !DEBUG
  889.         [DebuggerStepThroughAttribute()]
  890.         [DebuggerHiddenAttribute()]
  891.         #endif
  892.         public object GetValue2()
  893.         {
  894.             object result = this.GetValue();
  895.             if (result == Missing.Value) {
  896.                 throw new JScriptException(JSError.UndefinedIdentifier, new Context(new DocumentContext("", null), this.name));
  897.             }
  898.             return result;
  899.         }
  900.        
  901.         #if !DEBUG
  902.         [DebuggerStepThroughAttribute()]
  903.         [DebuggerHiddenAttribute()]
  904.         #endif
  905.         static internal object GetValueAtIndex(object obj, ulong index)
  906.         {
  907.             if (obj is ScriptObject)
  908.                 if (index < UInt32.MaxValue)
  909.                     return ((ScriptObject)obj).GetValueAtIndex((uint)index);
  910.                 else
  911.                     return ((ScriptObject)obj).GetMemberValue(index.ToString(CultureInfo.InvariantCulture));
  912.             default_property_case:
  913.             if (obj is IList)
  914.                 checked {
  915.                     return ((IList)obj)[(int)index];
  916.                 }
  917.             if (obj is Array)
  918.                 checked {
  919.                     return ((Array)obj).GetValue((int)index);
  920.                 }
  921.             Type type = obj.GetType();
  922.             if (type.IsCOMObject || obj is IReflect || index > Int32.MaxValue)
  923.                 return LateBinding.GetMemberValue(obj, index.ToString(CultureInfo.InvariantCulture));
  924.            
  925.             //Assume that the object does not itself have a field/property with numerical name.
  926.             //See if the object has a default indexed property, or default property that results in an Array or List and work with that.
  927.             MethodInfo getter = JSBinder.GetDefaultPropertyForArrayIndex(type, (int)index, null, false);
  928.             if (getter != null) {
  929.                 ParameterInfo[] pars = getter.GetParameters();
  930.                 if (pars == null || pars.Length == 0) {
  931.                     obj = getter.Invoke(obj, BindingFlags.SuppressChangeType, null, null, null);
  932.                     goto default_property_case;
  933.                 }
  934.                 else
  935.                     return getter.Invoke(obj, (BindingFlags)0, JSBinder.ob, new object[] {(int)index}, null);
  936.             }
  937.            
  938.             return Missing.Value;
  939.         }
  940.        
  941.         //Do not call this method for arguments that are going out to COM2 objects via interop.
  942.         private static object[] LickArgumentsIntoShape(ParameterInfo[] pars, object[] arguments, Binder binder, CultureInfo culture)
  943.         {
  944.             if (arguments == null)
  945.                 return null;
  946.             int formals = pars.Length;
  947.             if (formals == 0)
  948.                 return null;
  949.             object[] newArgs = arguments;
  950.             int actuals = arguments.Length;
  951.             if (actuals != formals)
  952.                 newArgs = new object[formals];
  953.             int m = formals - 1;
  954.             //Position of last formal param
  955.             int k = actuals < m ? actuals : m;
  956.             //Number of formal params that have corresponding actual arguments, bar the last one, which may be a varArg array.
  957.             //Copy all actual args that match formal param, bar the last one. Change DBNull to null. Coerce actual value to formal param type.
  958.             for (int i = 0; i < k; i++) {
  959.                 object arg = arguments[i];
  960.                 if (arg is DBNull)
  961.                     newArgs[i] = null;
  962.                 else
  963.                     //Outside of the world of OLE Variants, undefined == null == the null pointer.
  964.                     newArgs[i] = binder.ChangeType(arguments[i], pars[i].ParameterType, culture);
  965.             }
  966.             //Supply default values for all formal params, bar the last one, that do not have corresponding actual arguments
  967.             for (int i = k; i < m; i++) {
  968.                 object dv = TypeReferences.GetDefaultParameterValue(pars[i]);
  969.                 if (dv == System.Convert.DBNull)
  970.                     //No default value was specified
  971.                     dv = binder.ChangeType(null, pars[i].ParameterType, culture);
  972.                 //Substitute undefined
  973.                 newArgs[i] = dv;
  974.             }
  975.             //If the last formal param is a vararg param, treat it specially.
  976.             if (CustomAttribute.IsDefined(pars[m], typeof(ParamArrayAttribute), false)) {
  977.                 int numVarArgs = actuals - m;
  978.                 if (numVarArgs < 0)
  979.                     numVarArgs = 0;
  980.                 Type t = pars[m].ParameterType.GetElementType();
  981.                 Array pa = Array.CreateInstance(t, numVarArgs);
  982.                 for (int j = 0; j < numVarArgs; j++)
  983.                     pa.SetValue(binder.ChangeType(arguments[j + m], t, culture), j);
  984.                 newArgs[m] = pa;
  985.             }
  986.             else if (actuals < formals) {
  987.                 object dv = TypeReferences.GetDefaultParameterValue(pars[m]);
  988.                 if (dv == System.Convert.DBNull)
  989.                     //No default value was specified
  990.                     dv = binder.ChangeType(null, pars[m].ParameterType, culture);
  991.                 //Substitute undefined
  992.                 newArgs[m] = dv;
  993.             }
  994.             else
  995.                 newArgs[m] = binder.ChangeType(arguments[m], pars[m].ParameterType, culture);
  996.             return newArgs;
  997.         }
  998.        
  999.         static internal MemberInfo SelectMember(MemberInfo[] mems)
  1000.         {
  1001.             if (mems == null)
  1002.                 return null;
  1003.             MemberInfo result = null;
  1004.             foreach (MemberInfo mem in mems) {
  1005.                 switch (mem.MemberType) {
  1006.                     case MemberTypes.Field:
  1007.                         if (result == null || result.MemberType != MemberTypes.Field)
  1008.                             result = mem;
  1009.                         break;
  1010.                     case MemberTypes.Property:
  1011.                         if (result == null || (result.MemberType != MemberTypes.Field && result.MemberType != MemberTypes.Property)) {
  1012.                             ParameterInfo[] pars = ((PropertyInfo)mem).GetIndexParameters();
  1013.                             if (pars != null && pars.Length == 0)
  1014.                                 result = mem;
  1015.                         }
  1016.                         break;
  1017.                     case MemberTypes.TypeInfo:
  1018.                     case MemberTypes.NestedType:
  1019.                         if (result == null)
  1020.                             result = mem;
  1021.                         break;
  1022.                 }
  1023.             }
  1024.             return result;
  1025.         }
  1026.        
  1027.         #if !DEBUG
  1028.         [DebuggerStepThroughAttribute()]
  1029.         [DebuggerHiddenAttribute()]
  1030.         #endif
  1031.         internal void SetIndexedDefaultPropertyValue(object ob, object[] arguments, object value)
  1032.         {
  1033.             ScriptObject scrob = ob as ScriptObject;
  1034.             if (scrob != null) {
  1035.                 scrob[arguments] = value;
  1036.                 return;
  1037.             }
  1038.            
  1039.             System.Array arr = ob as System.Array;
  1040.             if (arr != null) {
  1041.                 if (arguments.Length != arr.Rank)
  1042.                     throw new JScriptException(JSError.IncorrectNumberOfIndices);
  1043.                 arr.SetValue(value, LateBinding.ToIndices(arguments));
  1044.                 return;
  1045.             }
  1046.            
  1047.             TypeCode tcode = Convert.GetTypeCode(ob);
  1048.             if (Convert.NeedsWrapper(tcode))
  1049.                 return;
  1050.             //senseless assignment to implicit wrapper. Do nothing.
  1051.             IReflect ir = LateBinding.GetIRForObjectThatRequiresInvokeMember(ob, this.checkForDebugger, tcode);
  1052.            
  1053.             if (ir != null) {
  1054.                 try {
  1055.                     int n = arguments.Length + 1;
  1056.                     object[] newargs = new object[n];
  1057.                     ArrayObject.Copy(arguments, 0, newargs, 0, n - 1);
  1058.                     newargs[n - 1] = value;
  1059.                     const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.OptionalParamBinding | BindingFlags.SetProperty | BindingFlags.SetField;
  1060.                     ir.InvokeMember(String.Empty, flags, JSBinder.ob, ob, newargs, null, null, null);
  1061.                     return;
  1062.                 }
  1063.                 catch (MissingMemberException) {
  1064.                     throw new JScriptException(JSError.OLENoPropOrMethod);
  1065.                 }
  1066.             }
  1067.            
  1068.             MemberInfo[] defaultMembers = TypeReflector.GetTypeReflectorFor(ob.GetType()).GetDefaultMembers();
  1069.             if (defaultMembers != null && defaultMembers.Length > 0) {
  1070.                 PropertyInfo prop = JSBinder.SelectProperty(Runtime.TypeRefs, defaultMembers, arguments);
  1071.                 if (prop != null) {
  1072.                     MethodInfo setter = JSProperty.GetSetMethod(prop, false);
  1073.                     if (setter != null) {
  1074.                         arguments = LateBinding.LickArgumentsIntoShape(prop.GetIndexParameters(), arguments, JSBinder.ob, null);
  1075.                         value = Convert.CoerceT(value, prop.PropertyType);
  1076.                         int n = arguments.Length + 1;
  1077.                         object[] newargs = new object[n];
  1078.                         ArrayObject.Copy(arguments, 0, newargs, 0, n - 1);
  1079.                         newargs[n - 1] = value;
  1080.                         setter.Invoke(ob, newargs);
  1081.                         return;
  1082.                     }
  1083.                 }
  1084.             }
  1085.             throw new JScriptException(JSError.OLENoPropOrMethod);
  1086.         }
  1087.        
  1088.         #if !DEBUG
  1089.         [DebuggerStepThroughAttribute()]
  1090.         [DebuggerHiddenAttribute()]
  1091.         #endif
  1092.         internal void SetIndexedPropertyValue(object[] arguments, object value)
  1093.         {
  1094.             if (this.obj == null)
  1095.                 throw new JScriptException(JSError.ObjectExpected);
  1096.             if (this.name == null) {
  1097.                 this.SetIndexedDefaultPropertyValue(this.obj, arguments, value);
  1098.                 return;
  1099.             }
  1100.             MemberInfo member = this.BindToMember();
  1101.             //Do a GetMember call and remember the result of the lookup for next time around
  1102.             //If the object has any members called this.name, we try to find a suitable indexed property.
  1103.             if (this.last_members != null && this.last_members.Length > 0) {
  1104.                 PropertyInfo prop = JSBinder.SelectProperty(Runtime.TypeRefs, this.last_members, arguments);
  1105.                 if (prop != null) {
  1106.                     if (arguments.Length > 0 && prop.GetIndexParameters().Length == 0) {
  1107.                         //Might be a parameterless property that results in an object that has a indexed property that can be assigned to
  1108.                         MethodInfo getter = JSProperty.GetGetMethod(prop, false);
  1109.                         if (getter != null) {
  1110.                             LateBinding.SetIndexedPropertyValueStatic(getter.Invoke(this.obj, null), arguments, value);
  1111.                             return;
  1112.                         }
  1113.                     }
  1114.                     arguments = LateBinding.LickArgumentsIntoShape(prop.GetIndexParameters(), arguments, JSBinder.ob, null);
  1115.                     value = Convert.CoerceT(value, prop.PropertyType);
  1116.                     JSProperty.SetValue(prop, this.obj, value, arguments);
  1117.                     return;
  1118.                 }
  1119.             }
  1120.            
  1121.             TypeCode tcode = Convert.GetTypeCode(obj);
  1122.             if (Convert.NeedsWrapper(tcode))
  1123.                 return;
  1124.             //senseless assignment to implicit wrapper. Do nothing.
  1125.             IReflect ir = LateBinding.GetIRForObjectThatRequiresInvokeMember(obj, this.checkForDebugger, tcode);
  1126.             if (ir != null) {
  1127.                 int n = arguments.Length + 1;
  1128.                 object[] newargs = new object[n];
  1129.                 ArrayObject.Copy(arguments, 0, newargs, 0, n - 1);
  1130.                 newargs[n - 1] = value;
  1131.                 const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.OptionalParamBinding | BindingFlags.SetProperty | BindingFlags.SetField;
  1132.                 ir.InvokeMember(this.name, flags, JSBinder.ob, this.obj, newargs, null, null, null);
  1133.                 return;
  1134.             }
  1135.            
  1136.             //<ob.foo> might be an object that has a default indexed property
  1137.             object ob = this.GetValue();
  1138.             if (ob != null && !(ob is Missing)) {
  1139.                 this.SetIndexedDefaultPropertyValue(ob, arguments, value);
  1140.                 return;
  1141.             }
  1142.            
  1143.             //Give up
  1144.             throw new JScriptException(JSError.OLENoPropOrMethod);
  1145.         }
  1146.        
  1147.         #if !DEBUG
  1148.         [DebuggerStepThroughAttribute()]
  1149.         [DebuggerHiddenAttribute()]
  1150.         #endif
  1151.         public static void SetIndexedPropertyValueStatic(object obj, object[] arguments, object value)
  1152.         {
  1153.             if (obj == null)
  1154.                 throw new JScriptException(JSError.ObjectExpected);
  1155.            
  1156.             ScriptObject scrob = obj as ScriptObject;
  1157.             if (scrob != null) {
  1158.                 scrob[arguments] = value;
  1159.                 return;
  1160.             }
  1161.            
  1162.             Array arr = obj as Array;
  1163.             if (arr != null) {
  1164.                 if (arguments.Length != arr.Rank)
  1165.                     throw new JScriptException(JSError.IncorrectNumberOfIndices);
  1166.                 arr.SetValue(value, LateBinding.ToIndices(arguments));
  1167.                 return;
  1168.             }
  1169.            
  1170.             TypeCode tcode = Convert.GetTypeCode(obj);
  1171.             if (Convert.NeedsWrapper(tcode))
  1172.                 return;
  1173.             //senseless assignment to implicit wrapper. Do nothing.
  1174.             IReflect ir = LateBinding.GetIRForObjectThatRequiresInvokeMember(obj, true, tcode);
  1175.             //Either called from IL, or on an type object
  1176.             if (ir != null) {
  1177.                 //Legacy behavior is to convert the last argument to a string and treat it as the name of the property being set
  1178.                 string name = String.Empty;
  1179.                 int n = arguments.Length;
  1180.                 if (n > 0)
  1181.                     name = Convert.ToString(arguments[n - 1]);
  1182.                 const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.OptionalParamBinding | BindingFlags.SetProperty | BindingFlags.SetField;
  1183.                 ir.InvokeMember(name, flags, JSBinder.ob, obj, new object[] {value}, null, null, null);
  1184.                 return;
  1185.             }
  1186.            
  1187.             MemberInfo[] defaultMembers = TypeReflector.GetTypeReflectorFor(obj.GetType()).GetDefaultMembers();
  1188.             if (defaultMembers != null && defaultMembers.Length > 0) {
  1189.                 PropertyInfo prop = JSBinder.SelectProperty(Runtime.TypeRefs, defaultMembers, arguments);
  1190.                 if (prop != null) {
  1191.                     MethodInfo setter = JSProperty.GetSetMethod(prop, false);
  1192.                     if (setter != null) {
  1193.                         arguments = LateBinding.LickArgumentsIntoShape(prop.GetIndexParameters(), arguments, JSBinder.ob, null);
  1194.                         value = Convert.CoerceT(value, prop.PropertyType);
  1195.                         int n = arguments.Length + 1;
  1196.                         object[] newargs = new object[n];
  1197.                         ArrayObject.Copy(arguments, 0, newargs, 0, n - 1);
  1198.                         newargs[n - 1] = value;
  1199.                         setter.Invoke(obj, newargs);
  1200.                         return;
  1201.                     }
  1202.                 }
  1203.             }
  1204.            
  1205.             throw new JScriptException(JSError.OLENoPropOrMethod);
  1206.         }
  1207.        
  1208.         #if !DEBUG
  1209.         [DebuggerStepThroughAttribute()]
  1210.         [DebuggerHiddenAttribute()]
  1211.         #endif
  1212.         private static void SetMember(object obj, object value, MemberInfo member)
  1213.         {
  1214.             switch (member.MemberType) {
  1215.                 case MemberTypes.Field:
  1216.                     FieldInfo field = (FieldInfo)member;
  1217.                     if (!field.IsLiteral && !field.IsInitOnly) {
  1218.                         if (field is JSField)
  1219.                             field.SetValue(obj, value);
  1220.                         else
  1221.                             field.SetValue(obj, Convert.CoerceT(value, field.FieldType), BindingFlags.SuppressChangeType, null, null);
  1222.                     }
  1223.                     return;
  1224.                 case MemberTypes.Property:
  1225.                     PropertyInfo property = (PropertyInfo)member;
  1226.                     if (property is JSProperty || property is JSWrappedProperty) {
  1227.                         property.SetValue(obj, value, null);
  1228.                         return;
  1229.                     }
  1230.                     MethodInfo setMeth = JSProperty.GetSetMethod(property, false);
  1231.                     if (setMeth != null)
  1232.                         try {
  1233.                             setMeth.Invoke(obj, BindingFlags.SuppressChangeType, null, new object[] {Convert.CoerceT(value, property.PropertyType)}, null);
  1234.                         }
  1235.                         catch (TargetInvocationException e) {
  1236.                             throw e.InnerException;
  1237.                         }
  1238.                     return;
  1239.             }
  1240.         }
  1241.        
  1242.         #if !DEBUG
  1243.         [DebuggerStepThroughAttribute()]
  1244.         [DebuggerHiddenAttribute()]
  1245.         #endif
  1246.         static internal void SetMemberValue(object obj, string name, object value)
  1247.         {
  1248.             if (obj is ScriptObject) {
  1249.                 ((ScriptObject)obj).SetMemberValue(name, value);
  1250.                 return;
  1251.             }
  1252.             LateBinding lb = new LateBinding(name, obj);
  1253.             lb.SetValue(value);
  1254.         }
  1255.        
  1256.         #if !DEBUG
  1257.         [DebuggerStepThroughAttribute()]
  1258.         [DebuggerHiddenAttribute()]
  1259.         #endif
  1260.         static internal void SetMemberValue(object obj, string name, object value, MemberInfo member, MemberInfo[] members)
  1261.         {
  1262.             if (member != null) {
  1263.                 LateBinding.SetMember(obj, value, member);
  1264.                 return;
  1265.             }
  1266.             if (obj is ScriptObject) {
  1267.                 //Create an expando the fast way. Also needed for $ properties on RegExp
  1268.                 ((ScriptObject)obj).SetMemberValue(name, value);
  1269.                 return;
  1270.             }
  1271.            
  1272.             TypeCode tcode = Convert.GetTypeCode(obj);
  1273.             if (Convert.NeedsWrapper(tcode))
  1274.                 return;
  1275.             //senseless assignment to implicit wrapper. Do nothing.
  1276.             IReflect ir = LateBinding.GetIRForObjectThatRequiresInvokeMember(obj, true, tcode);
  1277.             if (ir != null) {
  1278.                 try {
  1279.                     object[] args = new object[] {value};
  1280.                     IConvertible iconv = value as IConvertible;
  1281.                    
  1282.                     //BindingFlags.SetProperty makes interop call with DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF .
  1283.                     BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.OptionalParamBinding | BindingFlags.SetProperty | BindingFlags.SetField;
  1284.                     ir.InvokeMember(name, flags, JSBinder.ob, obj, args, null, null, null);
  1285.                     return;
  1286.                 }
  1287.                 catch (MissingMemberException) {
  1288.                 }
  1289.             }
  1290.            
  1291.             if (obj is IExpando) {
  1292.                 //Create an expando the slow way
  1293.                 PropertyInfo prop = ((IExpando)obj).AddProperty(name);
  1294.                 if (prop != null)
  1295.                     prop.SetValue(obj, value, null);
  1296.                 else {
  1297.                     FieldInfo field = ((IExpando)obj).AddField(name);
  1298.                     if (field != null) {
  1299.                         field.SetValue(obj, value);
  1300.                     }
  1301.                 }
  1302.                 return;
  1303.             }
  1304.         }
  1305.        
  1306.         #if !DEBUG
  1307.         [DebuggerStepThroughAttribute()]
  1308.         [DebuggerHiddenAttribute()]
  1309.         #endif
  1310.         static internal void SetValueAtIndex(object obj, ulong index, object value)
  1311.         {
  1312.             if (obj is ScriptObject) {
  1313.                 if (index < UInt32.MaxValue)
  1314.                     ((ScriptObject)obj).SetValueAtIndex((uint)index, value);
  1315.                 else
  1316.                     ((ScriptObject)obj).SetMemberValue(index.ToString(CultureInfo.InvariantCulture), value);
  1317.                 return;
  1318.             }
  1319.             default_property_case:
  1320.             if (obj is IList) {
  1321.                 IList list = (IList)obj;
  1322.                 if (index < (ulong)list.Count)
  1323.                     list[(int)index] = value;
  1324.                 else
  1325.                     list.Insert((int)index, value);
  1326.                 return;
  1327.             }
  1328.             if (obj is Array) {
  1329.                 checked {
  1330.                     ((Array)obj).SetValue(Convert.CoerceT(value, obj.GetType().GetElementType()), (int)index);
  1331.                 }
  1332.                 return;
  1333.             }
  1334.             Type type = obj.GetType();
  1335.             if (type.IsCOMObject || obj is IReflect || index > Int32.MaxValue) {
  1336.                 LateBinding.SetMemberValue(obj, index.ToString(CultureInfo.InvariantCulture), value);
  1337.                 return;
  1338.             }
  1339.            
  1340.             //Assume that the object does not itself have a field/property with numerical name.
  1341.             //See if the object has a default indexed property, or default property that results in an Array or List and work with that.
  1342.             MethodInfo setter = JSBinder.GetDefaultPropertyForArrayIndex(type, (int)index, null, true);
  1343.             if (setter != null) {
  1344.                 ParameterInfo[] pars = setter.GetParameters();
  1345.                 if (pars == null || pars.Length == 0) {
  1346.                     obj = setter.Invoke(obj, BindingFlags.SuppressChangeType, null, null, null);
  1347.                     goto default_property_case;
  1348.                 }
  1349.                 else
  1350.                     setter.Invoke(obj, (BindingFlags)0, JSBinder.ob, new object[] {(int)index, value}, null);
  1351.             }
  1352.         }
  1353.        
  1354.         #if !DEBUG
  1355.         [DebuggerStepThroughAttribute()]
  1356.         [DebuggerHiddenAttribute()]
  1357.         #endif
  1358.         public void SetValue(object value)
  1359.         {
  1360.             this.BindToMember();
  1361.             //Do a GetMember call and remember the result of the lookup for next time around
  1362.             LateBinding.SetMemberValue(this.obj, this.name, value, this.last_member, this.last_members);
  1363.         }
  1364.        
  1365.         static internal void SwapValues(object obj, uint left, uint right)
  1366.         {
  1367.             if (obj is JSObject) {
  1368.                 ((JSObject)obj).SwapValues(left, right);
  1369.                 return;
  1370.             }
  1371.             if (obj is IList) {
  1372.                 IList list = (IList)obj;
  1373.                 object temp = list[(int)left];
  1374.                 list[(int)left] = list[(int)right];
  1375.                 list[(int)right] = temp;
  1376.                 return;
  1377.             }
  1378.             if (obj is Array) {
  1379.                 Array arr = (Array)obj;
  1380.                 object temp = arr.GetValue((int)left);
  1381.                 arr.SetValue(arr.GetValue((int)right), (int)left);
  1382.                 arr.SetValue(temp, (int)right);
  1383.                 return;
  1384.             }
  1385.             if (obj is IExpando) {
  1386.                 string left_name = System.Convert.ToString(left, CultureInfo.InvariantCulture);
  1387.                 string right_name = System.Convert.ToString(right, CultureInfo.InvariantCulture);
  1388.                 IExpando eob = (IExpando)obj;
  1389.                 FieldInfo left_field = eob.GetField(left_name, BindingFlags.Instance | BindingFlags.Public);
  1390.                 FieldInfo right_field = eob.GetField(right_name, BindingFlags.Instance | BindingFlags.Public);
  1391.                 if (left_field == null)
  1392.                     if (right_field == null)
  1393.                         return;
  1394.                     else
  1395.                         try {
  1396.                             left_field = eob.AddField(left_name);
  1397.                             left_field.SetValue(obj, right_field.GetValue(obj));
  1398.                             eob.RemoveMember(right_field);
  1399.                         }
  1400.                         catch {
  1401.                             throw new JScriptException(JSError.ActionNotSupported);
  1402.                         }
  1403.                 else if (right_field == null)
  1404.                     try {
  1405.                         right_field = eob.AddField(right_name);
  1406.                         right_field.SetValue(obj, left_field.GetValue(obj));
  1407.                         eob.RemoveMember(left_field);
  1408.                     }
  1409.                     catch {
  1410.                         throw new JScriptException(JSError.ActionNotSupported);
  1411.                     }
  1412.                 object temp = left_field.GetValue(obj);
  1413.                 left_field.SetValue(obj, right_field.GetValue(obj));
  1414.                 right_field.SetValue(obj, temp);
  1415.                 return;
  1416.             }
  1417.             object lval = LateBinding.GetValueAtIndex(obj, left);
  1418.             object rval = LateBinding.GetValueAtIndex(obj, right);
  1419.             if (lval is Missing)
  1420.                 LateBinding.DeleteValueAtIndex(obj, right);
  1421.             else
  1422.                 LateBinding.SetValueAtIndex(obj, right, lval);
  1423.             if (rval is Missing)
  1424.                 LateBinding.DeleteValueAtIndex(obj, left);
  1425.             else
  1426.                 LateBinding.SetValueAtIndex(obj, left, rval);
  1427.         }
  1428.        
  1429.         private static int[] ToIndices(object[] arguments)
  1430.         {
  1431.             int n = arguments.Length;
  1432.             int[] result = new int[n];
  1433.             for (int i = 0; i < n; i++)
  1434.                 result[i] = Convert.ToInt32(arguments[i]);
  1435.             return result;
  1436.         }
  1437.     }
  1438. }

Developer Fusion