public bool Emit(Expression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { return(EmitInternal((TExpression)node, context, returnDefaultValueLabel, node.Type == typeof(void) ? ResultType.Void : whatReturn, extend, out resultType)); }
public abstract LLVMValueRef Emit(EmittingContext pContext);
protected abstract bool EmitInternal(TExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType);
public LLVMValueRef EmitHeader(EmittingContext pContext) { //Emit header return(pContext.EmitMethodHeader(Name, this, out _name)); }
public override LLVMValueRef Emit(EmittingContext pContext) { throw new NotSupportedException(); }
protected override bool EmitInternal(SwitchExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { GroboIL il = context.Il; var defaultLabel = il.DefineLabel("default"); var caseLabels = new GroboIL.Label[node.Cases.Count]; GroboIL.Label switchValueIsNullLabel = null; for (int index = 0; index < node.Cases.Count; index++) { caseLabels[index] = il.DefineLabel("case#" + index); } context.EmitLoadArguments(node.SwitchValue); using (var switchValue = context.DeclareLocal(node.SwitchValue.Type)) { il.Stloc(switchValue); Tuple <int, int, int> switchCase; if (context.ParsedLambda.ParsedSwitches.TryGetValue(node, out switchCase)) { // use simplified hashtable to locate the proper case var labels = new List <GroboIL.Label>(); for (int index = 0; index < node.Cases.Count; index++) { foreach (var testValue in node.Cases[index].TestValues) { if (((ConstantExpression)testValue).Value != null) { labels.Add(caseLabels[index]); } else { switchValueIsNullLabel = caseLabels[index]; } } } if (switchValueIsNullLabel != null) { if (!node.SwitchValue.Type.IsNullable()) { il.Ldloc(switchValue); } else { il.Ldloca(switchValue); context.EmitHasValueAccess(node.SwitchValue.Type); } il.Brfalse(switchValueIsNullLabel); } EmittingContext.LocalHolder pureSwitchValue = switchValue; if (node.SwitchValue.Type.IsNullable()) { pureSwitchValue = context.DeclareLocal(node.SwitchValue.Type.GetGenericArguments()[0]); il.Ldloca(switchValue); context.EmitValueAccess(node.SwitchValue.Type); il.Stloc(pureSwitchValue); } Type temp; ExpressionEmittersCollection.Emit(context.ParsedLambda.ConstantsBuilder.MakeAccess(context.ParsedLambda.ConstantsParameter, switchCase.Item1), context, out temp); var type = node.SwitchValue.Type.IsNullable() ? node.SwitchValue.Type.GetGenericArguments()[0] : node.SwitchValue.Type; var typeCode = Type.GetTypeCode(type); switch (typeCode) { case TypeCode.Byte: case TypeCode.Char: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: case TypeCode.SByte: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: il.Ldloc(pureSwitchValue); break; default: if (type.IsValueType) { il.Ldloca(pureSwitchValue); } else { il.Ldloc(pureSwitchValue); } il.Call(typeof(object).GetMethod("GetHashCode"), type); break; } using (var index = context.DeclareLocal(typeof(int))) { if (typeCode == TypeCode.Int64 || typeCode == TypeCode.UInt64) { il.Ldc_I8(switchCase.Item3); } else { il.Ldc_I4(switchCase.Item3); } il.Rem(true); if (typeCode == TypeCode.Int64 || typeCode == TypeCode.UInt64) { il.Conv <int>(); } il.Stloc(index); il.Ldloc(index); il.Ldelem(type); il.Ldloc(pureSwitchValue); if (node.Comparison != null) { il.Call(node.Comparison); } else { il.Ceq(); } il.Brfalse(defaultLabel); ExpressionEmittersCollection.Emit(context.ParsedLambda.ConstantsBuilder.MakeAccess(context.ParsedLambda.ConstantsParameter, switchCase.Item2), context, out temp); il.Ldloc(index); il.Ldelem(typeof(int)); il.Switch(labels.ToArray()); } if (pureSwitchValue != switchValue) { pureSwitchValue.Dispose(); } } else { // use a number of if/else branches to locate the proper case EmittingContext.LocalHolder pureSwitchValue = switchValue; EmittingContext.LocalHolder switchValueIsNull = null; if (node.SwitchValue.Type.IsNullable()) { pureSwitchValue = context.DeclareLocal(node.SwitchValue.Type.GetGenericArguments()[0]); switchValueIsNull = context.DeclareLocal(typeof(bool)); il.Ldloca(switchValue); il.Dup(); context.EmitValueAccess(node.SwitchValue.Type); il.Stloc(pureSwitchValue); context.EmitHasValueAccess(node.SwitchValue.Type); il.Stloc(switchValueIsNull); } for (int index = 0; index < node.Cases.Count; index++) { var caSe = node.Cases[index]; var label = caseLabels[index]; foreach (var testValue in caSe.TestValues) { context.EmitLoadArguments(testValue); GroboIL.Label elseLabel = null; if (testValue.Type.IsNullable()) { elseLabel = il.DefineLabel("else"); using (var temp = context.DeclareLocal(testValue.Type)) { il.Stloc(temp); il.Ldloca(temp); context.EmitHasValueAccess(testValue.Type); if (switchValueIsNull != null) { il.Ldloc(switchValueIsNull); il.Or(); il.Brfalse(label); il.Ldloca(temp); context.EmitHasValueAccess(testValue.Type); il.Ldloc(switchValueIsNull); il.And(); } il.Brfalse(elseLabel); il.Ldloca(temp); context.EmitValueAccess(testValue.Type); } } il.Ldloc(pureSwitchValue); if (node.Comparison != null) { il.Call(node.Comparison); } else { il.Ceq(); } il.Brtrue(label); if (elseLabel != null) { context.MarkLabelAndSurroundWithSP(elseLabel); } } } } } context.MarkLabelAndSurroundWithSP(defaultLabel); var doneLabel = il.DefineLabel("done"); context.EmitLoadArguments(node.DefaultBody); il.Br(doneLabel); for (int index = 0; index < node.Cases.Count; ++index) { context.MarkLabelAndSurroundWithSP(caseLabels[index]); context.EmitLoadArguments(node.Cases[index].Body); if (index < node.Cases.Count - 1) { il.Br(doneLabel); } } context.MarkLabelAndSurroundWithSP(doneLabel); resultType = node.Type; return(false); }
public override LLVMValueRef Emit(EmittingContext pContext) { pContext.EmitDebugLocation(this); NamespaceSyntax ns = null; IdentifierSyntax access = Identifier; if (Identifier.SyntaxType == SyntaxType.Namespace) { ns = (NamespaceSyntax)Identifier; access = Value; } //Check if this is a "static" method if (!pContext.Cache.IsTypeDefined(ns, access.Value) || Value.SyntaxType == SyntaxType.MethodCall) { LLVMValueRef value; if (Identifier.SyntaxType == SyntaxType.Namespace) { value = Value.Emit(pContext); //Terminal nodes are fully emitted in their child most node if (IsTerminalNode(Value)) { value = AccessStack <MemberAccess> .BuildGetElementPtr(pContext, value); } } else { LLVMValueRef identifier = Identifier.Emit(pContext); //For every method call we need to stop and allocate a new variable //This is because our method call is going to return a value, but we need a pointer. //To solve this we allocate a temporary variable, store the value, and continue if (Identifier.SyntaxType == SyntaxType.MethodCall) { var tempVar = pContext.AllocateVariable("memberaccess_temp", Identifier.Type); LLVM.BuildStore(pContext.Builder, identifier, tempVar); identifier = tempVar; pContext.AccessStack.Clear(); } //Store the index we pushed at. //We will later pop only if that index still exists //This allows things like MethodCalls to wipe the stack (because the arguments aren't in the same stack) while still properly popping values var index = pContext.AccessStack.Push(new MemberAccess(identifier, Identifier.Type)); value = Value.Emit(pContext); //Terminal nodes are fully emitted in their child most node if (IsTerminalNode(Value)) { value = AccessStack <MemberAccess> .BuildGetElementPtr(pContext, value); } pContext.AccessStack.PopFrom(index); } return(value); } else { //Only this way while fields are allow to be accessed if (access.Type.IsEnum) { int i = 0; if (access.SyntaxType == SyntaxType.MemberAccess) { i = access.Type.GetEnumValue(((MemberAccessSyntax)access).Value.Value); } else { i = access.Type.GetEnumValue(Value.Value); } return(pContext.GetInt(i)); } throw new NotSupportedException("Only static fields on Enums are supported"); } }
public static bool Emit(Expression zarr, Expression zindex, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { var arrayType = zarr.Type; var isArray = arrayType.IsArray; if (!isArray && !arrayType.IsList()) { throw new InvalidOperationException("Unable to perform array index operator to type '" + arrayType + "'"); } var itemType = isArray ? arrayType.GetElementType() : arrayType.GetGenericArguments()[0]; GroboIL il = context.Il; EmittingContext.LocalHolder arrayIndex = null; bool extendArray = extend && (CanAssign(zarr) || !isArray); bool extendArrayElement = extend && itemType.IsClass; var result = false; if (!extendArray) { result |= ExpressionEmittersCollection.Emit(zarr, context, returnDefaultValueLabel, ResultType.Value, extend, out arrayType); // stack: [array] if (context.Options.HasFlag(CompilerOptions.CheckNullReferences)) { result = true; il.Dup(); // stack: [array, array] il.Brfalse(returnDefaultValueLabel); // if(array == null) goto returnDefaultValue; stack: [array] } EmitLoadIndex(zindex, context, arrayType); // stack: [array, arrayIndex] if (context.Options.HasFlag(CompilerOptions.CheckArrayIndexes)) { result = true; arrayIndex = context.DeclareLocal(typeof(int)); il.Stloc(arrayIndex); // arrayIndex = index; stack: [array] il.Dup(); // stack: [array, array] if (isArray) { il.Ldlen(); // stack: [array, array.Length] } else { EmitLoadField(context, arrayType, arrayType.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); } il.Ldloc(arrayIndex); // stack: [array, array.Length, arrayIndex] il.Ble(returnDefaultValueLabel, false); // if(array.Length <= arrayIndex) goto returnDefaultValue; stack: [array] il.Ldloc(arrayIndex); // stack: [array, arrayIndex] il.Ldc_I4(0); // stack: [array, arrayIndex, 0] il.Blt(returnDefaultValueLabel, false); // if(arrayIndex < 0) goto returnDefaultValue; stack: [array] } else if (extendArrayElement || !isArray) { arrayIndex = context.DeclareLocal(typeof(int)); il.Stloc(arrayIndex); // arrayIndex = index; stack: [array] } } else { EmittingContext.LocalHolder arrayOwner = null; switch (zarr.NodeType) { case ExpressionType.Parameter: case ExpressionType.ArrayIndex: case ExpressionType.Index: Type type; ExpressionEmittersCollection.Emit(zarr, context, returnDefaultValueLabel, ResultType.ByRefAll, true, out type); // stack: [ref array] arrayOwner = context.DeclareLocal(type); il.Dup(); // stack: [ref array, ref array] il.Stloc(arrayOwner); // arrayOwner = ref array; stack: [ref array] il.Ldind(zarr.Type); // stack: [array] break; case ExpressionType.MemberAccess: var memberExpression = (MemberExpression)zarr; Type memberType; context.EmitMemberAccess(memberExpression, returnDefaultValueLabel, context.Options.HasFlag(CompilerOptions.CheckNullReferences), true, ResultType.ByRefValueTypesOnly, out memberType, out arrayOwner); // stack: [array] break; default: throw new InvalidOperationException("Cannot extend array for expression with node type '" + zarr.NodeType + "'"); } if (context.Options.HasFlag(CompilerOptions.CheckNullReferences)) { il.Dup(); // stack: [array, array] il.Brfalse(returnDefaultValueLabel); // if(array == null) goto returnDefaultValue; stack: [array] } EmitLoadIndex(zindex, context, arrayType); result = true; arrayIndex = context.DeclareLocal(typeof(int)); il.Stloc(arrayIndex); // arrayIndex = index; stack: [array] il.Ldloc(arrayIndex); // stack: [array, arrayIndex] il.Ldc_I4(0); // stack: [array, arrayIndex, 0] il.Blt(returnDefaultValueLabel, false); // if(arrayIndex < 0) goto returnDefaultValue; stack: [array] il.Dup(); // stack: [array, array] if (isArray) { il.Ldlen(); // stack: [array, array.Length] } else { EmitLoadField(context, arrayType, arrayType.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); } il.Ldloc(arrayIndex); // stack: [array, array.Length, arrayIndex] var bigEnoughLabel = il.DefineLabel("bigEnough"); il.Bgt(bigEnoughLabel, false); // if(array.Length > arrayIndex) goto bigEnough; stack: [array] using (var array = context.DeclareLocal(arrayType)) { il.Stloc(array); // stack: [] if (!isArray) { EnsureCount(context, array, arrayIndex, arrayType); } else { il.Ldloca(array); // stack: [ref array] il.Ldloc(arrayIndex); // stack: [ref array, arrayIndex] il.Ldc_I4(1); // stack: [ref array, arrayIndex, 1] il.Add(); // stack: [ref array, arrayIndex + 1] il.Call(arrayResizeMethod.MakeGenericMethod(arrayType.GetElementType())); // Array.Resize(ref array, 1 + arrayIndex); stack: [] switch (zarr.NodeType) { case ExpressionType.Parameter: case ExpressionType.ArrayIndex: case ExpressionType.Index: il.Ldloc(arrayOwner); // stack: [ref parameter] il.Ldloc(array); // stack: [ref parameter, array] il.Stind(arrayType); // parameter = array; stack: [] break; case ExpressionType.MemberAccess: var memberExpression = (MemberExpression)zarr; if (memberExpression.Expression != null) { il.Ldloc(arrayOwner); } il.Ldloc(array); switch (memberExpression.Member.MemberType) { case MemberTypes.Field: il.Stfld((FieldInfo)memberExpression.Member); break; case MemberTypes.Property: var propertyInfo = (PropertyInfo)memberExpression.Member; var setter = propertyInfo.GetSetMethod(context.SkipVisibility); if (setter == null) { throw new MissingMethodException(propertyInfo.ReflectedType.ToString(), "set_" + propertyInfo.Name); } il.Call(setter, memberExpression.Expression == null ? null : memberExpression.Expression.Type); break; default: throw new NotSupportedException("Member type '" + memberExpression.Member.MemberType + "' is not supported"); } break; default: throw new InvalidOperationException("Unable to assign array to an expression with node type '" + zarr.NodeType); } } il.Ldloc(array); context.MarkLabelAndSurroundWithSP(bigEnoughLabel); } } if (!isArray) { // TODO: это злобно, лист при всех операциях меняет _version, а мы нет EmitLoadField(context, arrayType, arrayType.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); arrayType = itemType.MakeArrayType(); } if (extendArrayElement) { // stack: [array] var constructor = itemType.GetConstructor(Type.EmptyTypes); if (itemType.IsArray || constructor != null) { using (var array = context.DeclareLocal(arrayType)) { il.Dup(); // stack: [array, array] il.Stloc(array); // stack: [array] il.Ldloc(arrayIndex); // stack: [array, arrayIndex] il.Ldelem(itemType); // stack: [array[arrayIndex]] var elementIsNotNullLabel = il.DefineLabel("elementIsNotNull"); il.Brtrue(elementIsNotNullLabel); il.Ldloc(array); il.Ldloc(arrayIndex); context.Create(itemType); il.Stelem(itemType); context.MarkLabelAndSurroundWithSP(elementIsNotNullLabel); il.Ldloc(array); } } } if (arrayIndex != null) { il.Ldloc(arrayIndex); arrayIndex.Dispose(); } switch (whatReturn) { case ResultType.ByRefAll: il.Ldelema(itemType); resultType = itemType.MakeByRefType(); break; case ResultType.ByRefValueTypesOnly: if (itemType.IsValueType) { il.Ldelema(itemType); resultType = itemType.MakeByRefType(); } else { il.Ldelem(itemType); // stack: [array[arrayIndex]] resultType = itemType; } break; default: il.Ldelem(itemType); // stack: [array[arrayIndex]] resultType = itemType; break; } return(result); }
public static TryGetValueDelegate <T> Build <T>(char[] keys, T[] values, int numberOfSegments, int numberOfKeysPerSegment) { // Assuming keys are sorted var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(bool), new[] { typeof(Closure <T>), typeof(char), typeof(T).MakeByRefType() }, typeof(string), true); var indices = new List <int>(); using (var il = new GroboIL(method)) { var idx = il.DeclareLocal(typeof(int), "idx"); var retFalseLabel = il.DefineLabel("retFalse"); var segments = new Segment[numberOfSegments]; for (int i = 0; i < numberOfSegments; ++i) { var firstKeyInSegment = keys[i * numberOfKeysPerSegment]; var lastKeyInSegment = keys[numberOfKeysPerSegment - 1 + i * numberOfKeysPerSegment]; segments[i] = new Segment { FirstKey = firstKeyInSegment, LastKey = lastKeyInSegment, Diff = firstKeyInSegment - indices.Count }; var segmentLength = lastKeyInSegment - firstKeyInSegment + 1; int start = indices.Count; for (int j = 0; j < segmentLength; ++j) { indices.Add(-1); } for (int j = 0; j < numberOfKeysPerSegment; ++j) { indices[start + keys[i * numberOfKeysPerSegment + j] - firstKeyInSegment] = i * numberOfKeysPerSegment + j; } } var context = new EmittingContext { Il = il, Segments = segments, RetFalseLabel = retFalseLabel, Idx = idx }; DoBinarySearch <T>(context, 0, numberOfSegments - 1); il.MarkLabel(retFalseLabel); il.Ldarg(2); // stack: [ref value] if (typeof(T).IsValueType) { il.Initobj(typeof(T)); // value = default(T); stack: [] } else { il.Ldnull(); // stack: [ref value, null] il.Stind(typeof(T)); // value = null; stack: [] } il.Ldc_I4(0); // stack: [false] il.Ret(); } var closure = new Closure <T> { indices = indices.ToArray(), values = values }; return((TryGetValueDelegate <T>)method.CreateDelegate(typeof(TryGetValueDelegate <T>), closure)); }
protected override bool EmitInternal(UnaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { var il = context.Il; GroboIL.Label operandIsNullLabel = context.CanReturn ? il.DefineLabel("operandIsNull") : null; var operandIsNullLabelUsed = ExpressionEmittersCollection.Emit(node.Operand, context, operandIsNullLabel, ResultType.Value, extend, out resultType); // stack: [obj] if (operandIsNullLabelUsed) { context.EmitReturnDefaultValue(resultType, operandIsNullLabel, il.DefineLabel("operandIsNotNull")); } if (resultType != node.Type && !(context.Options.HasFlag(CompilerOptions.UseTernaryLogic) && resultType == typeof(bool?) && node.Type == typeof(bool))) { if (node.Method != null) { if (!resultType.IsNullable()) { il.Call(node.Method); if (node.Type.IsNullable()) { il.Newobj(node.Type.GetConstructor(new[] { node.Method.ReturnType })); } } else { using (var temp = context.DeclareLocal(resultType)) { il.Stloc(temp); il.Ldloca(temp); il.Dup(); context.EmitHasValueAccess(resultType); var valueIsNullLabel = operandIsNullLabelUsed ? operandIsNullLabel : il.DefineLabel("valueIsNull"); il.Brfalse(valueIsNullLabel); context.EmitValueAccess(resultType); il.Call(node.Method); il.Newobj(node.Type.GetConstructor(new[] { node.Method.ReturnType })); if (!operandIsNullLabelUsed) { context.EmitReturnDefaultValue(node.Type, valueIsNullLabel, il.DefineLabel("valueIsNotNull")); } } } } else { switch (node.NodeType) { case ExpressionType.Convert: context.EmitConvert(resultType, node.Type); // stack: [(type)obj] break; case ExpressionType.ConvertChecked: context.EmitConvert(resultType, node.Type, true); // stack: [(type)obj] break; default: throw new InvalidOperationException("Node type '" + node.NodeType + "' is not valid at this point"); } } resultType = node.Type; } return(false); }
protected override bool EmitInternal(BinaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { return(Emit(node.Left, node.Right, context, returnDefaultValueLabel, whatReturn, extend, out resultType)); }
private void PopulateInterceptor(ToBeWeaved tbw, Instruction fieldAccessInstruction, FieldReference field, MethodDefinition tplMethod) { tplMethod.ReturnType.ReturnType = IsGetter ? field.FieldType : Cil.GetTypeReference(typeof(void)); bool isStaticField = fieldAccessInstruction.OpCode == OpCodes.Stsfld || fieldAccessInstruction.OpCode == OpCodes.Ldsfld; // The target object is already on the stack if we access an instance field if (!isStaticField) { if (field.DeclaringType.IsValueType) { tplMethod.Parameters.Add(new ParameterDefinition(new ReferenceType(field.DeclaringType))); } else { tplMethod.Parameters.Add(new ParameterDefinition(field.DeclaringType)); } } // The value to assign is already on the stack as well if (!IsGetter) { tplMethod.Parameters.Add(new ParameterDefinition(field.FieldType)); } EmittingContext ctx = new EmittingContext(tplMethod); VariableDefinition tmpObj = null; if (!isStaticField) { ctx.Emit(OpCodes.Ldarg_0); // load "this", which is the first parameter of the tplMethod if (field.DeclaringType.IsValueType) { ctx.Emit(OpCodes.Ldobj, field.DeclaringType); ctx.Emit(OpCodes.Box, field.DeclaringType); // Tmp object to store boxed value types when passed along call interceptors and then unwrapped after calls // tmpObj = new VariableDefinition(new ReferenceType(field.DeclaringType)); tmpObj = new VariableDefinition(Cil.GetTypeReference(typeof(object))); tplMethod.Body.Variables.Add(tmpObj); ctx.Emit(OpCodes.Stloc, tmpObj); ctx.Emit(OpCodes.Ldloc, tmpObj); } if (!IsGetter) { ctx.Emit(OpCodes.Ldarg, tplMethod.Parameters[1]); Cil.BoxIfRequired(field.FieldType, ctx); } } else // Static field { if (!IsGetter) { ctx.Emit(OpCodes.Ldarg, tplMethod.Parameters[0]); Cil.BoxIfRequired(field.FieldType, ctx); } } // Pass the field representation as the last parameter ctx.Emit(OpCodes.Ldtoken, field); #if DOTNETTWO ctx.Emit(OpCodes.Ldtoken, field.DeclaringType); ctx.Emit(OpCodes.Call, Cil.GetGenericFieldFromHandle); #else ctx.Emit(OpCodes.Call, Cil.GetFieldFromHandle); #endif // Create the JoinPoint MethodReference joinPointFactory; OpCode opCode = fieldAccessInstruction.OpCode; if (opCode == OpCodes.Stsfld) { joinPointFactory = Cil.StaticFieldSetterJoinPointFactory; } else if (opCode == OpCodes.Ldsfld) { joinPointFactory = Cil.StaticFieldGetterJoinPointFactory; } else if (opCode == OpCodes.Stfld) { joinPointFactory = Cil.FieldSetterJoinPointFactory; } else if (opCode == OpCodes.Ldfld) { joinPointFactory = Cil.FieldGetterJoinPointFactory; } else { throw new NotSupportedException("This kind of field accessor is not supported : " + opCode); } ctx.Emit(OpCodes.Newobj, joinPointFactory); // Add each interceptor foreach (MethodReference aspectMethod in tbw.Interceptors) { ctx.Emit(OpCodes.Ldtoken, Cil.TargetMainModule.Import(aspectMethod)); ctx.Emit(OpCodes.Call, Cil.GetMethodFromHandle); ctx.Emit(OpCodes.Call, Cil.AddInterceptorMethod); } // Invoke "proceed" on the joinpoint ctx.Emit(OpCodes.Call, Cil.ProceedMethod); Cil.UnboxIfRequired(tplMethod.ReturnType.ReturnType, ctx); if (!isStaticField && field.DeclaringType.IsValueType) // Unbox and update "this" { ctx.Emit(OpCodes.Ldarg_0); ctx.Emit(OpCodes.Ldloc, tmpObj); ctx.Emit(OpCodes.Unbox, field.DeclaringType); ctx.Emit(OpCodes.Ldobj, field.DeclaringType); ctx.Emit(OpCodes.Stobj, field.DeclaringType); } // Cast (to satisfy PEVerify) Cil.CastIfRequired(tplMethod.ReturnType.ReturnType, ctx); ctx.Emit(OpCodes.Ret); }
protected override bool EmitInternal(BinaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { GroboIL il = context.Il; if (node.Method != null) { throw new NotSupportedException("Custom operator '" + node.NodeType + "' is not supported"); } Expression left = node.Left; Expression right = node.Right; Type leftType; context.EmitLoadArgument(left, false, out leftType); // stack: [left] if (leftType == typeof(bool)) { switch (node.NodeType) { case ExpressionType.AndAlso: { var returnFalseLabel = il.DefineLabel("returnFalse"); il.Brfalse(returnFalseLabel); // if(left == false) return false; stack: [] Type rightType; context.EmitLoadArgument(right, false, out rightType); // stack: [right] var doneLabel = il.DefineLabel("done"); il.Br(doneLabel); // goto done; stack: [right] context.MarkLabelAndSurroundWithSP(returnFalseLabel); il.Ldc_I4(0); // stack: [false] if (rightType == typeof(bool?)) { il.Newobj(nullableBoolConstructor); // stack: [new bool?(false)] } context.MarkLabelAndSurroundWithSP(doneLabel); resultType = rightType; break; } case ExpressionType.OrElse: { var returnTrueLabel = il.DefineLabel("returnTrue"); il.Brtrue(returnTrueLabel); // if(left == true) return true; stack: [] Type rightType; context.EmitLoadArgument(right, false, out rightType); // stack: [right] var doneLabel = il.DefineLabel("done"); il.Br(doneLabel); // goto done; stack: [right] context.MarkLabelAndSurroundWithSP(returnTrueLabel); il.Ldc_I4(1); // stack: [true] if (rightType == typeof(bool?)) { il.Newobj(nullableBoolConstructor); // stack: [new bool?(true)] } context.MarkLabelAndSurroundWithSP(doneLabel); resultType = rightType; break; } default: throw new NotSupportedException("Node type '" + node.NodeType + "' is not supported"); } } else // bool? { switch (node.NodeType) { case ExpressionType.AndAlso: { /* * +-------+-------+-------+-------+ * | && | null | false | true | * +-------+-------+-------+-------+ * | null | null | false | null | * +-------+-------+-------+-------+ * | false | false | false | false | * +-------+-------+-------+-------+ * | true | null | false | true | * +-------+-------+-------+-------+ */ using (var localLeft = context.DeclareLocal(typeof(bool?))) { il.Stloc(localLeft); // localLeft = left; stack: [] il.Ldloca(localLeft); // stack: [&localLeft] context.EmitHasValueAccess(typeof(bool?)); // stack: [localLeft.HasValue] il.Ldc_I4(1); // stack: [localLeft.HasValue, true] il.Xor(); // stack: [!localLeft.HasValue] il.Ldloca(localLeft); // stack: [!localLeft.HasValue, &localLeft] context.EmitValueAccess(typeof(bool?)); // stack: [!localLeft.HasValue, localLeft.Value] il.Or(); // stack: [!localLeft.HasValue || localLeft.Value] var returnFalseLabel = il.DefineLabel("returnFalse"); il.Brfalse(returnFalseLabel); // if(localLeft == false) goto returnFalse; stack: [] Type rightType; context.EmitLoadArgument(right, false, out rightType); // stack: [right] using (var localRight = context.DeclareLocal(rightType)) { il.Stloc(localRight); // localRight = right; stack: [] if (rightType == typeof(bool)) { il.Ldloc(localRight); // stack: [localRight] } else { il.Ldloca(localRight); // stack: [&localRight] context.EmitHasValueAccess(typeof(bool?)); // stack: [localRight.HasValue] il.Ldc_I4(1); // stack: [localRight.HasValue, true] il.Xor(); // stack: [!localRight.HasValue] il.Ldloca(localRight); // stack: [!localRight.HasValue, &localRight] context.EmitValueAccess(typeof(bool?)); // stack: [!localRight.HasValue, localRight.Value] il.Or(); // stack: [!localRight.HasValue || localRight.Value] } il.Brfalse(returnFalseLabel); // if(localRight == false) goto returnFalse; if (rightType == typeof(bool)) { il.Ldloc(localRight); // stack: [localRight] } else { il.Ldloca(localRight); // stack: [&localRight] context.EmitHasValueAccess(typeof(bool?)); // stack: [localRight.HasValue] il.Ldloca(localRight); // stack: [localRight.HasValue, &localRight] context.EmitValueAccess(typeof(bool?)); // stack: [localRight.HasValue, localRight.Value] il.And(); // stack: [localRight.HasValue && localRight.Value] } var returnLeftLabel = il.DefineLabel("returnLeft"); il.Brtrue(returnLeftLabel); // if(localRight == true) goto returnLeft; il.Ldloca(localLeft); // stack: [&localLeft] il.Initobj(typeof(bool?)); // localLeft = default(bool?); stack: [] context.MarkLabelAndSurroundWithSP(returnLeftLabel); il.Ldloc(localLeft); // stack: [localLeft] var doneLabel = il.DefineLabel("done"); il.Br(doneLabel); context.MarkLabelAndSurroundWithSP(returnFalseLabel); il.Ldc_I4(0); // stack: [false] il.Newobj(nullableBoolConstructor); // new bool?(false) context.MarkLabelAndSurroundWithSP(doneLabel); resultType = typeof(bool?); } } break; } case ExpressionType.OrElse: { /* * +-------+-------+-------+-------+ * | || | null | false | true | * +-------+-------+-------+-------+ * | null | null | null | true | * +-------+-------+-------+-------+ * | false | null | false | true | * +-------+-------+-------+-------+ * | true | true | true | true | * +-------+-------+-------+-------+ */ using (var localLeft = context.DeclareLocal(typeof(bool?))) { il.Stloc(localLeft); // localLeft = left; stack: [] il.Ldloca(localLeft); // stack: [&localLeft] context.EmitHasValueAccess(typeof(bool?)); // stack: [localLeft.HasValue] il.Ldloca(localLeft); // stack: [localLeft.HasValue, &localLeft] context.EmitValueAccess(typeof(bool?)); // stack: [localLeft.HasValue, localLeft.Value] il.And(); // stack: [localLeft.HasValue && localLeft.Value] var returnTrueLabel = il.DefineLabel("returnTrue"); il.Brtrue(returnTrueLabel); // if(localLeft == true) goto returnTrue; stack: [] Type rightType; context.EmitLoadArgument(right, false, out rightType); // stack: [right] using (var localRight = context.DeclareLocal(rightType)) { il.Stloc(localRight); // localRight = right; stack: [] if (rightType == typeof(bool)) { il.Ldloc(localRight); // stack: [localRight] } else { il.Ldloca(localRight); // stack: [&localRight] context.EmitHasValueAccess(typeof(bool?)); // stack: [localRight.HasValue] il.Ldloca(localRight); // stack: [localRight.HasValue, &localRight] context.EmitValueAccess(typeof(bool?)); // stack: [localRight.HasValue, localRight.Value] il.And(); // stack: [localRight.HasValue && localRight.Value] } il.Brtrue(returnTrueLabel); // if(localRight == true) goto returnTrue; stack: [] if (rightType == typeof(bool)) { il.Ldloc(localRight); // stack: [localRight] } else { il.Ldloca(localRight); // stack: [&localRight] context.EmitHasValueAccess(typeof(bool?)); // stack: [localRight.HasValue] il.Ldc_I4(1); // stack: [localRight.HasValue, true] il.Xor(); // stack: [!localRight.HasValue] il.Ldloca(localRight); // stack: [!localRight.HasValue, &localRight] context.EmitValueAccess(typeof(bool?)); // stack: [!localRight.HasValue, localRight.Value] il.Or(); // stack: [!localRight.HasValue || localRight.Value] } var returnLeftLabel = il.DefineLabel("returnLeft"); il.Brfalse(returnLeftLabel); // if(localRight == false) goto returnLeft; il.Ldloca(localLeft); // stack: [&localLeft] il.Initobj(typeof(bool?)); // localLeft = default(bool?); stack: [] context.MarkLabelAndSurroundWithSP(returnLeftLabel); il.Ldloc(localLeft); // stack: [localLeft] var doneLabel = il.DefineLabel("done"); il.Br(doneLabel); context.MarkLabelAndSurroundWithSP(returnTrueLabel); il.Ldc_I4(1); // stack: [true] il.Newobj(nullableBoolConstructor); // new bool?(true) context.MarkLabelAndSurroundWithSP(doneLabel); resultType = typeof(bool?); } } break; } default: throw new NotSupportedException("Node type '" + node.NodeType + "' is not supported"); } } return(false); }
public override LLVMSharp.LLVMValueRef Emit(EmittingContext pContext) { //No generation for type syntax throw new NotImplementedException(); }
protected override bool EmitInternal(BinaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { Expression left = node.Left; Expression right = node.Right; Type leftType, rightType; context.EmitLoadArgument(left, false, out leftType); context.EmitLoadArgument(right, false, out rightType); GroboIL il = context.Il; if (!leftType.IsNullable() && !rightType.IsNullable()) { if (node.Method != null) { il.Call(node.Method); } else { if (leftType.IsStruct() || rightType.IsStruct()) { throw new InvalidOperationException("Cannot compare structs"); } il.Ceq(); if (node.NodeType == ExpressionType.NotEqual) { il.Ldc_I4(1); il.Xor(); } } } else { var type = leftType; if (type != rightType) { throw new InvalidOperationException("Cannot compare objects of different types '" + leftType + "' and '" + rightType + "'"); } using (var localLeft = context.DeclareLocal(type)) using (var localRight = context.DeclareLocal(type)) { il.Stloc(localRight); il.Stloc(localLeft); if (node.Method != null) { il.Ldloca(localLeft); // stack: [&left] context.EmitHasValueAccess(type); // stack: [left.HasValue] il.Dup(); // stack: [left.HasValue, left.HasValue] il.Ldloca(localRight); // stack: [left.HasValue, left.HasValue, &right] context.EmitHasValueAccess(type); // stack: [left.HasValue, left.HasValue, right.HasValue] var notEqualLabel = il.DefineLabel("notEqual"); il.Bne_Un(notEqualLabel); // stack: [left.HasValue] var equalLabel = il.DefineLabel("equal"); il.Brfalse(equalLabel); il.Ldloca(localLeft); context.EmitValueAccess(type); il.Ldloca(localRight); context.EmitValueAccess(type); il.Call(node.Method); var doneLabel = il.DefineLabel("done"); il.Br(doneLabel); context.MarkLabelAndSurroundWithSP(notEqualLabel); il.Pop(); il.Ldc_I4(node.NodeType == ExpressionType.Equal ? 0 : 1); il.Br(doneLabel); context.MarkLabelAndSurroundWithSP(equalLabel); il.Ldc_I4(node.NodeType == ExpressionType.Equal ? 1 : 0); context.MarkLabelAndSurroundWithSP(doneLabel); } else { il.Ldloca(localLeft); context.EmitValueAccess(type); il.Ldloca(localRight); context.EmitValueAccess(type); var notEqualLabel = il.DefineLabel("notEqual"); il.Bne_Un(notEqualLabel); il.Ldloca(localLeft); context.EmitHasValueAccess(type); il.Ldloca(localRight); context.EmitHasValueAccess(type); il.Ceq(); var doneLabel = il.DefineLabel("done"); il.Br(doneLabel); context.MarkLabelAndSurroundWithSP(notEqualLabel); il.Ldc_I4(0); context.MarkLabelAndSurroundWithSP(doneLabel); if (node.NodeType == ExpressionType.NotEqual) { il.Ldc_I4(1); il.Xor(); } } } } resultType = typeof(bool); return(false); }
protected override bool EmitInternal(ParameterExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { if (whatReturn == ResultType.Void) { resultType = typeof(void); return(false); } ConstructorInfo constructor = node.Type.GetConstructor(Type.EmptyTypes); extend &= node != context.ParsedLambda.ClosureParameter && node != context.ParsedLambda.ConstantsParameter && !node.Type.IsStaticClosure() && ((node.Type.IsClass && constructor != null) || node.Type.IsArray); int index = Array.IndexOf(context.Parameters, node); if (index >= 0) { if (extend) { context.Il.Ldarg(index); var parameterIsNotNullLabel = context.Il.DefineLabel("parameterIsNotNull"); context.Il.Brtrue(parameterIsNotNullLabel); context.Il.Ldarga(index); context.Create(node.Type); context.Il.Stind(node.Type); context.MarkLabelAndSurroundWithSP(parameterIsNotNullLabel); } switch (whatReturn) { case ResultType.Value: context.Il.Ldarg(index); // stack: [parameter] resultType = node.Type; break; case ResultType.ByRefAll: context.Il.Ldarga(index); // stack: [¶meter] resultType = node.Type.MakeByRefType(); break; case ResultType.ByRefValueTypesOnly: if (node.Type.IsValueType) { context.Il.Ldarga(index); // stack: [¶meter] resultType = node.Type.MakeByRefType(); } else { context.Il.Ldarg(index); // stack: [parameter] resultType = node.Type; } break; default: throw new NotSupportedException("Result type '" + whatReturn + "' is not supported"); } return(false); } GroboIL.Local variable; if (context.VariablesToLocals.TryGetValue(node, out variable)) { if (extend) { context.Il.Ldloc(variable); var parameterIsNotNullLabel = context.Il.DefineLabel("parameterIsNotNull"); context.Il.Brtrue(parameterIsNotNullLabel); context.Create(node.Type); context.Il.Stloc(variable); context.MarkLabelAndSurroundWithSP(parameterIsNotNullLabel); } switch (whatReturn) { case ResultType.Value: context.Il.Ldloc(variable); // stack: [variable] resultType = node.Type; break; case ResultType.ByRefAll: context.Il.Ldloca(variable); // stack: [&variable] resultType = node.Type.MakeByRefType(); break; case ResultType.ByRefValueTypesOnly: if (node.Type.IsValueType) { context.Il.Ldloca(variable); // stack: [&variable] resultType = node.Type.MakeByRefType(); } else { context.Il.Ldloc(variable); // stack: [variable] resultType = node.Type; } break; default: throw new NotSupportedException("Result type '" + whatReturn + "' is not supported"); } return(false); } throw new InvalidOperationException("Unknown parameter " + node); }
protected override bool EmitInternal(ConstantExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { if (node.Value == null) { context.EmitLoadDefaultValue(node.Type); } else { var typeCode = Type.GetTypeCode(node.Type.IsNullable() ? node.Type.GetGenericArguments()[0] : node.Type); switch (typeCode) { case TypeCode.Boolean: context.Il.Ldc_I4(((bool)node.Value) ? 1 : 0); break; case TypeCode.Byte: context.Il.Ldc_I4((byte)node.Value); break; case TypeCode.Char: context.Il.Ldc_I4((char)node.Value); break; case TypeCode.Int16: context.Il.Ldc_I4((short)node.Value); break; case TypeCode.Int32: context.Il.Ldc_I4((int)node.Value); break; case TypeCode.SByte: context.Il.Ldc_I4((sbyte)node.Value); break; case TypeCode.UInt16: context.Il.Ldc_I4((ushort)node.Value); break; case TypeCode.UInt32: unchecked { context.Il.Ldc_I4((int)(uint)node.Value); } break; case TypeCode.Int64: context.Il.Ldc_I8((long)node.Value); break; case TypeCode.UInt64: unchecked { context.Il.Ldc_I8((long)(ulong)node.Value); } break; case TypeCode.Single: context.Il.Ldc_R4((float)node.Value); break; case TypeCode.Double: context.Il.Ldc_R8((double)node.Value); break; case TypeCode.String: context.Il.Ldstr((string)node.Value); break; default: throw new NotSupportedException("Constant of type '" + node.Type + "' is not supported"); } if (node.Type.IsNullable()) { context.Il.Newobj(node.Type.GetConstructor(new[] { node.Type.GetGenericArguments()[0] })); } } resultType = node.Type; return(false); }
public void Cleanup() { foreach (DictionaryEntry entry in m_InterceptorsToWeave) { MethodDefinition containerMethod = entry.Key as MethodDefinition; TypeDefinition containerType = (TypeDefinition)containerMethod.DeclaringType; // Methods can be removed. In that case, they don't have a declaring type any more if (containerType != null) { // Clone and rename the target method MethodDefinition targetMethod = containerMethod.Clone(); targetMethod.Name += Joinpoints.OperationJoinPoint.WrappedMethodSuffix + "Body_" + Cil.GetNextId(); targetMethod.IsNewSlot = false; targetMethod.IsFinal = false; targetMethod.IsRuntimeSpecialName = targetMethod.IsSpecialName = false; containerType.Methods.Add(targetMethod); // Clear containerMethod containerMethod.Body.InitLocals = true; containerMethod.Body.ExceptionHandlers.Clear(); containerMethod.Body.Variables.Clear(); containerMethod.Body.Instructions.Clear(); // Reify arguments and call interceptors in the original (now target) method EmittingContext ctx = new EmittingContext(containerMethod); VariableDefinition tmpObj = null; if (!Cil.IsStatic(targetMethod)) { ctx.Emit(OpCodes.Ldarg_0); if (targetMethod.DeclaringType.IsValueType) { ctx.Emit(OpCodes.Ldobj, targetMethod.DeclaringType); ctx.Emit(OpCodes.Box, targetMethod.DeclaringType); // Tmp object to store boxed value types when passed along call interceptors and then unwrapped after calls //tmpObj = new VariableDefinition(new ReferenceType(targetMethod.DeclaringType)); tmpObj = new VariableDefinition(Cil.GetTypeReference(typeof(object))); containerMethod.Body.Variables.Add(tmpObj); ctx.Emit(OpCodes.Stloc, tmpObj); ctx.Emit(OpCodes.Ldloc, tmpObj); } } VariableDefinition arrayDef = new VariableDefinition(Cil.GetTypeReference(typeof(object[]))); containerMethod.Body.Variables.Add(arrayDef); ParameterDefinitionCollection containerParameters = containerMethod.Parameters; ParameterDefinitionCollection targetParameters = targetMethod.Parameters; // Instantiate an array of the right size ctx.Emit(OpCodes.Ldc_I4, containerParameters.Count); ctx.Emit(OpCodes.Newarr, Cil.GetTypeReference(typeof(object))); ctx.Emit(OpCodes.Stloc, arrayDef); // Load the array with data coming from the current parameters for (int i = containerParameters.Count - 1; i >= 0; i--) { ParameterDefinition p = containerParameters[i]; ctx.Emit(OpCodes.Ldloc, arrayDef); ctx.Emit(OpCodes.Ldc_I4, i); ctx.Emit(OpCodes.Ldarg, p); Cil.BoxIfRequired(p.ParameterType, ctx); ctx.Emit(OpCodes.Stelem_Ref); } // Pass real parameter values (taken from the stack) as the next parameter ctx.Emit(OpCodes.Ldloc, arrayDef); // end of Reify parameters ArrayList interceptors = entry.Value as ArrayList; Cil.InvokeInterceptors(containerMethod, ctx, targetMethod, interceptors); Cil.UnboxIfRequired(targetMethod.ReturnType.ReturnType, ctx); if (!Cil.IsStatic(targetMethod) && targetMethod.DeclaringType.IsValueType) { ctx.Emit(OpCodes.Ldarg_0); ctx.Emit(OpCodes.Ldloc, tmpObj); Cil.UnboxIfRequired(targetMethod.DeclaringType, ctx); ctx.Emit(OpCodes.Stobj, targetMethod.DeclaringType); } // Cast (to satisfy PEVerify) Cil.CastIfRequired(containerMethod.ReturnType.ReturnType, ctx); ctx.Emit(OpCodes.Ret); } } }
public override LLVMValueRef Emit(EmittingContext pContext) { //Enums are emitted by MemberAccessSyntax throw new NotImplementedException(); }
protected override bool EmitInternal(IndexExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { if (node.Object == null) { throw new InvalidOperationException("Indexing of null object is invalid"); } if (node.Object.Type.IsArray && node.Object.Type.GetArrayRank() == 1) { return(ExpressionEmittersCollection.Emit(Expression.ArrayIndex(node.Object, node.Arguments.Single()), context, returnDefaultValueLabel, whatReturn, extend, out resultType)); } if (node.Object.Type.IsList()) { return(ArrayIndexExpressionEmitter.Emit(node.Object, node.Arguments.Single(), context, returnDefaultValueLabel, whatReturn, extend, out resultType)); } Type objectType; bool result = ExpressionEmittersCollection.Emit(node.Object, context, returnDefaultValueLabel, ResultType.ByRefValueTypesOnly, extend, out objectType); if (objectType.IsValueType) { using (var temp = context.DeclareLocal(objectType)) { context.Il.Stloc(temp); context.Il.Ldloca(temp); } } if (context.Options.HasFlag(CompilerOptions.CheckNullReferences)) { result |= context.EmitNullChecking(objectType, returnDefaultValueLabel); } if (node.Indexer != null) { context.EmitLoadArguments(node.Arguments.ToArray()); MethodInfo getter = node.Indexer.GetGetMethod(context.SkipVisibility); if (getter == null) { throw new MissingMethodException(node.Indexer.ReflectedType.ToString(), "get_" + node.Indexer.Name); } GroboIL.Label doneLabel = null; if (node.Object.Type.IsDictionary()) { var valueType = node.Object.Type.GetGenericArguments()[1]; var constructor = valueType.GetConstructor(Type.EmptyTypes); extend &= (valueType.IsClass && constructor != null) || valueType.IsArray || valueType.IsValueType || valueType == typeof(string); doneLabel = context.Il.DefineLabel("done"); using (var dict = context.DeclareLocal(node.Object.Type)) using (var key = context.DeclareLocal(node.Arguments.Single().Type)) using (var value = context.DeclareLocal(valueType)) { context.Il.Stloc(key); // key = arg0; stack: [dict] context.Il.Dup(); // stack: [dict, dict] context.Il.Stloc(dict); // stack: [dict] context.Il.Ldloc(key); // stack: [dict, key] context.Il.Ldloca(value); // stack: [dict, key, ref value] var tryGetValueMethod = node.Object.Type.GetMethod("TryGetValue", BindingFlags.Public | BindingFlags.Instance); if (tryGetValueMethod == null) { throw new MissingMethodException(node.Object.Type.Name, "TryGetValue"); } context.Il.Call(tryGetValueMethod, node.Object.Type); // stack: [dict.TryGetValue(key, out value)] var loadResultLabel = context.Il.DefineLabel("loadResult"); context.Il.Brtrue(loadResultLabel); // if(dict.TryGetValue(key, out result)) goto loadResult; stack: [] if (valueType.IsValueType) { context.Il.Ldloca(value); context.Il.Initobj(valueType); // value = default(valueType) context.Il.Ldloc(value); // stack: [default(valueType)] } else if (valueType == typeof(string)) { context.Il.Ldstr(""); } else { context.Create(valueType); } context.Il.Stloc(value); if (extend) { context.Il.Ldloc(dict); // stack: [dict] context.Il.Ldloc(key); // stack: [dict, key] context.Il.Ldloc(value); // stack: [dict, key, value] var setter = node.Indexer.GetSetMethod(context.SkipVisibility); if (setter == null) { throw new MissingMethodException(node.Indexer.ReflectedType.ToString(), "set_" + node.Indexer.Name); } context.Il.Call(setter, node.Object.Type); // dict.set_Item(key, default(valueType)); stack: [] } context.MarkLabelAndSurroundWithSP(loadResultLabel); context.Il.Ldloc(value); } } if (doneLabel != null) { context.MarkLabelAndSurroundWithSP(doneLabel); } else { context.Il.Call(getter, node.Object.Type); } } else { Type arrayType = node.Object.Type; if (!arrayType.IsArray) { throw new InvalidOperationException("An array expected"); } int rank = arrayType.GetArrayRank(); if (rank != node.Arguments.Count) { throw new InvalidOperationException("Incorrect number of indeces '" + node.Arguments.Count + "' provided to access an array with rank '" + rank + "'"); } Type indexType = node.Arguments.First().Type; if (indexType != typeof(int)) { throw new InvalidOperationException("Indexing array with an index of type '" + indexType + "' is not allowed"); } context.EmitLoadArguments(node.Arguments.ToArray()); MethodInfo getMethod = arrayType.GetMethod("Get"); if (getMethod == null) { throw new MissingMethodException(arrayType.ToString(), "Get"); } context.Il.Call(getMethod, arrayType); } resultType = node.Type; return(result); }
protected override bool EmitInternal(MethodCallExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { var result = false; GroboIL il = context.Il; var method = node.Method; Expression obj; IEnumerable <Expression> arguments; IEnumerable <ParameterInfo> parameters; bool isStatic = method.IsStatic; if (!isStatic) { obj = node.Object; arguments = node.Arguments; parameters = method.GetParameters(); } else if (method.DeclaringType == typeof(Enumerable)) { obj = node.Arguments[0]; arguments = node.Arguments.Skip(1); parameters = method.GetParameters().Skip(1); } else { obj = null; arguments = node.Arguments; parameters = method.GetParameters(); } Type type = obj == null ? null : obj.Type; if (obj != null) { Type actualType; result |= ExpressionEmittersCollection.Emit(obj, context, returnDefaultValueLabel, isStatic ? ResultType.Value : ResultType.ByRefValueTypesOnly, extend, out actualType); // stack: [obj] if (actualType == typeof(void)) { throw new InvalidOperationException("Unable to call method on void"); } if (actualType.IsValueType && !isStatic) { using (var temp = context.DeclareLocal(actualType)) { il.Stloc(temp); il.Ldloca(temp); } actualType = actualType.MakeByRefType(); } if (context.Options.HasFlag(CompilerOptions.CheckNullReferences) && !actualType.IsValueType) { if (method.DeclaringType != typeof(Enumerable)) { result |= context.EmitNullChecking(type, returnDefaultValueLabel); } else { var arrIsNotNullLabel = il.DefineLabel("arrIsNotNull"); il.Dup(); il.Brtrue(arrIsNotNullLabel); il.Pop(); il.Ldc_I4(0); il.Newarr(GetElementType(type)); context.MarkLabelAndSurroundWithSP(arrIsNotNullLabel); } } } var parametersArray = parameters.ToArray(); var argumentsArray = arguments.ToArray(); for (int i = 0; i < argumentsArray.Length; i++) { var argument = argumentsArray[i]; var parameter = parametersArray[i]; if (parameter.ParameterType.IsByRef) { Type argumentType; var options = context.Options; context.Options = CompilerOptions.None; ExpressionEmittersCollection.Emit(argument, context, null, ResultType.ByRefAll, false, out argumentType); context.Options = options; if (!argumentType.IsByRef) { throw new InvalidOperationException("Expected type by reference"); } } else { Type argumentType; context.EmitLoadArgument(argument, true, out argumentType); } } il.Call(method, type); resultType = node.Type; return(result); }
public bool Compile(CompilerOptions pOptions, out LLVMModuleRef?pModule) { double totalTime = 0; var sw = new System.Diagnostics.Stopwatch(); sw.Start(); //Read source files pModule = null; string source = string.IsNullOrEmpty(pOptions.SourceFile) ? pOptions.Source : ReadSourceFile(pOptions.SourceFile); if (source == null) { return(false); } var lexer = new SmallerLexer(); var stream = lexer.StartTokenStream(source, pOptions.SourceFile); var parser = new SmallerParser(stream); //Create AST var tree = parser.Parse(); if (CompilerErrors.ErrorOccurred) { return(false); } totalTime += RecordPerfData(sw, "Parsed in: "); //Type inference, type checking, AST transformations var compilationModule = ModuleBuilder.Build(tree); if (compilationModule == null) { return(false); } totalTime += RecordPerfData(sw, "Type checked in: "); LLVMModuleRef module = LLVM.ModuleCreateWithName(tree.Name); LLVMPassManagerRef passManager = LLVM.CreateFunctionPassManagerForModule(module); if (pOptions.Optimizations) { LLVM.AddConstantPropagationPass(passManager); //Promote allocas to registers LLVM.AddPromoteMemoryToRegisterPass(passManager); //Do simple peephole optimizations LLVM.AddInstructionCombiningPass(passManager); //Re-associate expressions LLVM.AddReassociatePass(passManager); //Eliminate common subexpressions LLVM.AddGVNPass(passManager); //Simplify control flow graph LLVM.AddCFGSimplificationPass(passManager); } LLVM.InitializeFunctionPassManager(passManager); //Emitting LLVM bytecode using (var c = new EmittingContext(module, passManager, pOptions.Debug)) { compilationModule.Emit(c); if (LLVM.VerifyModule(module, LLVMVerifierFailureAction.LLVMPrintMessageAction, out string message).Value != 0) { LLVM.DumpModule(module); LLVM.DisposePassManager(passManager); pModule = null; return(false); } } pModule = module; LLVM.DisposePassManager(passManager); totalTime += RecordPerfData(sw, "Emitted bytecode in: "); Console.WriteLine("Total time: " + totalTime + "s"); return(true); }