/// <summary> /// Emit the end cases for a short-circuit /// </summary> /// <param name="info"></param> /// <param name="ilg"></param> /// <param name="endLabel"></param> private static void EmitTerminals(ShortCircuitInfo info, FleeILGenerator ilg, Label endLabel) { // Emit the false case if it was used if (info.Branches.HasLabel(OurFalseTerminalKey) == true) { Label falseLabel = info.Branches.FindLabel(OurFalseTerminalKey); // Mark the label and note its position ilg.MarkLabel(falseLabel); MarkBranchTarget(info, falseLabel, ilg); ilg.Emit(OpCodes.Ldc_I4_0); // If we also have a true terminal, then skip over it if (info.Branches.HasLabel(OurTrueTerminalKey) == true) { ilg.Emit(OpCodes.Br_S, endLabel); } } // Emit the true case if it was used if (info.Branches.HasLabel(OurTrueTerminalKey) == true) { Label trueLabel = info.Branches.FindLabel(OurTrueTerminalKey); // Mark the label and note its position ilg.MarkLabel(trueLabel); MarkBranchTarget(info, trueLabel, ilg); ilg.Emit(OpCodes.Ldc_I4_1); } }
/// <summary> /// Get the label for a short-circuit /// </summary> private static Label GetShortCircuitLabel(AndOrElement current, ShortCircuitInfo info, YaleIlGenerator ilg) { // We modify the given stacks so we need to clone them var cloneOperands = (Stack)info.Operands.Clone(); var cloneOperators = (Stack)info.Operators.Clone(); // Pop all siblings current.PopRightChild(cloneOperands, cloneOperators); // Go until we run out of operators while (cloneOperators.Count > 0) { // Get the top operator var top = (AndOrElement)cloneOperators.Pop(); // Is is a different operation? if (top.myOperation != current.myOperation) { // Yes, so return a label to its right operand var nextOperand = cloneOperands.Pop(); return(GetLabel(nextOperand, ilg, info)); } // No, so keep going up the stack top.PopRightChild(cloneOperands, cloneOperators); } // We've reached the end of the stack so return the label for the appropriate true/false terminal if (current.myOperation == AndOrOperation.And) { return(GetLabel(OurFalseTerminalKey, ilg, info)); } return(GetLabel(OurTrueTerminalKey, ilg, info)); }
/// <summary> /// Emit a short-circuited logical operation sequence /// The idea: Store all the leaf operands in a stack with the leftmost at the top and rightmost at the bottom. /// For each operand, emit it and try to find an end point for when it short-circuits. This means we go up through /// the stack of operators (ignoring siblings) until we find a different operation (then emit a branch to its right operand) /// or we reach the root (emit a branch to a true/false). /// Repeat the process for all operands and then emit the true/false/last operand end cases. /// </summary> private void EmitLogical(YaleIlGenerator ilg, ShortCircuitInfo info, ExpressionContext context) { // We always have an end label info.Branches.GetLabel(OurEndLabelKey, ilg); // Populate our data structures PopulateData(info); // Emit the sequence EmitLogicalShortCircuit(ilg, info, context); // Get the last operand var terminalOperand = (BaseExpressionElement)info.Operands.Pop(); // Emit it EmitOperand(terminalOperand, info, ilg, context); // And jump to the end var endLabel = info.Branches.FindLabel(OurEndLabelKey); ilg.Emit(OpCodes.Br_S, endLabel); // Emit our true/false terminals EmitTerminals(info, ilg, endLabel); // Mark the end ilg.MarkLabel(endLabel); }
/// <summary> /// Emit a short-circuited logical operation sequence /// The idea: Store all the leaf operands in a stack with the leftmost at the top and rightmost at the bottom. /// For each operand, emit it and try to find an end point for when it short-circuits. This means we go up through /// the stack of operators (ignoring siblings) until we find a different operation (then emit a branch to its right operand) /// or we reach the root (emit a branch to a true/false). /// Repeat the process for all operands and then emit the true/false/last operand end cases. /// </summary> /// <param name="ilg"></param> /// <param name="info"></param> /// <param name="services"></param> private void EmitLogical(FleeILGenerator ilg, ShortCircuitInfo info, IServiceProvider services) { // We always have an end label info.Branches.GetLabel(OurEndLabelKey, ilg); // Populate our data structures this.PopulateData(info); // Emit the sequence EmitLogicalShortCircuit(ilg, info, services); // Get the last operand ExpressionElement terminalOperand = (ExpressionElement)info.Operands.Pop(); // Emit it EmitOperand(terminalOperand, info, ilg, services); // And jump to the end Label endLabel = info.Branches.FindLabel(OurEndLabelKey); ilg.Emit(OpCodes.Br_S, endLabel); // Emit our true/false terminals EmitTerminals(info, ilg, endLabel); // Mark the end ilg.MarkLabel(endLabel); }
/// <summary> /// Note a label's position if we are in mark mode /// </summary> /// <param name="info"></param> /// <param name="target"></param> /// <param name="ilg"></param> private static void MarkBranchTarget(ShortCircuitInfo info, Label target, FleeILGenerator ilg) { if (ilg.IsTemp == true) { info.Branches.MarkLabel(ilg, target); } }
/// <summary> /// Visit the nodes of the tree (right then left) and populate some data structures /// </summary> /// <param name="info"></param> private void PopulateData(ShortCircuitInfo info) { // Is our right child a leaf or another And/Or expression? AndOrElement andOrChild = MyRightChild as AndOrElement; if (andOrChild == null) { // Leaf so push it on the stack info.Operands.Push(MyRightChild); } else { // Another And/Or expression so recurse andOrChild.PopulateData(info); } // Add ourselves as an operator info.Operators.Push(this); // Do the same thing for the left child andOrChild = MyLeftChild as AndOrElement; if (andOrChild == null) { info.Operands.Push(MyLeftChild); } else { andOrChild.PopulateData(info); } }
/// <summary> /// Emit a short-circuited logical operation sequence /// The idea: Store all the leaf operands in a stack with the leftmost at the top and rightmost at the bottom. /// For each operand, emit it and try to find an end point for when it short-circuits. This means we go up through /// the stack of operators (ignoring siblings) until we find a different operation (then emit a branch to its right operand) /// or we reach the root (emit a branch to a true/false). /// Repeat the process for all operands and then emit the true/false/last operand end cases. /// </summary> /// <param name="ilg"></param> /// <param name="info"></param> /// <param name="services"></param> private void EmitLogical(FleeILGenerator ilg, ShortCircuitInfo info, IServiceProvider services) { // We always have an end label Label endLabel = ilg.DefineLabel(); // Populate our data structures this.PopulateData(info); // Emit the sequence EmitLogicalShortCircuit(ilg, info, services); // Get the last operand ExpressionElement terminalOperand = (ExpressionElement)info.Operands.Pop(); // Emit it EmitOperand(terminalOperand, info, ilg, services); // only 1-3 opcodes, always a short branch ilg.EmitBranch(endLabel); // Emit our true/false terminals EmitTerminals(info, ilg, endLabel); // Mark the end ilg.MarkLabel(endLabel); }
private static Label GetLabel(object key, FleeILGenerator ilg, ShortCircuitInfo info) { if (info.HasLabel(key)) { return(info.FindLabel(key)); } return(info.AddLabel(key, ilg.DefineLabel())); }
private void DoEmitLogical(FleeILGenerator ilg, IServiceProvider services) { // We have to do a 'fake' emit so we can get the positions of the labels ShortCircuitInfo info = new ShortCircuitInfo(); // Do the real emit this.EmitLogical(ilg, info, services); }
private static void EmitOperand(ExpressionElement operand, ShortCircuitInfo info, FleeILGenerator ilg, IServiceProvider services) { // Is this operand the target of a label? if (info.HasLabel(operand) == true) { // Yes, so mark it Label leftLabel = info.FindLabel(operand); ilg.MarkLabel(leftLabel); } // Emit the operand operand.Emit(ilg, services); }
/// <summary> /// Emit a sequence of and/or expressions with short-circuiting /// </summary> /// <param name="ilg"></param> /// <param name="info"></param> /// <param name="services"></param> private static void EmitLogicalShortCircuit(YaleIlGenerator ilg, ShortCircuitInfo info, ExpressionContext context) { while (info.Operators.Count != 0) { // Get the operator var op = (AndOrElement)info.Operators.Pop(); // Get the left operand var leftOperand = (BaseExpressionElement)info.Operands.Pop(); // Emit the left EmitOperand(leftOperand, info, ilg, context); // Get the label for the short-circuit case var label = GetShortCircuitLabel(op, info, ilg); // Emit the branch EmitBranch(op, ilg, label, info); } }
/// <summary> /// Emit a sequence of and/or expressions with short-circuiting /// </summary> /// <param name="ilg"></param> /// <param name="info"></param> /// <param name="services"></param> private static void EmitLogicalShortCircuit(FleeILGenerator ilg, ShortCircuitInfo info, IServiceProvider services) { while (info.Operators.Count != 0) { // Get the operator AndOrElement op = (AndOrElement)info.Operators.Pop(); // Get the left operand ExpressionElement leftOperand = (ExpressionElement)info.Operands.Pop(); // Emit the left EmitOperand(leftOperand, info, ilg, services); // Get the label for the short-circuit case Label l = GetShortCircuitLabel(op, info, ilg); // Emit the branch EmitBranch(op, ilg, l, info); } }
private void DoEmitLogical(YaleIlGenerator ilGenerator, ExpressionContext context) { // We have to do a 'fake' emit so we can get the positions of the labels var info = new ShortCircuitInfo(); // Create a temporary IL generator var ilgTemp = CreateTempIlGenerator(ilGenerator); // We have to make sure that the label count for the temp YaleIlGenerator matches our real YaleIlGenerator Utility.SyncFleeIlGeneratorLabels(ilGenerator, ilgTemp); // Do the fake emit EmitLogical(ilgTemp, info, context); // Clear everything except the label positions info.ClearTempState(); info.Branches.ComputeBranches(); Utility.SyncFleeIlGeneratorLabels(ilgTemp, ilGenerator); // Do the real emit EmitLogical(ilGenerator, info, context); }
private void DoEmitLogical(FleeILGenerator ilg, IServiceProvider services) { // We have to do a 'fake' emit so we can get the positions of the labels ShortCircuitInfo info = new ShortCircuitInfo(); // Create a temporary IL generator FleeILGenerator ilgTemp = this.CreateTempFleeILGenerator(ilg); // We have to make sure that the label count for the temp FleeILGenerator matches our real FleeILGenerator Utility.SyncFleeILGeneratorLabels(ilg, ilgTemp); // Do the fake emit this.EmitLogical(ilgTemp, info, services); // Clear everything except the label positions info.ClearTempState(); info.Branches.ComputeBranches(); Utility.SyncFleeILGeneratorLabels(ilgTemp, ilg); // Do the real emit this.EmitLogical(ilg, info, services); }
private static void EmitBranch(AndOrElement op, FleeILGenerator ilg, Label target, ShortCircuitInfo info) { if (ilg.IsTemp == true) { info.Branches.AddBranch(ilg, target); // Temp mode; just emit a short branch and return OpCode shortBranch = GetBranchOpcode(op, false); ilg.Emit(shortBranch, target); return; } // Emit the proper branch opcode // Determine if it is a long branch bool longBranch = info.Branches.IsLongBranch(ilg, target); // Get the branch opcode OpCode brOpcode = GetBranchOpcode(op, longBranch); // Emit the branch ilg.Emit(brOpcode, target); }
// Emit a short-circuited logical operation sequence // The idea: Store all the leaf operands in a stack with the leftmost at the top and rightmost at the bottom. // For each operand, emit it and try to find an end point for when it short-circuits. This means we go up through // the stack of operators (ignoring siblings) until we find a different operation (then emit a branch to its right operand) // or we reach the root (emit a branch to a true/false). // Repeat the process for all operands and then emit the true/false/last operand end cases. private void EmitLogical(FleeILGenerator ilg, ShortCircuitInfo info, IServiceProvider services) { // We always have an end label info.Branches.GetLabel(OurEndLabelKey, ilg); // Populate our data structures this.PopulateData(info); // Emit the sequence EmitLogicalShortCircuit(ilg, info, services); // Get the last operand ExpressionElement terminalOperand = (ExpressionElement)info.Operands.Pop(); // Emit it EmitOperand(terminalOperand, info, ilg, services); // And jump to the end Label endLabel = info.Branches.FindLabel(OurEndLabelKey); ilg.Emit(OpCodes.Br_S, endLabel); // Emit our true/false terminals EmitTerminals(info, ilg, endLabel); // Mark the end ilg.MarkLabel(endLabel); }
// Get the label for a short-circuit private static Label GetShortCircuitLabel(AndOrElement current, ShortCircuitInfo info, FleeILGenerator ilg) { // We modify the given stacks so we need to clone them Stack cloneOperands = (Stack)info.Operands.Clone(); Stack cloneOperators = (Stack)info.Operators.Clone(); // Pop all siblings current.PopRightChild(cloneOperands, cloneOperators); // Go until we run out of operators while (cloneOperators.Count > 0) { // Get the top operator AndOrElement top = (AndOrElement)cloneOperators.Pop(); // Is is a different operation? if (top.MyOperation != current.MyOperation) { // Yes, so return a label to its right operand object nextOperand = cloneOperands.Pop(); return GetLabel(nextOperand, ilg, info); } else { // No, so keep going up the stack top.PopRightChild(cloneOperands, cloneOperators); } } // We've reached the end of the stack so return the label for the appropriate true/false terminal if (current.MyOperation == AndOrOperation.And) { return GetLabel(OurFalseTerminalKey, ilg, info); } else { return GetLabel(OurTrueTerminalKey, ilg, info); } }
private static Label GetLabel(object key, FleeILGenerator ilg, ShortCircuitInfo info) { return(info.Branches.GetLabel(key, ilg)); }
private static void EmitOperand(ExpressionElement operand, ShortCircuitInfo info, FleeILGenerator ilg, IServiceProvider services) { // Is this operand the target of a label? if (info.Branches.HasLabel(operand) == true) { // Yes, so mark it Label leftLabel = info.Branches.FindLabel(operand); ilg.MarkLabel(leftLabel); // Note the label's position MarkBranchTarget(info, leftLabel, ilg); } // Emit the operand operand.Emit(ilg, services); }
// Note a label's position if we are in mark mode private static void MarkBranchTarget(ShortCircuitInfo info, Label target, FleeILGenerator ilg) { if (ilg.IsTemp == true) { info.Branches.MarkLabel(ilg, target); } }
// Emit the end cases for a short-circuit private static void EmitTerminals(ShortCircuitInfo info, FleeILGenerator ilg, Label endLabel) { // Emit the false case if it was used if (info.Branches.HasLabel(OurFalseTerminalKey) == true) { Label falseLabel = info.Branches.FindLabel(OurFalseTerminalKey); // Mark the label and note its position ilg.MarkLabel(falseLabel); MarkBranchTarget(info, falseLabel, ilg); ilg.Emit(OpCodes.Ldc_I4_0); // If we also have a true terminal, then skip over it if (info.Branches.HasLabel(OurTrueTerminalKey) == true) { ilg.Emit(OpCodes.Br_S, endLabel); } } // Emit the true case if it was used if (info.Branches.HasLabel(OurTrueTerminalKey) == true) { Label trueLabel = info.Branches.FindLabel(OurTrueTerminalKey); // Mark the label and note its position ilg.MarkLabel(trueLabel); MarkBranchTarget(info, trueLabel, ilg); ilg.Emit(OpCodes.Ldc_I4_1); } }
private static Label GetLabel(object key, FleeILGenerator ilg, ShortCircuitInfo info) { return info.Branches.GetLabel(key, ilg); }
// Visit the nodes of the tree (right then left) and populate some data structures private void PopulateData(ShortCircuitInfo info) { // Is our right child a leaf or another And/Or expression? AndOrElement andOrChild = MyRightChild as AndOrElement; if (andOrChild == null) { // Leaf so push it on the stack info.Operands.Push(MyRightChild); } else { // Another And/Or expression so recurse andOrChild.PopulateData(info); } // Add ourselves as an operator info.Operators.Push(this); // Do the same thing for the left child andOrChild = MyLeftChild as AndOrElement; if (andOrChild == null) { info.Operands.Push(MyLeftChild); } else { andOrChild.PopulateData(info); } }
private static void EmitBranch(AndOrElement op, FleeILGenerator ilg, Label target, ShortCircuitInfo info) { // Get the branch opcode if (op._myOperation == AndOrOperation.And) { ilg.EmitBranchFalse(target); } else { ilg.EmitBranchTrue(target); } }
// Emit a sequence of and/or expressions with short-circuiting private static void EmitLogicalShortCircuit(FleeILGenerator ilg, ShortCircuitInfo info, IServiceProvider services) { while (info.Operators.Count != 0) { // Get the operator AndOrElement op = (AndOrElement)info.Operators.Pop(); // Get the left operand ExpressionElement leftOperand = (ExpressionElement)info.Operands.Pop(); // Emit the left EmitOperand(leftOperand, info, ilg, services); // Get the label for the short-circuit case Label l = GetShortCircuitLabel(op, info, ilg); // Emit the branch EmitBranch(op, ilg, l, info); } }