static private IsPromotableTo ( IReflect source_ir, IReflect target_ir ) : bool | ||
source_ir | IReflect | |
target_ir | IReflect | |
return | bool |
internal override IReflect InferType(JSField inference_target) { MethodInfo oper; if (this.type1 == null || inference_target != null) { oper = this.GetOperator(this.operand1.InferType(inference_target), this.operand2.InferType(inference_target)); } else { oper = this.GetOperator(this.type1, this.type2); } if (oper != null) { this.metaData = oper; return(oper.ReturnType); } if (this.type1 == Typeob.String || this.type2 == Typeob.String) { return(Typeob.String); } if (Convert.IsPrimitiveNumericType(this.type1)) { if (Convert.IsPromotableTo(this.type2, this.type1) || ((this.operand2 is ConstantWrapper) && ((ConstantWrapper)this.operand2).IsAssignableTo(this.type1))) { return(this.type1); } else if (Convert.IsPrimitiveNumericType(this.type1) && Convert.IsPrimitiveNumericTypeFitForDouble(this.type2)) { return(Typeob.Double); } } return(Typeob.Object); }
internal void SetInferredType(IReflect ir, AST expr) { this.isDefined = true; if (this.type != null) { return; //The local variable has a type annotation. } if (this.outerField != null) { this.outerField.SetInferredType(ir, expr); return; } if (Convert.IsPrimitiveNumericType(ir)) { ir = Typeob.Double; } else if (ir == Typeob.Void) { ir = Typeob.Object; } if (this.inferred_type == null) { this.inferred_type = ir; } else { //Check to see if ir is compatible with this.inferred_type. If not, generalize this.inferred_type to Object and invalidate dependants. if (ir == this.inferred_type) { return; } if (!Convert.IsPrimitiveNumericType(this.inferred_type) || !Convert.IsPrimitiveNumericType(ir) || !Convert.IsPromotableTo(ir, this.inferred_type)) { this.inferred_type = Typeob.Object; if (this.dependents != null) //Some other fields have had their inferred types set to something or other, based on this field's inferred type //Since the inference for this field proved wrong, the inferences for the other fields might be wrong as well. { for (int i = 0, n = this.dependents.Count; i < n; i++) { ((JSLocalField)this.dependents[i]).SetInferredType(Typeob.Object, null); } } } } }
internal void SetInferredType(IReflect ir, AST expr) { this.isDefined = true; if (this.type != null) { return; //The local variable has a type annotation. } if (this.outerField != null) { this.outerField.SetInferredType(ir, expr); return; } if (Convert.IsPrimitiveNumericTypeFitForDouble(ir)) { ir = Typeob.Double; } else if (ir == Typeob.Void) { ir = Typeob.Object; } if (this.inferred_type == null) { this.inferred_type = ir; } else { //Check to see if ir is compatible with this.inferred_type. If not, generalize this.inferred_type to Object and invalidate dependants. if (ir == this.inferred_type) { return; } if (!Convert.IsPrimitiveNumericType(this.inferred_type) || !Convert.IsPrimitiveNumericType(ir) || !Convert.IsPromotableTo(ir, this.inferred_type)) { this.inferred_type = Typeob.Object; if (this.dependents != null) { for (int i = 0, n = this.dependents.Count; i < n; i++) { ((JSLocalField)this.dependents[i]).SetInferredType(Typeob.Object, null); } } } } }
internal override IReflect InferType(JSField inference_target) { Debug.Assert(Globals.TypeRefs.InReferenceContext(this.type1)); Debug.Assert(Globals.TypeRefs.InReferenceContext(this.type2)); MethodInfo oper; if (this.type1 == null || inference_target != null) { oper = this.GetOperator(this.operand1.InferType(inference_target), this.operand2.InferType(inference_target)); } else { oper = this.GetOperator(this.type1, this.type2); } if (oper != null) { this.metaData = oper; return(oper.ReturnType); } if (this.type1 == Typeob.Char && this.operatorTok == JSToken.Minus) { TypeCode t2 = Type.GetTypeCode(this.type2); if (Convert.IsPrimitiveNumericTypeCode(t2) || t2 == TypeCode.Boolean) { return(Typeob.Char); } else if (t2 == TypeCode.Char) { return(Typeob.Int32); } } if (Convert.IsPrimitiveNumericType(this.type1)) { if (Convert.IsPromotableTo(this.type2, this.type1) || ((this.operand2 is ConstantWrapper) && ((ConstantWrapper)this.operand2).IsAssignableTo(this.type1))) { return(this.type1); } else if (Convert.IsPrimitiveNumericType(this.type1) && Convert.IsPrimitiveNumericTypeFitForDouble(this.type2)) { return(Typeob.Double); } } return(Typeob.Object); }
internal bool IsPromotableTo(Type other) { Type st = this.GetBakedSuperType(); if (other.IsAssignableFrom(st)) { return(true); } if (other.IsInterface && this.ImplementsInterface(other)) { return(true); } EnumDeclaration ed = this.owner as EnumDeclaration; if (ed != null && Convert.IsPromotableTo(ed.baseType.ToType(), other)) { return(true); } return(false); }
internal override void TranslateToConditionalBranch(ILGenerator il, bool branchIfTrue, Label label, bool shortForm) { Type t1 = this.type1; Type t2 = this.type2; Type t3 = Typeob.Object; if (t1.IsPrimitive && t2.IsPrimitive) { t3 = Typeob.Double; if (Convert.IsPromotableTo(t1, t2)) { t3 = t2; } else if (Convert.IsPromotableTo(t2, t1)) { t3 = t1; } else if (t1 == Typeob.Int64 || t1 == Typeob.UInt64 || t2 == Typeob.Int64 || t2 == Typeob.UInt64) { t3 = Typeob.Object; //Cannot convert these to double without loss of precision in some cases, so use the helper method } } if (t3 == Typeob.SByte || t3 == Typeob.Int16) { t3 = Typeob.Int32; } else if (t3 == Typeob.Byte || t3 == Typeob.UInt16) { t3 = Typeob.UInt32; } if (this.metaData == null) { this.operand1.TranslateToIL(il, t3); this.operand2.TranslateToIL(il, t3); if (t3 == Typeob.Object) { il.Emit(OpCodes.Call, CompilerGlobals.jScriptCompareMethod); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Conv_R8); t3 = Typeob.Double; } } else if (this.metaData is MethodInfo) { MethodInfo oper = (MethodInfo)this.metaData; ParameterInfo[] pars = oper.GetParameters(); this.operand1.TranslateToIL(il, pars[0].ParameterType); this.operand2.TranslateToIL(il, pars[1].ParameterType); il.Emit(OpCodes.Call, oper); if (branchIfTrue) { il.Emit(shortForm ? OpCodes.Brtrue_S : OpCodes.Brtrue, label); } else { il.Emit(shortForm ? OpCodes.Brfalse_S : OpCodes.Brfalse, label); } return; } else { //Getting here is just too bad. We do not know until the code runs whether or not to call an overloaded operator method. //Compile operands to objects and devolve the decision making to run time thunks il.Emit(OpCodes.Ldloc, (LocalBuilder)this.metaData); this.operand1.TranslateToIL(il, Typeob.Object); this.operand2.TranslateToIL(il, Typeob.Object); il.Emit(OpCodes.Call, CompilerGlobals.evaluateRelationalMethod); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Conv_R8); t3 = Typeob.Double; } if (branchIfTrue) { if (t3 == Typeob.UInt32 || t3 == Typeob.UInt64) { switch (this.operatorTok) { case JSToken.GreaterThan: il.Emit(shortForm ? OpCodes.Bgt_Un_S : OpCodes.Bgt_Un, label); break; case JSToken.GreaterThanEqual: il.Emit(shortForm ? OpCodes.Bge_Un_S : OpCodes.Bge_Un, label); break; case JSToken.LessThan: il.Emit(shortForm ? OpCodes.Blt_Un_S : OpCodes.Blt_Un, label); break; case JSToken.LessThanEqual: il.Emit(shortForm ? OpCodes.Ble_Un_S : OpCodes.Ble_Un, label); break; default: throw new JScriptException(JSError.InternalError, this.context); } } else { switch (this.operatorTok) { case JSToken.GreaterThan: il.Emit(shortForm ? OpCodes.Bgt_S : OpCodes.Bgt, label); break; case JSToken.GreaterThanEqual: il.Emit(shortForm ? OpCodes.Bge_S : OpCodes.Bge, label); break; case JSToken.LessThan: il.Emit(shortForm ? OpCodes.Blt_S : OpCodes.Blt, label); break; case JSToken.LessThanEqual: il.Emit(shortForm ? OpCodes.Ble_S : OpCodes.Ble, label); break; default: throw new JScriptException(JSError.InternalError, this.context); } } } else { if (t3 == Typeob.Int32 || t3 == Typeob.Int64) { switch (this.operatorTok) { case JSToken.GreaterThan: il.Emit(shortForm ? OpCodes.Ble_S : OpCodes.Ble, label); break; case JSToken.GreaterThanEqual: il.Emit(shortForm ? OpCodes.Blt_S : OpCodes.Blt, label); break; case JSToken.LessThan: il.Emit(shortForm ? OpCodes.Bge_S : OpCodes.Bge, label); break; case JSToken.LessThanEqual: il.Emit(shortForm ? OpCodes.Bgt_S : OpCodes.Bgt, label); break; default: throw new JScriptException(JSError.InternalError, this.context); } } else { switch (this.operatorTok) { case JSToken.GreaterThan: il.Emit(shortForm ? OpCodes.Ble_Un_S : OpCodes.Ble_Un, label); break; case JSToken.GreaterThanEqual: il.Emit(shortForm ? OpCodes.Blt_Un_S : OpCodes.Blt_Un, label); break; case JSToken.LessThan: il.Emit(shortForm ? OpCodes.Bge_Un_S : OpCodes.Bge_Un, label); break; case JSToken.LessThanEqual: il.Emit(shortForm ? OpCodes.Bgt_Un_S : OpCodes.Bgt_Un, label); break; default: throw new JScriptException(JSError.InternalError, this.context); } } } }
internal void TranslateToConditionalBranch(ILGenerator il, Type etype, bool branchIfTrue, Label label, bool shortForm) { Debug.PreCondition(this.case_value != null); Type t1 = etype; Type t2 = Convert.ToType(this.case_value.InferType(null)); if (t1 != t2 && t1.IsPrimitive && t2.IsPrimitive) { if (t1 == Typeob.Single && t2 == Typeob.Double) { t2 = Typeob.Single; } else if (Convert.IsPromotableTo(t2, t1)) { t2 = t1; } else if (Convert.IsPromotableTo(t1, t2)) { t1 = t2; } } bool nonPrimitive = true; if (t1 == t2 && t1 != Typeob.Object) { Convert.Emit(this, il, etype, t1); if (!t1.IsPrimitive && t1.IsValueType) { il.Emit(OpCodes.Box, t1); } this.case_value.context.EmitLineInfo(il); this.case_value.TranslateToIL(il, t1); if (t1 == Typeob.String) { il.Emit(OpCodes.Call, CompilerGlobals.stringEqualsMethod); } else if (!t1.IsPrimitive) { if (t1.IsValueType) { il.Emit(OpCodes.Box, t1); } il.Emit(OpCodes.Callvirt, CompilerGlobals.equalsMethod); } else { nonPrimitive = false; } } else { Convert.Emit(this, il, etype, Typeob.Object); this.case_value.context.EmitLineInfo(il); this.case_value.TranslateToIL(il, Typeob.Object); il.Emit(OpCodes.Call, CompilerGlobals.jScriptStrictEqualsMethod); } if (branchIfTrue) { if (nonPrimitive) { il.Emit(shortForm ? OpCodes.Brtrue_S : OpCodes.Brtrue, label); } else { il.Emit(shortForm ? OpCodes.Beq_S : OpCodes.Beq, label); } } else { if (nonPrimitive) { il.Emit(shortForm ? OpCodes.Brfalse_S : OpCodes.Brfalse, label); } else { il.Emit(shortForm ? OpCodes.Bne_Un_S : OpCodes.Bne_Un, label); } } }
private void TranslateToILForNoOverloadCase(ILGenerator il, Type rtype) { Type type = Convert.ToType(this.operand.InferType(null)); this.operand.TranslateToILPreSetPlusGet(il); if (rtype == Typeob.Void) { Type rt = Typeob.Double; if (Convert.IsPrimitiveNumericType(type)) { if (type == Typeob.SByte || type == Typeob.Int16) { rt = Typeob.Int32; } else if (type == Typeob.Byte || type == Typeob.UInt16 || type == Typeob.Char) { rt = Typeob.UInt32; } else { rt = type; } } Convert.Emit(this, il, type, rt); il.Emit(OpCodes.Ldc_I4_1); Convert.Emit(this, il, Typeob.Int32, rt); if (rt == Typeob.Double || rt == Typeob.Single) { if (this.operatorTok == PostOrPrefix.PostfixDecrement || this.operatorTok == PostOrPrefix.PrefixDecrement) { il.Emit(OpCodes.Sub); } else { il.Emit(OpCodes.Add); } } else if (rt == Typeob.Int32 || rt == Typeob.Int64) { if (this.operatorTok == PostOrPrefix.PostfixDecrement || this.operatorTok == PostOrPrefix.PrefixDecrement) { il.Emit(OpCodes.Sub_Ovf); } else { il.Emit(OpCodes.Add_Ovf); } } else { if (this.operatorTok == PostOrPrefix.PostfixDecrement || this.operatorTok == PostOrPrefix.PrefixDecrement) { il.Emit(OpCodes.Sub_Ovf_Un); } else { il.Emit(OpCodes.Add_Ovf_Un); } } Convert.Emit(this, il, rt, type); this.operand.TranslateToILSet(il); } else { //set rt to be the smallest type that is precise enough for the result and the variable Type rt = Typeob.Double; if (Convert.IsPrimitiveNumericType(rtype) && Convert.IsPromotableTo(type, rtype)) { rt = rtype; } else if (Convert.IsPrimitiveNumericType(type) && Convert.IsPromotableTo(rtype, type)) { rt = type; } if (rt == Typeob.SByte || rt == Typeob.Int16) { rt = Typeob.Int32; } else if (rt == Typeob.Byte || rt == Typeob.UInt16 || rt == Typeob.Char) { rt = Typeob.UInt32; } LocalBuilder result = il.DeclareLocal(rtype); Convert.Emit(this, il, type, rt); if (this.operatorTok == PostOrPrefix.PostfixDecrement) { il.Emit(OpCodes.Dup); if (type == Typeob.Char) { Convert.Emit(this, il, rt, Typeob.Char); Convert.Emit(this, il, Typeob.Char, rtype); } else { Convert.Emit(this, il, rt, rtype); } il.Emit(OpCodes.Stloc, result); il.Emit(OpCodes.Ldc_I4_1); Convert.Emit(this, il, Typeob.Int32, rt); if (rt == Typeob.Double || rt == Typeob.Single) { il.Emit(OpCodes.Sub); } else if (rt == Typeob.Int32 || rt == Typeob.Int64) { il.Emit(OpCodes.Sub_Ovf); } else { il.Emit(OpCodes.Sub_Ovf_Un); } } else if (this.operatorTok == PostOrPrefix.PostfixIncrement) { il.Emit(OpCodes.Dup); if (type == Typeob.Char) { Convert.Emit(this, il, rt, Typeob.Char); Convert.Emit(this, il, Typeob.Char, rtype); } else { Convert.Emit(this, il, rt, rtype); } il.Emit(OpCodes.Stloc, result); il.Emit(OpCodes.Ldc_I4_1); Convert.Emit(this, il, Typeob.Int32, rt); if (rt == Typeob.Double || rt == Typeob.Single) { il.Emit(OpCodes.Add); } else if (rt == Typeob.Int32 || rt == Typeob.Int64) { il.Emit(OpCodes.Add_Ovf); } else { il.Emit(OpCodes.Add_Ovf_Un); } } else if (this.operatorTok == PostOrPrefix.PrefixDecrement) { il.Emit(OpCodes.Ldc_I4_1); Convert.Emit(this, il, Typeob.Int32, rt); if (rt == Typeob.Double || rt == Typeob.Single) { il.Emit(OpCodes.Sub); } else if (rt == Typeob.Int32 || rt == Typeob.Int64) { il.Emit(OpCodes.Sub_Ovf); } else { il.Emit(OpCodes.Sub_Ovf_Un); } il.Emit(OpCodes.Dup); if (type == Typeob.Char) { Convert.Emit(this, il, rt, Typeob.Char); Convert.Emit(this, il, Typeob.Char, rtype); } else { Convert.Emit(this, il, rt, rtype); } il.Emit(OpCodes.Stloc, result); } else //if (this.operatorTok == PostOrPrefix.PrefixIncrement) { il.Emit(OpCodes.Ldc_I4_1); Convert.Emit(this, il, Typeob.Int32, rt); if (rt == Typeob.Double || rt == Typeob.Single) { il.Emit(OpCodes.Add); } else if (rt == Typeob.Int32 || rt == Typeob.Int64) { il.Emit(OpCodes.Add_Ovf); } else { il.Emit(OpCodes.Add_Ovf_Un); } il.Emit(OpCodes.Dup); if (type == Typeob.Char) { Convert.Emit(this, il, rt, Typeob.Char); Convert.Emit(this, il, Typeob.Char, rtype); } else { Convert.Emit(this, il, rt, rtype); } il.Emit(OpCodes.Stloc, result); } Convert.Emit(this, il, rt, type); this.operand.TranslateToILSet(il); il.Emit(OpCodes.Ldloc, result); } }
internal override void TranslateToIL(ILGenerator il, Type rtype) { if (this.metaData == null) { Type rt = this.operatorTok == JSToken.LogicalNot ? Typeob.Boolean : Typeob.Double; if (Convert.IsPrimitiveNumericType(rtype) && Convert.IsPromotableTo(this.type, rtype)) { rt = rtype; } if (this.operatorTok == JSToken.BitwiseNot && !Convert.IsPrimitiveIntegerType(rt)) { rt = this.type; if (!Convert.IsPrimitiveIntegerType(rt)) { rt = Typeob.Int32; } } this.operand.TranslateToIL(il, this.type); Convert.Emit(this, il, this.type, rt, true); switch (this.operatorTok) { case JSToken.BitwiseNot: il.Emit(OpCodes.Not); break; case JSToken.LogicalNot: Convert.Emit(this, il, rt, Typeob.Boolean, true); rt = Typeob.Boolean; il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Ceq); break; case JSToken.Minus: il.Emit(OpCodes.Neg); break; case JSToken.Plus: break; default: throw new JScriptException(JSError.InternalError, this.context); } Convert.Emit(this, il, rt, rtype); return; } if (this.metaData is MethodInfo) { MethodInfo oper = (MethodInfo)this.metaData; ParameterInfo[] pars = oper.GetParameters(); this.operand.TranslateToIL(il, pars[0].ParameterType); il.Emit(OpCodes.Call, oper); Convert.Emit(this, il, oper.ReturnType, rtype); return; } //Getting here is just too bad. We do not know until the code runs whether or not to call an overloaded operator method. //Compile operands to objects and devolve the decision making to run time thunks il.Emit(OpCodes.Ldloc, (LocalBuilder)this.metaData); this.operand.TranslateToIL(il, Typeob.Object); il.Emit(OpCodes.Call, CompilerGlobals.evaluateUnaryMethod); Convert.Emit(this, il, Typeob.Object, rtype); }
internal override AST PartiallyEvaluate() { this.ctor = this.ctor.PartiallyEvaluateAsCallable(); //first weed out assignment expressions and use them as property initializers ASTList positionalArgs = new ASTList(this.args.context); ASTList namedArgs = new ASTList(this.args.context); for (int i = 0, m = this.args.count; i < m; i++) { AST arg = this.args[i]; Assign assign = arg as Assign; if (assign != null) { assign.rhside = assign.rhside.PartiallyEvaluate(); namedArgs.Append(assign); } else { positionalArgs.Append(arg.PartiallyEvaluate()); } } int n = positionalArgs.count; IReflect[] argIRs = new IReflect[n]; for (int i = 0; i < n; i++) { AST arg = positionalArgs[i]; // only accept ConstantWrappers if (arg is ConstantWrapper) { Object argument = arg.Evaluate(); if ((argIRs[i] = CustomAttribute.TypeOfArgument(argument)) != null) { this.positionalArgValues.Add(argument); continue; } } else if (arg is ArrayLiteral && ((ArrayLiteral)arg).IsOkToUseInCustomAttribute()) { argIRs[i] = Typeob.ArrayObject; this.positionalArgValues.Add(arg.Evaluate()); continue; } arg.context.HandleError(JSError.InvalidCustomAttributeArgument); return(null); // the custom attribute is not good and it will be ignored } //Get the custom attribute and the appropriate constructor (under the covers) this.type = this.ctor.ResolveCustomAttribute(positionalArgs, argIRs, this.target); if (this.type == null) { return(null); } if (Convert.IsPromotableTo((IReflect)this.type, typeof(CodeAccessSecurityAttribute))) { this.context.HandleError(JSError.CannotUseStaticSecurityAttribute); return(null); } //Coerce the positional arguments to the right type and supply default values for optional parameters ConstructorInfo c = (ConstructorInfo)((Binding)this.ctor).member; ParameterInfo[] parameters = c.GetParameters(); int j = 0; int len = this.positionalArgValues.Count; foreach (ParameterInfo p in parameters) { IReflect ir = p is ParameterDeclaration ? ((ParameterDeclaration)p).ParameterIReflect : p.ParameterType; if (j < len) { Object value = this.positionalArgValues[j]; this.positionalArgValues[j] = Convert.Coerce(value, ir, value is ArrayObject); j++; } else { Object value; if (p.DefaultValue == System.Convert.DBNull) { value = Convert.Coerce(null, ir); } else { value = p.DefaultValue; } this.positionalArgValues.Add(value); } } //Check validity of property/field initializers for (int i = 0, m = namedArgs.count; i < m; i++) { Assign assign = (Assign)namedArgs[i]; if (assign.lhside is Lookup && (assign.rhside is ConstantWrapper || (assign.rhside is ArrayLiteral && ((ArrayLiteral)assign.rhside).IsOkToUseInCustomAttribute()))) { Object value = assign.rhside.Evaluate(); IReflect argType = null; if (value is ArrayObject || ((argType = CustomAttribute.TypeOfArgument(value)) != null && argType != Typeob.Object)) { String name = ((Lookup)assign.lhside).Name; MemberInfo [] members = ((IReflect)this.type).GetMember(name, BindingFlags.Public | BindingFlags.Instance); if (members == null || members.Length == 0) { assign.context.HandleError(JSError.NoSuchMember); return(null); } if (members.Length == 1) { MemberInfo member = members[0]; if (member is FieldInfo) { FieldInfo fieldInfo = (FieldInfo)member; if (!fieldInfo.IsLiteral && !fieldInfo.IsInitOnly) { try{ IReflect ir = fieldInfo is JSVariableField ? ((JSVariableField)fieldInfo).GetInferredType(null) : fieldInfo.FieldType; value = Convert.Coerce(value, ir, value is ArrayObject); this.namedArgFields.Add(member); this.namedArgFieldValues.Add(value); continue; }catch (JScriptException) { assign.rhside.context.HandleError(JSError.TypeMismatch); return(null); // the custom attribute is not good and it will be ignored } } } else if (member is PropertyInfo) { PropertyInfo propertyInfo = (PropertyInfo)member; MethodInfo setMethodInfo = JSProperty.GetSetMethod(propertyInfo, false); if (setMethodInfo != null) { ParameterInfo [] paramInfo = setMethodInfo.GetParameters(); if (paramInfo != null && paramInfo.Length == 1) { try{ IReflect ir = paramInfo[0] is ParameterDeclaration ? ((ParameterDeclaration)paramInfo[0]).ParameterIReflect : paramInfo[0].ParameterType; value = Convert.Coerce(value, ir, value is ArrayObject); this.namedArgProperties.Add(member); this.namedArgPropertyValues.Add(value); }catch (JScriptException) { assign.rhside.context.HandleError(JSError.TypeMismatch); return(null); // the custom attribute is not good and it will be ignored } continue; } } } } } } assign.context.HandleError(JSError.InvalidCustomAttributeArgument); return(null); } if (!this.CheckIfTargetOK(this.type)) { return(null); //Ignore attribute } //Consume and discard assembly name attributes try{ Type ty = this.type as Type; if (ty != null && this.target is AssemblyCustomAttributeList) { if (ty.FullName == "System.Reflection.AssemblyAlgorithmIdAttribute") { if (this.positionalArgValues.Count > 0) { this.Engine.Globals.assemblyHashAlgorithm = (AssemblyHashAlgorithm)Convert.CoerceT(this.positionalArgValues[0], typeof(AssemblyHashAlgorithm)); } return(null); } if (ty.FullName == "System.Reflection.AssemblyCultureAttribute") { if (this.positionalArgValues.Count > 0) { String cultureId = Convert.ToString(this.positionalArgValues[0]); if (this.Engine.PEFileKind != PEFileKinds.Dll && cultureId.Length > 0) { this.context.HandleError(JSError.ExecutablesCannotBeLocalized); return(null); } this.Engine.Globals.assemblyCulture = new CultureInfo(cultureId); } return(null); } if (ty.FullName == "System.Reflection.AssemblyDelaySignAttribute") { if (this.positionalArgValues.Count > 0) { this.Engine.Globals.assemblyDelaySign = Convert.ToBoolean(this.positionalArgValues[0], false); } return(null); } if (ty.FullName == "System.Reflection.AssemblyFlagsAttribute") { if (this.positionalArgValues.Count > 0) { this.Engine.Globals.assemblyFlags = (AssemblyFlags)(uint)Convert.CoerceT(this.positionalArgValues[0], typeof(uint)); } return(null); } if (ty.FullName == "System.Reflection.AssemblyKeyFileAttribute") { if (this.positionalArgValues.Count > 0) { this.Engine.Globals.assemblyKeyFileName = Convert.ToString(this.positionalArgValues[0]); if (this.Engine.Globals.assemblyKeyFileName != null && this.Engine.Globals.assemblyKeyFileName.Length == 0) { this.Engine.Globals.assemblyKeyFileName = null; } } return(null); } if (ty.FullName == "System.Reflection.AssemblyKeyNameAttribute") { if (this.positionalArgValues.Count > 0) { this.Engine.Globals.assemblyKeyName = Convert.ToString(this.positionalArgValues[0]); if (this.Engine.Globals.assemblyKeyName != null && this.Engine.Globals.assemblyKeyName.Length == 0) { this.Engine.Globals.assemblyKeyName = null; } } return(null); } if (ty.FullName == "System.Reflection.AssemblyVersionAttribute") { if (this.positionalArgValues.Count > 0) { this.Engine.Globals.assemblyVersion = this.ParseVersion(Convert.ToString(this.positionalArgValues[0])); } return(null); } if (ty.FullName == "System.CLSCompliantAttribute") { this.Engine.isCLSCompliant = this.args == null || this.args.count == 0 || Convert.ToBoolean(this.positionalArgValues[0], false); return(this); } } }catch (ArgumentException) { this.context.HandleError(JSError.InvalidCall); } return(this); }
private void TranslateToILForNoOverloadCase(ILGenerator il, Type rtype) { Type lhtype = Convert.ToType(this.operand1.InferType(null)); Type rhtype = Convert.ToType(this.operand2.InferType(null)); Type rt = Typeob.Double; if (this.operatorTok != JSToken.Divide && (rtype == Typeob.Void || rtype == lhtype || Convert.IsPrimitiveNumericType(lhtype)) && (Convert.IsPromotableTo(rhtype, lhtype) || ((this.operand2 is ConstantWrapper) && ((ConstantWrapper)this.operand2).IsAssignableTo(lhtype)))) { rt = lhtype; } if (rt == Typeob.SByte || rt == Typeob.Int16) { rt = Typeob.Int32; } else if (rt == Typeob.Byte || rt == Typeob.UInt16 || rt == Typeob.Char) { rt = Typeob.UInt32; } // If we have "unsigned -= signed" or "signed -= unsigned" then generating the // correct code gets quite complicated. Just go late-bound for this edge case. if (this.operand2 is ConstantWrapper) { if (!((ConstantWrapper)this.operand2).IsAssignableTo(rt)) { // eg: "var u : byte = 123; u -= -100;" should go late bound because // of signed/unsigned mismatch but "u -= 1" should not. rt = Typeob.Object; } } else { if ((Convert.IsPrimitiveSignedNumericType(rhtype) && Convert.IsPrimitiveUnsignedIntegerType(lhtype)) || (Convert.IsPrimitiveUnsignedIntegerType(rhtype) && Convert.IsPrimitiveSignedIntegerType(lhtype))) { rt = Typeob.Object; } } this.operand1.TranslateToILPreSetPlusGet(il); Convert.Emit(this, il, lhtype, rt); this.operand2.TranslateToIL(il, rt); if (rt == Typeob.Object) { il.Emit(OpCodes.Ldc_I4, (int)this.operatorTok); il.Emit(OpCodes.Call, CompilerGlobals.numericbinaryDoOpMethod); } else if (rt == Typeob.Double || rt == Typeob.Single) { switch (this.operatorTok) { case JSToken.Divide: il.Emit(OpCodes.Div); break; case JSToken.Minus: il.Emit(OpCodes.Sub); break; case JSToken.Modulo: il.Emit(OpCodes.Rem); break; case JSToken.Multiply: il.Emit(OpCodes.Mul); break; default: throw new JScriptException(JSError.InternalError, this.context); } } else if (rt == Typeob.Int32 || rt == Typeob.Int64 || rt == Typeob.Int16 || rt == Typeob.SByte) { switch (this.operatorTok) { case JSToken.Divide: il.Emit(OpCodes.Div); break; case JSToken.Minus: il.Emit(OpCodes.Sub_Ovf); break; case JSToken.Modulo: il.Emit(OpCodes.Rem); break; case JSToken.Multiply: il.Emit(OpCodes.Mul_Ovf); break; default: throw new JScriptException(JSError.InternalError, this.context); } } else { switch (this.operatorTok) { case JSToken.Divide: il.Emit(OpCodes.Div); break; case JSToken.Minus: il.Emit(OpCodes.Sub_Ovf_Un); break; case JSToken.Modulo: il.Emit(OpCodes.Rem); break; case JSToken.Multiply: il.Emit(OpCodes.Mul_Ovf_Un); break; default: throw new JScriptException(JSError.InternalError, this.context); } } if (rtype != Typeob.Void) { LocalBuilder result = il.DeclareLocal(rt); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Stloc, result); Convert.Emit(this, il, rt, lhtype); this.operand1.TranslateToILSet(il); il.Emit(OpCodes.Ldloc, result); Convert.Emit(this, il, rt, rtype); } else { Convert.Emit(this, il, rt, lhtype); this.operand1.TranslateToILSet(il); } }
internal override AST PartiallyEvaluate() { if (this.alreadyPartiallyEvaluated) { return(this); } this.alreadyPartiallyEvaluated = true; if (this.inBrackets && this.AllParamsAreMissing()) { if (this.isConstructor) { this.args.context.HandleError(JSError.TypeMismatch); } IReflect ir = ((TypeExpression)(new TypeExpression(this.func)).PartiallyEvaluate()).ToIReflect(); return(new ConstantWrapper(new TypedArray(ir, this.args.count + 1), this.context)); } this.func = this.func.PartiallyEvaluateAsCallable(); this.args = (ASTList)this.args.PartiallyEvaluate(); IReflect[] argIRs = this.ArgIRs(); this.func.ResolveCall(this.args, argIRs, this.isConstructor, this.inBrackets); if (!this.isConstructor && !this.inBrackets && this.func is Binding && this.args.count == 1) { Binding b = (Binding)this.func; if (b.member is Type) { Type t = (Type)b.member; ConstantWrapper arg0 = this.args[0] as ConstantWrapper; if (arg0 != null) { try{ if (arg0.value == null || arg0.value is DBNull) { return(this); } else if (arg0.isNumericLiteral && (t == Typeob.Decimal || t == Typeob.Int64 || t == Typeob.UInt64 || t == Typeob.Single)) { return(new ConstantWrapper(Convert.CoerceT(arg0.context.GetCode(), t, true), this.context)); } else { return(new ConstantWrapper(Convert.CoerceT(arg0.Evaluate(), t, true), this.context)); } }catch { arg0.context.HandleError(JSError.TypeMismatch); } } else { if (!Binding.AssignmentCompatible(t, this.args[0], argIRs[0], false)) { this.args[0].context.HandleError(JSError.ImpossibleConversion); } } } else if (b.member is JSVariableField) { JSVariableField field = (JSVariableField)b.member; if (field.IsLiteral) { if (field.value is ClassScope) { ClassScope csc = (ClassScope)field.value; IReflect ut = csc.GetUnderlyingTypeIfEnum(); if (ut != null) { if (!Convert.IsPromotableTo(argIRs[0], ut) && !Convert.IsPromotableTo(ut, argIRs[0]) && (argIRs[0] != Typeob.String || ut == csc)) { this.args[0].context.HandleError(JSError.ImpossibleConversion); } } else { if (!Convert.IsPromotableTo(argIRs[0], csc) && !Convert.IsPromotableTo(csc, argIRs[0])) { this.args[0].context.HandleError(JSError.ImpossibleConversion); } } } else if (field.value is TypedArray) { TypedArray ta = (TypedArray)field.value; if (!Convert.IsPromotableTo(argIRs[0], ta) && !Convert.IsPromotableTo(ta, argIRs[0])) { this.args[0].context.HandleError(JSError.ImpossibleConversion); } } } } } return(this); }
internal override void TranslateToIL(ILGenerator il, Type rtype) { if (this.metaData == null) { Type rt = Typeob.Double; if (Convert.IsPrimitiveNumericType(rtype) && Convert.IsPromotableTo(this.type1, rtype) && Convert.IsPromotableTo(this.type2, rtype)) { rt = rtype; } if (this.operatorTok == JSToken.Divide) { rt = Typeob.Double; } else if (rt == Typeob.SByte || rt == Typeob.Int16) { rt = Typeob.Int32; } else if (rt == Typeob.Byte || rt == Typeob.UInt16 || rt == Typeob.Char) { rt = Typeob.UInt32; } this.operand1.TranslateToIL(il, rt); this.operand2.TranslateToIL(il, rt); if (rt == Typeob.Double || rt == Typeob.Single) { switch (this.operatorTok) { case JSToken.Divide: il.Emit(OpCodes.Div); break; case JSToken.Minus: il.Emit(OpCodes.Sub); break; case JSToken.Modulo: il.Emit(OpCodes.Rem); break; case JSToken.Multiply: il.Emit(OpCodes.Mul); break; default: throw new JScriptException(JSError.InternalError, this.context); } } else if (rt == Typeob.Int32 || rt == Typeob.Int64) { switch (this.operatorTok) { case JSToken.Divide: il.Emit(OpCodes.Div); break; case JSToken.Minus: il.Emit(OpCodes.Sub_Ovf); break; case JSToken.Modulo: il.Emit(OpCodes.Rem); break; case JSToken.Multiply: il.Emit(OpCodes.Mul_Ovf); break; default: throw new JScriptException(JSError.InternalError, this.context); } } else { switch (this.operatorTok) { case JSToken.Divide: il.Emit(OpCodes.Div); break; case JSToken.Minus: il.Emit(OpCodes.Sub_Ovf_Un); break; case JSToken.Modulo: il.Emit(OpCodes.Rem); break; case JSToken.Multiply: il.Emit(OpCodes.Mul_Ovf_Un); break; default: throw new JScriptException(JSError.InternalError, this.context); } } if (Convert.ToType(this.InferType(null)) == Typeob.Char) { Convert.Emit(this, il, rt, Typeob.Char); Convert.Emit(this, il, Typeob.Char, rtype); } else { Convert.Emit(this, il, rt, rtype); } return; } if (this.metaData is MethodInfo) { MethodInfo oper = (MethodInfo)this.metaData; ParameterInfo[] pars = oper.GetParameters(); this.operand1.TranslateToIL(il, pars[0].ParameterType); this.operand2.TranslateToIL(il, pars[1].ParameterType); il.Emit(OpCodes.Call, oper); Convert.Emit(this, il, oper.ReturnType, rtype); return; } //Getting here is just too bad. We do not know until the code runs whether or not to call an overloaded operator method. //Compile operands to objects and devolve the decision making to run time thunks il.Emit(OpCodes.Ldloc, (LocalBuilder)this.metaData); this.operand1.TranslateToIL(il, Typeob.Object); this.operand2.TranslateToIL(il, Typeob.Object); il.Emit(OpCodes.Call, CompilerGlobals.evaluateNumericBinaryMethod); Convert.Emit(this, il, Typeob.Object, rtype); }
internal override void TranslateToConditionalBranch(ILGenerator il, bool branchIfTrue, Label label, bool shortForm) { Type t1 = Convert.ToType(this.operand1.InferType(null)); Type t2 = Convert.ToType(this.operand2.InferType(null)); if (this.operand1 is ConstantWrapper) { if (this.operand1.Evaluate() == null) { t1 = Typeob.Empty; } } if (this.operand2 is ConstantWrapper) { if (this.operand2.Evaluate() == null) { t2 = Typeob.Empty; } } if (t1 != t2 && t1.IsPrimitive && t2.IsPrimitive) { if (t1 == Typeob.Single) { t2 = t1; } else if (t2 == Typeob.Single) { t1 = t2; } else if (Convert.IsPromotableTo(t2, t1)) { t2 = t1; } else if (Convert.IsPromotableTo(t1, t2)) { t1 = t2; } } bool nonPrimitive = true; if (t1 == t2 && t1 != Typeob.Object) { this.operand1.TranslateToIL(il, t1); if (!t1.IsPrimitive && t1.IsValueType) { Convert.EmitLdloca(il, t1); } this.operand2.TranslateToIL(il, t1); if (t1 == Typeob.String) { il.Emit(OpCodes.Call, CompilerGlobals.stringEqualsMethod); } else if (!t1.IsPrimitive) { il.Emit(OpCodes.Callvirt, CompilerGlobals.equalsMethod); } else { nonPrimitive = false; } } else if (t1 == Typeob.Empty) { this.operand2.TranslateToIL(il, Typeob.Object); branchIfTrue = !branchIfTrue; } else if (t2 == Typeob.Empty) { this.operand1.TranslateToIL(il, Typeob.Object); branchIfTrue = !branchIfTrue; } else { this.operand1.TranslateToIL(il, Typeob.Object); this.operand2.TranslateToIL(il, Typeob.Object); il.Emit(OpCodes.Call, CompilerGlobals.jScriptStrictEqualsMethod); } if (branchIfTrue) { if (this.operatorTok == JSToken.StrictEqual) { if (nonPrimitive) { il.Emit(shortForm ? OpCodes.Brtrue_S : OpCodes.Brtrue, label); } else { il.Emit(shortForm ? OpCodes.Beq_S : OpCodes.Beq, label); } } else if (nonPrimitive) { il.Emit(shortForm ? OpCodes.Brfalse_S : OpCodes.Brfalse, label); } else { il.Emit(shortForm ? OpCodes.Bne_Un_S : OpCodes.Bne_Un, label); } } else { if (this.operatorTok == JSToken.StrictEqual) { if (nonPrimitive) { il.Emit(shortForm ? OpCodes.Brfalse_S : OpCodes.Brfalse, label); } else { il.Emit(shortForm ? OpCodes.Bne_Un_S : OpCodes.Bne_Un, label); } } else if (nonPrimitive) { il.Emit(shortForm ? OpCodes.Brtrue_S : OpCodes.Brtrue, label); } else { il.Emit(shortForm ? OpCodes.Beq_S : OpCodes.Beq, label); } } return; }
internal override void TranslateToIL(ILGenerator il, Type rtype) { Type type = Convert.ToType(this.InferType(null)); if (this.metaData == null) { Type rt = Typeob.Object; if (rtype == Typeob.Double) { rt = rtype; } else if (this.type1 == Typeob.Char && this.type2 == Typeob.Char) { rt = Typeob.String; } else if (Convert.IsPrimitiveNumericType(rtype) && Convert.IsPromotableTo(this.type1, rtype) && Convert.IsPromotableTo(this.type2, rtype)) { rt = rtype; } else if (this.type1 != Typeob.String && this.type2 != Typeob.String) //Both will be converted to numbers { rt = Typeob.Double; //Won't get here unless InferType returned Typeob.Double. } else { rt = Typeob.String; } if (rt == Typeob.SByte || rt == Typeob.Int16) { rt = Typeob.Int32; } else if (rt == Typeob.Byte || rt == Typeob.UInt16 || rt == Typeob.Char) { rt = Typeob.UInt32; } if (rt == Typeob.String) { if (this.operand1 is Plus && this.type1 == rt) { Plus op1 = (Plus)this.operand1; if (op1.operand1 is Plus && op1.type1 == rt) { Plus op11 = (Plus)op1.operand1; if (op11.operand1 is Plus && op11.type1 == rt) { int len = op1.TranslateToILArrayOfStrings(il, 1); il.Emit(OpCodes.Dup); ConstantWrapper.TranslateToILInt(il, len - 1); this.operand2.TranslateToIL(il, rt); il.Emit(OpCodes.Stelem_Ref); il.Emit(OpCodes.Call, CompilerGlobals.stringConcatArrMethod); Convert.Emit(this, il, rt, rtype); return; } Plus.TranslateToStringWithSpecialCaseForNull(il, op11.operand1); Plus.TranslateToStringWithSpecialCaseForNull(il, op11.operand2); Plus.TranslateToStringWithSpecialCaseForNull(il, op1.operand2); Plus.TranslateToStringWithSpecialCaseForNull(il, this.operand2); il.Emit(OpCodes.Call, CompilerGlobals.stringConcat4Method); Convert.Emit(this, il, rt, rtype); return; } Plus.TranslateToStringWithSpecialCaseForNull(il, op1.operand1); Plus.TranslateToStringWithSpecialCaseForNull(il, op1.operand2); Plus.TranslateToStringWithSpecialCaseForNull(il, this.operand2); il.Emit(OpCodes.Call, CompilerGlobals.stringConcat3Method); Convert.Emit(this, il, rt, rtype); return; } Plus.TranslateToStringWithSpecialCaseForNull(il, this.operand1); Plus.TranslateToStringWithSpecialCaseForNull(il, this.operand2); il.Emit(OpCodes.Call, CompilerGlobals.stringConcat2Method); Convert.Emit(this, il, rt, rtype); return; } this.operand1.TranslateToIL(il, rt); this.operand2.TranslateToIL(il, rt); if (rt == Typeob.Object) { il.Emit(OpCodes.Call, CompilerGlobals.plusDoOpMethod); } else if (rt == Typeob.Double || rt == Typeob.Single) { il.Emit(OpCodes.Add); } else if (rt == Typeob.Int32 || rt == Typeob.Int64) { il.Emit(OpCodes.Add_Ovf); } else { il.Emit(OpCodes.Add_Ovf_Un); } if (type == Typeob.Char) { Convert.Emit(this, il, rt, Typeob.Char); Convert.Emit(this, il, Typeob.Char, rtype); } else { Convert.Emit(this, il, rt, rtype); } return; } if (this.metaData is MethodInfo) { MethodInfo oper = (MethodInfo)this.metaData; ParameterInfo[] pars = oper.GetParameters(); this.operand1.TranslateToIL(il, pars[0].ParameterType); this.operand2.TranslateToIL(il, pars[1].ParameterType); il.Emit(OpCodes.Call, oper); Convert.Emit(this, il, oper.ReturnType, rtype); return; } //Getting here is just too bad. We do not know until the code runs whether or not to call an overloaded operator method. //Compile operands to objects and devolve the decision making to run time thunks //Also get here when dealing with Int64 and UInt64. These cannot always be converted to doubles. The late-bound code checks for this. il.Emit(OpCodes.Ldloc, (LocalBuilder)this.metaData); this.operand1.TranslateToIL(il, Typeob.Object); this.operand2.TranslateToIL(il, Typeob.Object); il.Emit(OpCodes.Callvirt, CompilerGlobals.evaluatePlusMethod); Convert.Emit(this, il, Typeob.Object, rtype); }
internal override void TranslateToConditionalBranch(ILGenerator il, bool branchIfTrue, Label label, bool shortForm) { Type t1 = Convert.ToType(this.operand1.InferType(null)); Type t2 = Convert.ToType(this.operand2.InferType(null)); if (this.operand1 is ConstantWrapper) { if (this.operand1.Evaluate() == null) { t1 = Typeob.Empty; } } if (this.operand2 is ConstantWrapper) { if (this.operand2.Evaluate() == null) { t2 = Typeob.Empty; } } if (t1 != t2 && t1.IsPrimitive && t2.IsPrimitive) { if (t1 == Typeob.Single) { t2 = t1; } else if (t2 == Typeob.Single) { t1 = t2; } else if (Convert.IsPromotableTo(t2, t1)) { t2 = t1; } else if (Convert.IsPromotableTo(t1, t2)) { t1 = t2; } } bool nonPrimitive = true; if (t1 == t2 && t1 != Typeob.Object) { // Operand types are equal and not Object - need to compare values only. Primitive // values get compared with IL instructions; other values including value types // get compared with Object.Equals. String is special cased for perf. Type t = t1; if (!t1.IsPrimitive) { t = Typeob.Object; } this.operand1.TranslateToIL(il, t); this.operand2.TranslateToIL(il, t); if (t1 == Typeob.String) { il.Emit(OpCodes.Call, CompilerGlobals.stringEqualsMethod); } else if (!t1.IsPrimitive) { il.Emit(OpCodes.Callvirt, CompilerGlobals.equalsMethod); } else { nonPrimitive = false; } } else if (t1 == Typeob.Empty) { this.operand2.TranslateToIL(il, Typeob.Object); branchIfTrue = !branchIfTrue; } else if (t2 == Typeob.Empty) { this.operand1.TranslateToIL(il, Typeob.Object); branchIfTrue = !branchIfTrue; } else { this.operand1.TranslateToIL(il, Typeob.Object); this.operand2.TranslateToIL(il, Typeob.Object); il.Emit(OpCodes.Call, CompilerGlobals.jScriptStrictEqualsMethod); } if (branchIfTrue) { if (this.operatorTok == JSToken.StrictEqual) { if (nonPrimitive) { il.Emit(shortForm ? OpCodes.Brtrue_S : OpCodes.Brtrue, label); } else { il.Emit(shortForm ? OpCodes.Beq_S : OpCodes.Beq, label); } } else if (nonPrimitive) { il.Emit(shortForm ? OpCodes.Brfalse_S : OpCodes.Brfalse, label); } else { il.Emit(shortForm ? OpCodes.Bne_Un_S : OpCodes.Bne_Un, label); } } else { if (this.operatorTok == JSToken.StrictEqual) { if (nonPrimitive) { il.Emit(shortForm ? OpCodes.Brfalse_S : OpCodes.Brfalse, label); } else { il.Emit(shortForm ? OpCodes.Bne_Un_S : OpCodes.Bne_Un, label); } } else if (nonPrimitive) { il.Emit(shortForm ? OpCodes.Brtrue_S : OpCodes.Brtrue, label); } else { il.Emit(shortForm ? OpCodes.Beq_S : OpCodes.Beq, label); } } return; }
private void TranslateToILForNoOverloadCase(ILGenerator il, Type rtype) { Type lhtype = Convert.ToType(this.operand1.InferType(null)); Type rhtype = Convert.ToType(this.operand2.InferType(null)); Type rt = Typeob.Object; if (lhtype == Typeob.String || rhtype == Typeob.String) { rt = Typeob.String; } else if (rtype == Typeob.Void || rtype == lhtype || Convert.IsPrimitiveNumericType(lhtype) && (Convert.IsPromotableTo(rhtype, lhtype) || ((this.operand2 is ConstantWrapper) && ((ConstantWrapper)this.operand2).IsAssignableTo(lhtype)))) { rt = lhtype; } if (rt == Typeob.SByte || rt == Typeob.Int16) { rt = Typeob.Int32; } else if (rt == Typeob.Byte || rt == Typeob.UInt16) { rt = Typeob.UInt32; } // If we have "unsigned += signed" or "signed += unsigned" then generating the // correct code gets quite complicated. Just go late-bound for this edge case. if (this.operand2 is ConstantWrapper) { if (!((ConstantWrapper)this.operand2).IsAssignableTo(rt)) { // eg: "var u : byte = 123; u += -100;" should go late bound because // of signed/unsigned mismatch but "u += 1" should not. rt = Typeob.Object; } } else { if ((Convert.IsPrimitiveSignedNumericType(rhtype) && Convert.IsPrimitiveUnsignedIntegerType(lhtype)) || (Convert.IsPrimitiveUnsignedIntegerType(rhtype) && Convert.IsPrimitiveSignedIntegerType(lhtype))) { rt = Typeob.Object; } } this.operand1.TranslateToILPreSetPlusGet(il); Convert.Emit(this, il, lhtype, rt); this.operand2.TranslateToIL(il, rt); if (rt == Typeob.Object || rt == Typeob.String) { il.Emit(OpCodes.Call, CompilerGlobals.plusDoOpMethod); rt = Typeob.Object; } else if (rt == Typeob.Double || rt == Typeob.Single) { il.Emit(OpCodes.Add); } else if (rt == Typeob.Int32 || rt == Typeob.Int64 || rt == Typeob.Int16 || rt == Typeob.SByte) { il.Emit(OpCodes.Add_Ovf); } else { il.Emit(OpCodes.Add_Ovf_Un); } if (rtype != Typeob.Void) { LocalBuilder result = il.DeclareLocal(rt); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Stloc, result); Convert.Emit(this, il, rt, lhtype); this.operand1.TranslateToILSet(il); il.Emit(OpCodes.Ldloc, result); Convert.Emit(this, il, rt, rtype); } else { Convert.Emit(this, il, rt, lhtype); this.operand1.TranslateToILSet(il); } }
internal override void TranslateToConditionalBranch(ILGenerator il, bool branchIfTrue, Label label, bool shortForm) { if (this.metaData == null) { Type t1 = this.type1; Type t2 = this.type2; Type t3 = Typeob.Object; bool emitNullAndUndefined = true; if (t1.IsPrimitive && t2.IsPrimitive) { t3 = Typeob.Double; if (t1 == Typeob.Single || t2 == Typeob.Single) { t3 = Typeob.Single; } else if (Convert.IsPromotableTo(t1, t2)) { t3 = t2; } else if (Convert.IsPromotableTo(t2, t1)) { t3 = t1; } } else if (t1 == Typeob.String && (t2 == Typeob.String || t2 == Typeob.Empty || t2 == Typeob.Null)) { t3 = Typeob.String; if (t2 != Typeob.String) { emitNullAndUndefined = false; branchIfTrue = !branchIfTrue; } } else if ((t1 == Typeob.Empty || t1 == Typeob.Null) && t2 == Typeob.String) { t3 = Typeob.String; emitNullAndUndefined = false; branchIfTrue = !branchIfTrue; } if (t3 == Typeob.SByte || t3 == Typeob.Int16) { t3 = Typeob.Int32; } else if (t3 == Typeob.Byte || t3 == Typeob.UInt16) { t3 = Typeob.UInt32; } if (emitNullAndUndefined) { this.operand1.TranslateToIL(il, t3); this.operand2.TranslateToIL(il, t3); if (t3 == Typeob.Object) { il.Emit(OpCodes.Call, CompilerGlobals.jScriptEqualsMethod); } else if (t3 == Typeob.String) { il.Emit(OpCodes.Call, CompilerGlobals.stringEqualsMethod); } } else if (t1 == Typeob.String) { this.operand1.TranslateToIL(il, t3); } else if (t2 == Typeob.String) { this.operand2.TranslateToIL(il, t3); } if (branchIfTrue) { if (this.operatorTok == JSToken.Equal) { if (t3 == Typeob.String || t3 == Typeob.Object) { il.Emit(shortForm ? OpCodes.Brtrue_S : OpCodes.Brtrue, label); } else { il.Emit(shortForm ? OpCodes.Beq_S : OpCodes.Beq, label); } } else if (t3 == Typeob.String || t3 == Typeob.Object) { il.Emit(shortForm ? OpCodes.Brfalse_S : OpCodes.Brfalse, label); } else { il.Emit(shortForm ? OpCodes.Bne_Un_S : OpCodes.Bne_Un, label); } } else { if (this.operatorTok == JSToken.Equal) { if (t3 == Typeob.String || t3 == Typeob.Object) { il.Emit(shortForm ? OpCodes.Brfalse_S : OpCodes.Brfalse, label); } else { il.Emit(shortForm ? OpCodes.Bne_Un_S : OpCodes.Bne_Un, label); } } else if (t3 == Typeob.String || t3 == Typeob.Object) { il.Emit(shortForm ? OpCodes.Brtrue_S : OpCodes.Brtrue, label); } else { il.Emit(shortForm ? OpCodes.Beq_S : OpCodes.Beq, label); } } return; } if (this.metaData is MethodInfo) { MethodInfo oper = (MethodInfo)this.metaData; ParameterInfo[] pars = oper.GetParameters(); this.operand1.TranslateToIL(il, pars[0].ParameterType); this.operand2.TranslateToIL(il, pars[1].ParameterType); il.Emit(OpCodes.Call, oper); if (branchIfTrue) { il.Emit(shortForm ? OpCodes.Brtrue_S : OpCodes.Brtrue, label); } else { il.Emit(shortForm ? OpCodes.Brfalse_S : OpCodes.Brfalse, label); } return; } //Getting here is just too bad. We do not know until the code runs whether or not to call an overloaded operator method. //Compile operands to objects and devolve the decision making to run time thunks il.Emit(OpCodes.Ldloc, (LocalBuilder)this.metaData); this.operand1.TranslateToIL(il, Typeob.Object); this.operand2.TranslateToIL(il, Typeob.Object); il.Emit(OpCodes.Call, CompilerGlobals.evaluateEqualityMethod); if (branchIfTrue) { if (this.operatorTok == JSToken.Equal) { il.Emit(shortForm ? OpCodes.Brtrue_S : OpCodes.Brtrue, label); } else { il.Emit(shortForm ? OpCodes.Brfalse_S : OpCodes.Brfalse, label); } } else { if (this.operatorTok == JSToken.Equal) { il.Emit(shortForm ? OpCodes.Brfalse_S : OpCodes.Brfalse, label); } else { il.Emit(shortForm ? OpCodes.Brtrue_S : OpCodes.Brtrue, label); } } return; }