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

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. namespace Microsoft.JScript
  16. {
  17.    
  18.     using Microsoft.JScript.Vsa;
  19.     using System;
  20.     using System.Reflection;
  21.     using System.Reflection.Emit;
  22.     using System.Globalization;
  23.     using System.Diagnostics;
  24.    
  25.     internal sealed class JSNativeMethod : JSMethod
  26.     {
  27.         private MethodInfo method;
  28.         private ParameterInfo[] formalParams;
  29.         private bool hasThis;
  30.         private bool hasVarargs;
  31.         private bool hasEngine;
  32.         private VsaEngine engine;
  33.        
  34.         internal JSNativeMethod(MethodInfo method, object obj, VsaEngine engine) : base(obj)
  35.         {
  36.             this.method = method;
  37.             this.formalParams = method.GetParameters();
  38.             object[] attrs = CustomAttribute.GetCustomAttributes(method, typeof(JSFunctionAttribute), false);
  39.             JSFunctionAttribute attr = attrs.Length > 0 ? (JSFunctionAttribute)attrs[0] : new JSFunctionAttribute((JSFunctionAttributeEnum)0);
  40.             JSFunctionAttributeEnum attrVal = attr.attributeValue;
  41.             if ((attrVal & JSFunctionAttributeEnum.HasThisObject) != 0)
  42.                 this.hasThis = true;
  43.             if ((attrVal & JSFunctionAttributeEnum.HasEngine) != 0)
  44.                 this.hasEngine = true;
  45.             if ((attrVal & JSFunctionAttributeEnum.HasVarArgs) != 0)
  46.                 this.hasVarargs = true;
  47.             this.engine = engine;
  48.         }
  49.        
  50.         internal override object Construct(object[] args)
  51.         {
  52.             throw new JScriptException(JSError.NoConstructor);
  53.         }
  54.        
  55.         public override MethodAttributes Attributes {
  56.             get { return this.method.Attributes; }
  57.         }
  58.        
  59.         public override Type DeclaringType {
  60.             get { return this.method.DeclaringType; }
  61.         }
  62.        
  63.         public override ParameterInfo[] GetParameters()
  64.         {
  65.             return this.formalParams;
  66.         }
  67.        
  68.         internal override MethodInfo GetMethodInfo(CompilerGlobals compilerGlobals)
  69.         {
  70.             return this.method;
  71.         }
  72.        
  73.         #if !DEBUG
  74.         [DebuggerStepThroughAttribute()]
  75.         [DebuggerHiddenAttribute()]
  76.         #endif
  77.         internal override object Invoke(object obj, object thisob, BindingFlags options, Binder binder, object[] parameters, CultureInfo culture)
  78.         {
  79.             int n = this.formalParams.Length;
  80.             int pn = (parameters != null ? parameters.Length : 0);
  81.             if (!this.hasThis && !this.hasVarargs && n == pn)
  82.                 if (binder != null)
  83.                     return TypeReferences.ToExecutionContext(this.method).Invoke(this.obj, BindingFlags.SuppressChangeType, null, this.ConvertParams(0, parameters, binder, culture), null);
  84.                 else
  85.                     return TypeReferences.ToExecutionContext(this.method).Invoke(this.obj, options, binder, parameters, culture);
  86.             int offset = (this.hasThis ? 1 : 0) + (this.hasEngine ? 1 : 0);
  87.             object[] arguments = new object[n];
  88.             if (this.hasThis) {
  89.                 arguments[0] = thisob;
  90.                 if (this.hasEngine)
  91.                     arguments[1] = this.engine;
  92.             }
  93.             else if (this.hasEngine)
  94.                 arguments[0] = this.engine;
  95.             if (this.hasVarargs) {
  96.                 if (n == offset + 1)
  97.                     arguments[offset] = parameters;
  98.                 //No params other than the vararg array
  99.                 else {
  100.                     //Some of the values in parameters must be passed separately from the vararg array
  101.                     int argsToCopy = n - 1 - offset;
  102.                     //The number of separate arguments
  103.                     if (pn > argsToCopy) {
  104.                         ArrayObject.Copy(parameters, 0, arguments, offset, argsToCopy);
  105.                         int vn = pn - argsToCopy;
  106.                         object[] varargs = new object[vn];
  107.                         ArrayObject.Copy(parameters, argsToCopy, varargs, 0, vn);
  108.                         arguments[n - 1] = varargs;
  109.                     }
  110.                     else {
  111.                         ArrayObject.Copy(parameters, 0, arguments, offset, pn);
  112.                         for (int i = pn; i < argsToCopy; i++)
  113.                             arguments[i + offset] = Missing.Value;
  114.                         arguments[n - 1] = new object[0];
  115.                     }
  116.                 }
  117.             }
  118.             else {
  119.                 if (parameters != null) {
  120.                     if (n - offset < pn)
  121.                         ArrayObject.Copy(parameters, 0, arguments, offset, n - offset);
  122.                     else
  123.                         ArrayObject.Copy(parameters, 0, arguments, offset, pn);
  124.                 }
  125.                 if (n - offset > pn) {
  126.                     for (int i = pn + offset; i < n; i++)
  127.                         if (i == n - 1 && this.formalParams[i].ParameterType.IsArray && CustomAttribute.IsDefined(this.formalParams[i], typeof(ParamArrayAttribute), true))
  128.                             arguments[i] = System.Array.CreateInstance(this.formalParams[i].ParameterType.GetElementType(), 0);
  129.                         else
  130.                             arguments[i] = Missing.Value;
  131.                 }
  132.             }
  133.             if (binder != null)
  134.                 return TypeReferences.ToExecutionContext(this.method).Invoke(this.obj, BindingFlags.SuppressChangeType, null, this.ConvertParams(offset, arguments, binder, culture), null);
  135.             else
  136.                 return TypeReferences.ToExecutionContext(this.method).Invoke(this.obj, options, binder, arguments, culture);
  137.         }
  138.        
  139.         private object[] ConvertParams(int offset, object[] parameters, Binder binder, CultureInfo culture)
  140.         {
  141.             int n = this.formalParams.Length;
  142.             if (this.hasVarargs)
  143.                 n--;
  144.             for (int i = offset; i < n; i++) {
  145.                 Type fpt = this.formalParams[i].ParameterType;
  146.                 if (fpt != Typeob.Object)
  147.                     parameters[i] = binder.ChangeType(parameters[i], fpt, culture);
  148.             }
  149.             return parameters;
  150.         }
  151.        
  152.         public override string Name {
  153.             get { return this.method.Name; }
  154.         }
  155.        
  156.         public override Type ReturnType {
  157.             get { return this.method.ReturnType; }
  158.         }
  159.     }
  160.    
  161.    
  162. }

Developer Fusion