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

  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.     using System.Runtime.InteropServices.Expando;
  24.    
  25.     internal sealed class Member : Binding
  26.     {
  27.         private bool fast;
  28.         private bool isImplicitWrapper;
  29.         private LateBinding lateBinding;
  30.         private Context memberNameContext;
  31.         internal AST rootObject;
  32.         private IReflect rootObjectInferredType;
  33.         //Keeps track of the type inference that was used to do a binding. A binding is invalid if this changes.
  34.         private LocalBuilder refLoc;
  35.         private LocalBuilder temp;
  36.        
  37.         internal Member(Context context, AST rootObject, AST memberName) : base(context, memberName.context.GetCode())
  38.         {
  39.             this.fast = this.Engine.doFast;
  40.             this.isImplicitWrapper = false;
  41.             this.isNonVirtual = rootObject is ThisLiteral && ((ThisLiteral)rootObject).isSuper;
  42.             this.lateBinding = null;
  43.             this.memberNameContext = memberName.context;
  44.             this.rootObject = rootObject;
  45.             this.rootObjectInferredType = null;
  46.             this.refLoc = null;
  47.             this.temp = null;
  48.         }
  49.        
  50.         private void BindName(JSField inferenceTarget)
  51.         {
  52.             MemberInfo[] members = null;
  53.             this.rootObject = this.rootObject.PartiallyEvaluate();
  54.             IReflect obType = this.rootObjectInferredType = this.rootObject.InferType(inferenceTarget);
  55.             if (this.rootObject is ConstantWrapper) {
  56.                 object ob = Convert.ToObject2(this.rootObject.Evaluate(), this.Engine);
  57.                 if (ob == null) {
  58.                     this.rootObject.context.HandleError(JSError.ObjectExpected);
  59.                     return;
  60.                 }
  61.                 ClassScope csc = ob as ClassScope;
  62.                 Type t = ob as Type;
  63.                 if (csc != null || t != null) {
  64.                     //object is a type. Look for static members on the type only. If none are found, look for instance members on type Type.
  65.                     if (csc != null)
  66.                         this.members = members = csc.GetMember(this.name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly);
  67.                     else
  68.                         this.members = members = t.GetMember(this.name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly);
  69.                     if (members.Length > 0)
  70.                         return;
  71.                     //found a binding
  72.                     //Look for instance members on type Type
  73.                     this.members = members = Typeob.Type.GetMember(this.name, BindingFlags.Public | BindingFlags.Instance);
  74.                     return;
  75.                 }
  76.                 Namespace ns = ob as Namespace;
  77.                 if (ns != null) {
  78.                     string fullname = ns.Name + "." + this.name;
  79.                     csc = this.Engine.GetClass(fullname);
  80.                     if (csc != null) {
  81.                         FieldAttributes attrs = FieldAttributes.Literal;
  82.                         if ((csc.owner.attributes & TypeAttributes.Public) == 0)
  83.                             attrs |= FieldAttributes.Private;
  84.                         this.members = new MemberInfo[] {new JSGlobalField(null, this.name, csc, attrs)};
  85.                         return;
  86.                     }
  87.                     else {
  88.                         t = this.Engine.GetType(fullname);
  89.                         if (t != null) {
  90.                             this.members = new MemberInfo[] {t};
  91.                             return;
  92.                         }
  93.                     }
  94.                 }
  95.                 else if (ob is MathObject || ob is ScriptFunction && !(ob is FunctionObject))
  96.                     //It is a built in constructor function
  97.                     obType = (IReflect)ob;
  98.             }
  99.             obType = this.ProvideWrapperForPrototypeProperties(obType);
  100.            
  101.             //Give up and go late bound if not enough is known about the object at compile time.
  102.             if (obType == Typeob.Object && !this.isNonVirtual) {
  103.                 //The latter provides for super in classes that extend System.Object
  104.                 this.members = new MemberInfo[0];
  105.                 return;
  106.             }
  107.            
  108.             Type ty = obType as Type;
  109.             //Interfaces are weird, call a helper
  110.             if (ty != null && ty.IsInterface) {
  111.                 this.members = JSBinder.GetInterfaceMembers(this.name, ty);
  112.                 return;
  113.             }
  114.             ClassScope cs = obType as ClassScope;
  115.             if (cs != null && cs.owner.isInterface) {
  116.                 this.members = cs.owner.GetInterfaceMember(this.name);
  117.                 return;
  118.             }
  119.            
  120.             //Now run up the inheritance chain until a member is found
  121.             while (obType != null) {
  122.                 cs = obType as ClassScope;
  123.                 if (cs != null) {
  124.                     //The FlattenHierachy flag here tells ClassScope to add in any overloads found on base classes
  125.                     members = this.members = obType.GetMember(this.name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.FlattenHierarchy);
  126.                     if (members.Length > 0)
  127.                         return;
  128.                     obType = cs.GetSuperType();
  129.                     continue;
  130.                 }
  131.                 ty = obType as Type;
  132.                 if (ty == null) {
  133.                     //Dealing with the global scope via the this literal or with a built in object in fast mode
  134.                     this.members = obType.GetMember(this.name, BindingFlags.Public | BindingFlags.Instance);
  135.                     return;
  136.                 }
  137.                 members = this.members = ty.GetMember(this.name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
  138.                 if (members.Length > 0) {
  139.                     MemberInfo mem = LateBinding.SelectMember(members);
  140.                     if (mem == null) {
  141.                         //Found a method or methods. Need to add any overloads found in base classes.
  142.                         //Do another lookup, this time with the DeclaredOnly flag cleared and asking only for methods
  143.                         members = this.members = ty.GetMember(this.name, MemberTypes.Method, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
  144.                         if (members.Length == 0)
  145.                             //Dealing with an indexed property, ask again
  146.                             this.members = ty.GetMember(this.name, MemberTypes.Property, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
  147.                     }
  148.                     return;
  149.                 }
  150.                 obType = ty.BaseType;
  151.             }
  152.         }
  153.        
  154.         internal override object Evaluate()
  155.         {
  156.             object value = base.Evaluate();
  157.             if (value is Missing)
  158.                 value = null;
  159.             return value;
  160.         }
  161.        
  162.         internal override LateBinding EvaluateAsLateBinding()
  163.         {
  164.             LateBinding lb = this.lateBinding;
  165.             if (lb == null) {
  166.                 if (this.member != null && !this.rootObjectInferredType.Equals(this.rootObject.InferType(null)))
  167.                     this.InvalidateBinding();
  168.                 this.lateBinding = lb = new LateBinding(this.name, null, VsaEngine.executeForJSEE);
  169.                 lb.last_member = this.member;
  170.             }
  171.             object val = this.rootObject.Evaluate();
  172.             try {
  173.                 lb.obj = val = Convert.ToObject(val, this.Engine);
  174.                 if (this.defaultMember == null && this.member != null)
  175.                     lb.last_object = val;
  176.             }
  177.             catch (JScriptException e) {
  178.                 if (e.context == null) {
  179.                     e.context = this.rootObject.context;
  180.                 }
  181.                 throw e;
  182.             }
  183.             return lb;
  184.         }
  185.        
  186.         internal object EvaluateAsType()
  187.         {
  188.             WrappedNamespace ns = this.rootObject.EvaluateAsWrappedNamespace(false);
  189.             object result = ns.GetMemberValue(this.name);
  190.             if (result != null && !(result is Missing))
  191.                 return result;
  192.             object ob = null;
  193.             Member root = this.rootObject as Member;
  194.             if (root == null) {
  195.                 Lookup lookup = this.rootObject as Lookup;
  196.                 if (lookup == null)
  197.                     return null;
  198.                 ob = lookup.PartiallyEvaluate();
  199.                 ConstantWrapper cw = ob as ConstantWrapper;
  200.                 if (cw != null)
  201.                     ob = cw.value;
  202.                 else {
  203.                     JSGlobalField f = lookup.member as JSGlobalField;
  204.                     if (f != null && f.IsLiteral)
  205.                         ob = f.value;
  206.                     else
  207.                         return null;
  208.                 }
  209.             }
  210.             else
  211.                 ob = root.EvaluateAsType();
  212.             ClassScope csc = ob as ClassScope;
  213.             if (csc != null) {
  214.                 MemberInfo[] members = csc.GetMember(this.name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
  215.                 if (members.Length == 0)
  216.                     return null;
  217.                 JSMemberField field = members[0] as JSMemberField;
  218.                 if (field == null || !field.IsLiteral || !(field.value is ClassScope) || !field.IsPublic && !field.IsAccessibleFrom(this.Engine.ScriptObjectStackTop()))
  219.                     return null;
  220.                 return field.value;
  221.             }
  222.             Type t = ob as Type;
  223.             if (t != null)
  224.                 return t.GetNestedType(this.name);
  225.             return null;
  226.         }
  227.        
  228.         internal override WrappedNamespace EvaluateAsWrappedNamespace(bool giveErrorIfNameInUse)
  229.         {
  230.             WrappedNamespace root = this.rootObject.EvaluateAsWrappedNamespace(giveErrorIfNameInUse);
  231.             string name = this.name;
  232.             root.AddFieldOrUseExistingField(name, Namespace.GetNamespace(root.ToString() + "." + name, this.Engine), FieldAttributes.Literal);
  233.             return new WrappedNamespace(root.ToString() + "." + name, this.Engine);
  234.         }
  235.        
  236.         protected override object GetObject()
  237.         {
  238.             return Convert.ToObject(this.rootObject.Evaluate(), this.Engine);
  239.         }
  240.        
  241.         protected override void HandleNoSuchMemberError()
  242.         {
  243.             IReflect obType = this.rootObject.InferType(null);
  244.             object obVal = null;
  245.            
  246.             if (this.rootObject is ConstantWrapper)
  247.                 obVal = this.rootObject.Evaluate();
  248.            
  249.             if ((obType == Typeob.Object && !this.isNonVirtual) || (obType is JSObject && !((JSObject)obType).noExpando) || (obType is GlobalScope && !((GlobalScope)obType).isKnownAtCompileTime))
  250.                 return;
  251.             if (obType is Type) {
  252.                 Type t = (Type)obType;
  253.                 if (Typeob.ScriptFunction.IsAssignableFrom(t) || t == Typeob.MathObject) {
  254.                     //dealing with an assigment to a member of a builtin constructor function.
  255.                     Debug.Assert(this.fast);
  256.                     this.memberNameContext.HandleError(JSError.OLENoPropOrMethod);
  257.                     return;
  258.                 }
  259.                 if (Typeob.IExpando.IsAssignableFrom(t))
  260.                     return;
  261.                 if (!this.fast)
  262.                     if (t == Typeob.Boolean || t == Typeob.String || Convert.IsPrimitiveNumericType(t))
  263.                         return;
  264.                
  265.                 // Check to see if we couldn't get the member because it is non-static.
  266.                 if (obVal is ClassScope) {
  267.                     MemberInfo[] members = ((ClassScope)obVal).GetMember(this.name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
  268.                     if (members.Length > 0) {
  269.                         this.memberNameContext.HandleError(JSError.NonStaticWithTypeName);
  270.                         return;
  271.                     }
  272.                 }
  273.             }
  274.            
  275.             if (obVal is FunctionObject) {
  276.                 this.rootObject = new ConstantWrapper(((FunctionObject)obVal).name, this.rootObject.context);
  277.                 this.memberNameContext.HandleError(JSError.OLENoPropOrMethod);
  278.                 return;
  279.             }
  280.            
  281.             // Check to see if we couldn't get the member because it is static.
  282.             if (obType is ClassScope) {
  283.                 MemberInfo[] members = ((ClassScope)obType).GetMember(this.name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
  284.                 if (members.Length > 0) {
  285.                     this.memberNameContext.HandleError(JSError.StaticRequiresTypeName);
  286.                     return;
  287.                 }
  288.             }
  289.            
  290.             if (obVal is Type)
  291.                 this.memberNameContext.HandleError(JSError.NoSuchStaticMember, Convert.ToTypeName((Type)obVal));
  292.             else if (obVal is ClassScope)
  293.                 this.memberNameContext.HandleError(JSError.NoSuchStaticMember, Convert.ToTypeName((ClassScope)obVal));
  294.             else if (obVal is Namespace)
  295.                 this.memberNameContext.HandleError(JSError.NoSuchType, ((Namespace)obVal).Name + "." + this.name);
  296.             else {
  297.                 if (obType == FunctionPrototype.ob && this.rootObject is Binding && ((Binding)this.rootObject).member is JSVariableField && ((JSVariableField)((Binding)this.rootObject).member).value is FunctionObject)
  298.                     return;
  299.                 this.memberNameContext.HandleError(JSError.NoSuchMember, Convert.ToTypeName(obType));
  300.             }
  301.         }
  302.        
  303.         internal override IReflect InferType(JSField inference_target)
  304.         {
  305.             if (this.members == null) {
  306.                 this.BindName(inference_target);
  307.             }
  308.             else {
  309.                 if (!this.rootObjectInferredType.Equals(this.rootObject.InferType(inference_target)))
  310.                     this.InvalidateBinding();
  311.             }
  312.             return base.InferType(null);
  313.         }
  314.        
  315.         internal override IReflect InferTypeOfCall(JSField inference_target, bool isConstructor)
  316.         {
  317.             if (!this.rootObjectInferredType.Equals(this.rootObject.InferType(inference_target)))
  318.                 this.InvalidateBinding();
  319.             return base.InferTypeOfCall(null, isConstructor);
  320.         }
  321.        
  322.         internal override AST PartiallyEvaluate()
  323.         {
  324.             this.BindName(null);
  325.             if (this.members == null || this.members.Length == 0) {
  326.                 //if this rootObject is a constant and its value is a namespace, turn this node also into a namespace constant
  327.                 if (this.rootObject is ConstantWrapper) {
  328.                     object val = this.rootObject.Evaluate();
  329.                     if (val is Namespace) {
  330.                         return new ConstantWrapper(Namespace.GetNamespace(((Namespace)val).Name + "." + this.name, this.Engine), this.context);
  331.                     }
  332.                 }
  333.                 this.HandleNoSuchMemberError();
  334.                 return this;
  335.             }
  336.             this.ResolveRHValue();
  337.             if (this.member is FieldInfo && ((FieldInfo)this.member).IsLiteral) {
  338.                 object val = this.member is JSVariableField ? ((JSVariableField)this.member).value : TypeReferences.GetConstantValue((FieldInfo)this.member);
  339.                 if (val is AST) {
  340.                     AST pval = ((AST)val).PartiallyEvaluate();
  341.                     if (pval is ConstantWrapper)
  342.                         return pval;
  343.                     val = null;
  344.                 }
  345.                 if (!(val is FunctionObject) && (!(val is ClassScope) || ((ClassScope)val).owner.IsStatic))
  346.                     return new ConstantWrapper(val, this.context);
  347.             }
  348.             else if (this.member is Type)
  349.                 return new ConstantWrapper(this.member, this.context);
  350.             return this;
  351.         }
  352.        
  353.         internal override AST PartiallyEvaluateAsCallable()
  354.         {
  355.             this.BindName(null);
  356.             //Resolving the call is delayed until the arguments have been partially evaluated
  357.             return this;
  358.         }
  359.        
  360.         internal override AST PartiallyEvaluateAsReference()
  361.         {
  362.             this.BindName(null);
  363.             if (this.members == null || this.members.Length == 0) {
  364.                 if (this.isImplicitWrapper && !Convert.IsArray(this.rootObjectInferredType))
  365.                     this.context.HandleError(JSError.UselessAssignment);
  366.                 else
  367.                     this.HandleNoSuchMemberError();
  368.                 return this;
  369.             }
  370.             this.ResolveLHValue();
  371.             if (this.isImplicitWrapper)
  372.                 if (this.member == null || (!(this.member is JSField) && Typeob.JSObject.IsAssignableFrom(this.member.DeclaringType)))
  373.                     this.context.HandleError(JSError.UselessAssignment);
  374.             return this;
  375.         }
  376.        
  377.         private IReflect ProvideWrapperForPrototypeProperties(IReflect obType)
  378.         {
  379.             //Provide for early binding to prototype methods in fast mode, by fudging the type
  380.             if (obType == Typeob.String) {
  381.                 obType = Globals.globalObject.originalString.Construct();
  382.                 ((JSObject)obType).noExpando = this.fast;
  383.                 this.isImplicitWrapper = true;
  384.             }
  385.             else if ((obType is Type && Typeob.Array.IsAssignableFrom((Type)obType)) || obType is TypedArray) {
  386.                 obType = Globals.globalObject.originalArray.ConstructWrapper();
  387.                 ((JSObject)obType).noExpando = this.fast;
  388.                 this.isImplicitWrapper = true;
  389.             }
  390.             else if (obType == Typeob.Boolean) {
  391.                 obType = Globals.globalObject.originalBoolean.Construct();
  392.                 ((JSObject)obType).noExpando = this.fast;
  393.                 this.isImplicitWrapper = true;
  394.             }
  395.             else if (Convert.IsPrimitiveNumericType(obType)) {
  396.                 Type baseType = (Type)obType;
  397.                 obType = Globals.globalObject.originalNumber.Construct();
  398.                 ((JSObject)obType).noExpando = this.fast;
  399.                 ((NumberObject)obType).baseType = baseType;
  400.                 this.isImplicitWrapper = true;
  401.             }
  402.             else if (obType is Type)
  403.                 obType = Convert.ToIReflect((Type)obType, this.Engine);
  404.             return obType;
  405.         }
  406.        
  407.         internal override object ResolveCustomAttribute(ASTList args, IReflect[] argIRs, AST target)
  408.         {
  409.             this.name = this.name + "Attribute";
  410.             this.BindName(null);
  411.             if (this.members == null || this.members.Length == 0) {
  412.                 this.name = this.name.Substring(0, this.name.Length - 9);
  413.                 this.BindName(null);
  414.             }
  415.             return base.ResolveCustomAttribute(args, argIRs, target);
  416.         }
  417.        
  418.         //code in parser relies on the member string (x.y.z...) being returned from here
  419.         public override string ToString()
  420.         {
  421.             return this.rootObject.ToString() + "." + this.name;
  422.         }
  423.        
  424.         internal override void TranslateToILInitializer(ILGenerator il)
  425.         {
  426.             this.rootObject.TranslateToILInitializer(il);
  427.             if (!this.rootObjectInferredType.Equals(this.rootObject.InferType(null)))
  428.                 this.InvalidateBinding();
  429.             if (this.defaultMember != null)
  430.                 return;
  431.             if (this.member != null)
  432.                 switch (this.member.MemberType) {
  433.                     case MemberTypes.Constructor:
  434.                     case MemberTypes.Method:
  435.                     case MemberTypes.NestedType:
  436.                     case MemberTypes.Property:
  437.                     case MemberTypes.TypeInfo:
  438.                         return;
  439.                     case MemberTypes.Field:
  440.                         if (this.member is JSExpandoField) {
  441.                             this.member = null;
  442.                             break;
  443.                         }
  444.                         return;
  445.                 }
  446.             this.refLoc = il.DeclareLocal(Typeob.LateBinding);
  447.             il.Emit(OpCodes.Ldstr, this.name);
  448.             il.Emit(OpCodes.Newobj, CompilerGlobals.lateBindingConstructor);
  449.             il.Emit(OpCodes.Stloc, this.refLoc);
  450.         }
  451.        
  452.         protected override void TranslateToILObject(ILGenerator il, Type obType, bool noValue)
  453.         {
  454.             if (noValue && obType.IsValueType && obType != Typeob.Enum) {
  455.                 if (this.temp == null)
  456.                     this.rootObject.TranslateToILReference(il, obType);
  457.                 else {
  458.                     Type tempType = Convert.ToType(this.rootObject.InferType(null));
  459.                     if (tempType == obType)
  460.                         il.Emit(OpCodes.Ldloca, this.temp);
  461.                     else {
  462.                         il.Emit(OpCodes.Ldloc, this.temp);
  463.                         Convert.Emit(this, il, tempType, obType);
  464.                         Convert.EmitLdloca(il, obType);
  465.                     }
  466.                 }
  467.             }
  468.             else {
  469.                 if (this.temp == null || this.rootObject is ThisLiteral)
  470.                     this.rootObject.TranslateToIL(il, obType);
  471.                 else {
  472.                     il.Emit(OpCodes.Ldloc, this.temp);
  473.                     Type tempType = Convert.ToType(this.rootObject.InferType(null));
  474.                     Convert.Emit(this, il, tempType, obType);
  475.                 }
  476.             }
  477.         }
  478.        
  479.         protected override void TranslateToILWithDupOfThisOb(ILGenerator il)
  480.         {
  481.             IReflect ir = this.rootObject.InferType(null);
  482.             Type tempType = Convert.ToType(ir);
  483.             this.rootObject.TranslateToIL(il, tempType);
  484.             if (ir == Typeob.Object || ir == Typeob.String || ir is TypedArray || (ir == tempType && Typeob.Array.IsAssignableFrom(tempType))) {
  485.                 tempType = Typeob.Object;
  486.                 this.EmitILToLoadEngine(il);
  487.                 il.Emit(OpCodes.Call, CompilerGlobals.toObjectMethod);
  488.             }
  489.             il.Emit(OpCodes.Dup);
  490.             this.temp = il.DeclareLocal(tempType);
  491.             il.Emit(OpCodes.Stloc, temp);
  492.             Convert.Emit(this, il, tempType, Typeob.Object);
  493.             this.TranslateToIL(il, Typeob.Object);
  494.         }
  495.        
  496.         internal void TranslateToLateBinding(ILGenerator il, bool speculativeEarlyBindingsExist)
  497.         {
  498.             if (speculativeEarlyBindingsExist) {
  499.                 LocalBuilder temp = il.DeclareLocal(Typeob.Object);
  500.                 il.Emit(OpCodes.Stloc, temp);
  501.                 il.Emit(OpCodes.Ldloc, this.refLoc);
  502.                 il.Emit(OpCodes.Dup);
  503.                 il.Emit(OpCodes.Ldloc, temp);
  504.             }
  505.             else {
  506.                 il.Emit(OpCodes.Ldloc, this.refLoc);
  507.                 il.Emit(OpCodes.Dup);
  508.                 this.TranslateToILObject(il, Typeob.Object, false);
  509.             }
  510.             IReflect ir = this.rootObject.InferType(null);
  511.             if (ir == Typeob.Object || ir == Typeob.String || ir is TypedArray || (ir is Type && ((Type)ir).IsPrimitive) || (ir is Type && Typeob.Array.IsAssignableFrom((Type)ir))) {
  512.                 this.EmitILToLoadEngine(il);
  513.                 il.Emit(OpCodes.Call, CompilerGlobals.toObjectMethod);
  514.             }
  515.             il.Emit(OpCodes.Stfld, CompilerGlobals.objectField);
  516.         }
  517.     }
  518. }

Developer Fusion