mirror of
https://github.com/SSCLI/sscli_20021101
synced 2026-06-08 12:28:57 +00:00
9fa3874800
Moved the original file to the archive subfolder.
606 lines
21 KiB
C#
606 lines
21 KiB
C#
// ==++==
|
|
//
|
|
//
|
|
// Copyright (c) 2002 Microsoft Corporation. All rights reserved.
|
|
//
|
|
// The use and distribution terms for this software are contained in the file
|
|
// named license.txt, which can be found in the root of this distribution.
|
|
// By using this software in any fashion, you are agreeing to be bound by the
|
|
// terms of this license.
|
|
//
|
|
// You must not remove this notice, or any other, from this software.
|
|
//
|
|
//
|
|
// ==--==
|
|
namespace Microsoft.JScript
|
|
{
|
|
|
|
using System;
|
|
using System.Reflection;
|
|
using System.Reflection.Emit;
|
|
using System.Diagnostics;
|
|
|
|
public sealed class BitwiseBinary : BinaryOp{
|
|
private Object metaData = null;
|
|
|
|
internal BitwiseBinary(Context context, AST operand1, AST operand2, JSToken operatorTok)
|
|
: base(context, operand1, operand2, operatorTok) {
|
|
}
|
|
|
|
public BitwiseBinary(int operatorTok)
|
|
: base(null, null, null, (JSToken)operatorTok){
|
|
}
|
|
|
|
internal override Object Evaluate(){
|
|
return this.EvaluateBitwiseBinary(this.operand1.Evaluate(), this.operand2.Evaluate());
|
|
}
|
|
|
|
#if !DEBUG
|
|
[DebuggerStepThroughAttribute]
|
|
[DebuggerHiddenAttribute]
|
|
#endif
|
|
public Object EvaluateBitwiseBinary(Object v1, Object v2){
|
|
if (v1 is Int32 && v2 is Int32)
|
|
return DoOp((Int32)v1, (Int32)v2, this.operatorTok);
|
|
else
|
|
return EvaluateBitwiseBinary(v1, v2, this.operatorTok);
|
|
}
|
|
|
|
#if !DEBUG
|
|
[DebuggerStepThroughAttribute]
|
|
[DebuggerHiddenAttribute]
|
|
#endif
|
|
private Object EvaluateBitwiseBinary(Object v1, Object v2, JSToken operatorTok){
|
|
IConvertible ic1 = Convert.GetIConvertible(v1);
|
|
IConvertible ic2 = Convert.GetIConvertible(v2);
|
|
TypeCode t1 = Convert.GetTypeCode(v1, ic1);
|
|
TypeCode t2 = Convert.GetTypeCode(v2, ic2);
|
|
switch (t1){
|
|
case TypeCode.Empty:
|
|
case TypeCode.DBNull:
|
|
return EvaluateBitwiseBinary(0, v2, operatorTok);
|
|
|
|
case TypeCode.Boolean:
|
|
case TypeCode.Char:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
int i = ic1.ToInt32(null);
|
|
switch (t2){
|
|
case TypeCode.Empty:
|
|
case TypeCode.DBNull:
|
|
return DoOp(i, 0, operatorTok);
|
|
case TypeCode.Boolean:
|
|
case TypeCode.Char:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
return DoOp(i, ic2.ToInt32(null), operatorTok);
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
return DoOp(i, (int)(long)ic2.ToDouble(null), operatorTok);
|
|
case TypeCode.Object:
|
|
case TypeCode.Decimal:
|
|
case TypeCode.DateTime:
|
|
case TypeCode.String:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
i = (int)(long)ic1.ToDouble(null);
|
|
switch (t2){
|
|
case TypeCode.Empty:
|
|
case TypeCode.DBNull:
|
|
return DoOp(i, 0, operatorTok);
|
|
case TypeCode.Boolean:
|
|
case TypeCode.Char:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
return DoOp(i, ic2.ToInt32(null), operatorTok);
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
return DoOp(i, (int)(long)ic2.ToDouble(null), operatorTok);
|
|
case TypeCode.Object:
|
|
case TypeCode.Decimal:
|
|
case TypeCode.DateTime:
|
|
case TypeCode.String:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Object:
|
|
case TypeCode.Decimal:
|
|
case TypeCode.DateTime:
|
|
case TypeCode.String:
|
|
break;
|
|
}
|
|
if (v2 == null) return DoOp(Convert.ToInt32(v1), 0, this.operatorTok);
|
|
MethodInfo oper = this.GetOperator(v1.GetType(), v2.GetType());
|
|
if (oper != null)
|
|
return oper.Invoke(null, (BindingFlags)0, JSBinder.ob, new Object[]{v1, v2}, null);
|
|
else
|
|
return DoOp(Convert.ToInt32(v1), Convert.ToInt32(v2), this.operatorTok);
|
|
}
|
|
|
|
internal static Object DoOp(int i, int j, JSToken operatorTok){
|
|
switch (operatorTok){
|
|
case JSToken.BitwiseAnd:
|
|
return i & j;
|
|
case JSToken.BitwiseOr:
|
|
return i | j;
|
|
case JSToken.BitwiseXor:
|
|
return i ^ j;
|
|
case JSToken.LeftShift:
|
|
return i << j;
|
|
case JSToken.RightShift:
|
|
return i >> j;
|
|
case JSToken.UnsignedRightShift:
|
|
return ((uint)i) >> j;
|
|
default:
|
|
throw new JScriptException(JSError.InternalError);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
return BitwiseBinary.ResultType(this.type1, this.type2, this.operatorTok);
|
|
}
|
|
|
|
internal static Type Operand2Type(JSToken operatorTok, Type bbrType){
|
|
switch (operatorTok){
|
|
case JSToken.LeftShift:
|
|
case JSToken.RightShift:
|
|
case JSToken.UnsignedRightShift:
|
|
return Typeob.Int32;
|
|
}
|
|
return bbrType;
|
|
}
|
|
|
|
internal static Type ResultType(Type type1, Type type2, JSToken operatorTok){
|
|
switch (operatorTok){
|
|
case JSToken.LeftShift:
|
|
case JSToken.RightShift:
|
|
if (Convert.IsPrimitiveIntegerType(type1))
|
|
return type1;
|
|
else if (Typeob.JSObject.IsAssignableFrom(type1))
|
|
return Typeob.Int32;
|
|
else
|
|
return Typeob.Object;
|
|
case JSToken.UnsignedRightShift:
|
|
switch(Type.GetTypeCode(type1)){
|
|
case TypeCode.Byte:
|
|
case TypeCode.SByte: return Typeob.Byte;
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int16: return Typeob.UInt16;
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32: return Typeob.UInt32;
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64: return Typeob.UInt64;
|
|
default:
|
|
if (Typeob.JSObject.IsAssignableFrom(type1))
|
|
return Typeob.Int32;
|
|
else
|
|
return Typeob.Object;
|
|
}
|
|
}
|
|
TypeCode t1 = Type.GetTypeCode(type1);
|
|
TypeCode t2 = Type.GetTypeCode(type2);
|
|
switch (t1){
|
|
case TypeCode.Empty:
|
|
case TypeCode.DBNull:
|
|
case TypeCode.Boolean:
|
|
switch (t2){
|
|
case TypeCode.SByte:
|
|
return Typeob.SByte;
|
|
case TypeCode.Byte:
|
|
return Typeob.Byte;
|
|
case TypeCode.Char:
|
|
case TypeCode.UInt16:
|
|
return Typeob.UInt16;
|
|
case TypeCode.Int16:
|
|
return Typeob.Int16;
|
|
case TypeCode.Empty:
|
|
case TypeCode.DBNull:
|
|
case TypeCode.Boolean:
|
|
case TypeCode.Int32:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
return Typeob.Int32;
|
|
case TypeCode.UInt32:
|
|
return Typeob.UInt32;
|
|
case TypeCode.Int64:
|
|
return Typeob.Int64;
|
|
case TypeCode.UInt64:
|
|
return Typeob.UInt64;
|
|
case TypeCode.Object:
|
|
if (Typeob.JSObject.IsAssignableFrom(type2)) return Typeob.Int32;
|
|
break;
|
|
case TypeCode.Decimal:
|
|
case TypeCode.DateTime:
|
|
case TypeCode.String:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.SByte:
|
|
switch (t2){
|
|
case TypeCode.Empty:
|
|
case TypeCode.DBNull:
|
|
case TypeCode.Boolean:
|
|
case TypeCode.SByte:
|
|
return Typeob.SByte;
|
|
case TypeCode.Byte:
|
|
return Typeob.Byte;
|
|
case TypeCode.Char:
|
|
case TypeCode.Int16:
|
|
return Typeob.Int16;
|
|
case TypeCode.UInt16:
|
|
return Typeob.UInt16;
|
|
case TypeCode.Int32:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
return Typeob.Int32;
|
|
case TypeCode.UInt32:
|
|
return Typeob.UInt32;
|
|
case TypeCode.Int64:
|
|
return Typeob.Int64;
|
|
case TypeCode.UInt64:
|
|
return Typeob.UInt64;
|
|
case TypeCode.Object:
|
|
if (Typeob.JSObject.IsAssignableFrom(type2)) return Typeob.Int32;
|
|
break;
|
|
case TypeCode.Decimal:
|
|
case TypeCode.DateTime:
|
|
case TypeCode.String:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Byte:
|
|
switch (t2){
|
|
case TypeCode.Empty:
|
|
case TypeCode.DBNull:
|
|
case TypeCode.Boolean:
|
|
case TypeCode.Byte:
|
|
case TypeCode.SByte:
|
|
return Typeob.Byte;
|
|
case TypeCode.Char:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int16:
|
|
return Typeob.UInt16;
|
|
case TypeCode.Int32:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
case TypeCode.UInt32:
|
|
return Typeob.UInt32;
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
return Typeob.UInt64;
|
|
case TypeCode.Object:
|
|
if (Typeob.JSObject.IsAssignableFrom(type2)) return Typeob.UInt32;
|
|
break;
|
|
case TypeCode.Decimal:
|
|
case TypeCode.DateTime:
|
|
case TypeCode.String:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Int16:
|
|
switch (t2){
|
|
case TypeCode.Empty:
|
|
case TypeCode.DBNull:
|
|
case TypeCode.Boolean:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Int16:
|
|
return Typeob.Int16;
|
|
case TypeCode.Byte:
|
|
case TypeCode.Char:
|
|
case TypeCode.UInt16:
|
|
return Typeob.UInt16;
|
|
case TypeCode.Int32:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
return Typeob.Int32;
|
|
case TypeCode.UInt32:
|
|
return Typeob.UInt32;
|
|
case TypeCode.Int64:
|
|
return Typeob.Int64;
|
|
case TypeCode.UInt64:
|
|
return Typeob.UInt64;
|
|
case TypeCode.Object:
|
|
if (Typeob.JSObject.IsAssignableFrom(type2)) return Typeob.Int32;
|
|
break;
|
|
case TypeCode.Decimal:
|
|
case TypeCode.DateTime:
|
|
case TypeCode.String:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Char:
|
|
case TypeCode.UInt16:
|
|
switch (t2){
|
|
case TypeCode.Empty:
|
|
case TypeCode.DBNull:
|
|
case TypeCode.Boolean:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Char:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Int16:
|
|
return Typeob.UInt16;
|
|
case TypeCode.Int32:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
case TypeCode.UInt32:
|
|
return Typeob.UInt32;
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
return Typeob.UInt64;
|
|
case TypeCode.Object:
|
|
if (Typeob.JSObject.IsAssignableFrom(type2)) return Typeob.UInt32;
|
|
break;
|
|
case TypeCode.Decimal:
|
|
case TypeCode.DateTime:
|
|
case TypeCode.String:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Int32:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
switch (t2){
|
|
case TypeCode.Empty:
|
|
case TypeCode.DBNull:
|
|
case TypeCode.Boolean:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
return Typeob.Int32;
|
|
case TypeCode.Byte:
|
|
case TypeCode.Char:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.UInt32:
|
|
return Typeob.UInt32;
|
|
case TypeCode.Int64:
|
|
return Typeob.Int64;
|
|
case TypeCode.UInt64:
|
|
return Typeob.UInt64;
|
|
case TypeCode.Object:
|
|
if (Typeob.JSObject.IsAssignableFrom(type2)) return Typeob.Int32;
|
|
break;
|
|
case TypeCode.Decimal:
|
|
case TypeCode.DateTime:
|
|
case TypeCode.String:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.UInt32:
|
|
switch (t2){
|
|
case TypeCode.Empty:
|
|
case TypeCode.DBNull:
|
|
case TypeCode.Boolean:
|
|
case TypeCode.Byte:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Char:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
return Typeob.UInt32;
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
return Typeob.UInt64;
|
|
case TypeCode.Object:
|
|
if (Typeob.JSObject.IsAssignableFrom(type2)) return Typeob.UInt32;
|
|
break;
|
|
case TypeCode.Decimal:
|
|
case TypeCode.DateTime:
|
|
case TypeCode.String:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Int64:
|
|
switch (t2){
|
|
case TypeCode.Empty:
|
|
case TypeCode.DBNull:
|
|
case TypeCode.Boolean:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.Int64:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
return Typeob.Int64;
|
|
case TypeCode.Byte:
|
|
case TypeCode.Char:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.UInt64:
|
|
return Typeob.UInt64;
|
|
case TypeCode.Object:
|
|
if (Typeob.JSObject.IsAssignableFrom(type2)) return Typeob.Int64;
|
|
break;
|
|
case TypeCode.Decimal:
|
|
case TypeCode.DateTime:
|
|
case TypeCode.String:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.UInt64:
|
|
switch (t2){
|
|
case TypeCode.Empty:
|
|
case TypeCode.DBNull:
|
|
case TypeCode.Boolean:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Char:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.UInt64:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
case TypeCode.Int64:
|
|
return Typeob.UInt64;
|
|
case TypeCode.Object:
|
|
if (Typeob.JSObject.IsAssignableFrom(type2)) return Typeob.UInt64;
|
|
break;
|
|
case TypeCode.Decimal:
|
|
case TypeCode.DateTime:
|
|
case TypeCode.String:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Object:
|
|
if (Typeob.JSObject.IsAssignableFrom(type1)) return Typeob.Int32;
|
|
break;
|
|
|
|
case TypeCode.Decimal:
|
|
case TypeCode.DateTime:
|
|
case TypeCode.String:
|
|
break;
|
|
}
|
|
return Typeob.Object;
|
|
}
|
|
|
|
internal static void TranslateToBitCountMask(ILGenerator il, Type type, AST operand2){
|
|
int mask = 0;
|
|
switch (Type.GetTypeCode(type)){
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
mask = 7; break;
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int16:
|
|
mask = 15; break;
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
mask = 31; break;
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
mask = 63; break;
|
|
}
|
|
ConstantWrapper cw = operand2 as ConstantWrapper;
|
|
if (cw != null){
|
|
int m = Convert.ToInt32(cw.value);
|
|
if (m <= mask) return;
|
|
}
|
|
il.Emit(OpCodes.Ldc_I4_S, mask);
|
|
il.Emit(OpCodes.And);
|
|
}
|
|
|
|
internal override void TranslateToIL(ILGenerator il, Type rtype){
|
|
if (this.metaData == null){
|
|
Type bbrType = BitwiseBinary.ResultType(this.type1, this.type2, this.operatorTok);
|
|
if (Convert.IsPrimitiveNumericType(this.type1)){
|
|
this.operand1.TranslateToIL(il, this.type1);
|
|
Convert.Emit(this, il, this.type1, bbrType, true);
|
|
}else{
|
|
this.operand1.TranslateToIL(il, Typeob.Double);
|
|
Convert.Emit(this, il, Typeob.Double, bbrType, true);
|
|
}
|
|
Type op2type = BitwiseBinary.Operand2Type(this.operatorTok, bbrType);
|
|
if (Convert.IsPrimitiveNumericType(this.type2)){
|
|
this.operand2.TranslateToIL(il, this.type2);
|
|
Convert.Emit(this, il, this.type2, op2type, true);
|
|
}else{
|
|
this.operand2.TranslateToIL(il, Typeob.Double);
|
|
Convert.Emit(this, il, Typeob.Double, op2type, true);
|
|
}
|
|
switch (this.operatorTok){
|
|
case JSToken.BitwiseAnd:
|
|
il.Emit(OpCodes.And);
|
|
break;
|
|
case JSToken.BitwiseOr:
|
|
il.Emit(OpCodes.Or);
|
|
break;
|
|
case JSToken.BitwiseXor:
|
|
il.Emit(OpCodes.Xor);
|
|
break;
|
|
case JSToken.LeftShift:
|
|
BitwiseBinary.TranslateToBitCountMask(il, bbrType, this.operand2);
|
|
il.Emit(OpCodes.Shl);
|
|
break;
|
|
case JSToken.RightShift:
|
|
BitwiseBinary.TranslateToBitCountMask(il, bbrType, this.operand2);
|
|
il.Emit(OpCodes.Shr);
|
|
break;
|
|
case JSToken.UnsignedRightShift:
|
|
BitwiseBinary.TranslateToBitCountMask(il, bbrType, this.operand2);
|
|
il.Emit(OpCodes.Shr_Un);
|
|
break;
|
|
default:
|
|
throw new JScriptException(JSError.InternalError, this.context);
|
|
}
|
|
Convert.Emit(this, il, bbrType, 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.evaluateBitwiseBinaryMethod);
|
|
Convert.Emit(this, il, Typeob.Object, rtype);
|
|
}
|
|
|
|
internal override void TranslateToILInitializer(ILGenerator il){
|
|
IReflect rtype = this.InferType(null);
|
|
this.operand1.TranslateToILInitializer(il);
|
|
this.operand2.TranslateToILInitializer(il);
|
|
if (rtype != Typeob.Object)
|
|
return;
|
|
this.metaData = il.DeclareLocal(typeof(BitwiseBinary));
|
|
ConstantWrapper.TranslateToILInt(il, (int)this.operatorTok);
|
|
il.Emit(OpCodes.Newobj, CompilerGlobals.bitwiseBinaryConstructor);
|
|
il.Emit(OpCodes.Stloc, (LocalBuilder)this.metaData);
|
|
}
|
|
}
|
|
}
|