static void BuildTables(IEnumerable <JumpEntry> jumps, LabelOperand defaultLabel, out List <JumpTable> tables, out List <JumpEntry> rest) { rest = new List <JumpEntry>(); var numbers = FilterJumps(jumps, rest); var comparer = new GenericComparer <JumpTableEntry <int> >((b1, b2) => b1.Value - b2.Value); numbers.Sort(comparer); tables = new List <JumpTable>(); for (var i = 0; i < numbers.Count; i++) { var table = TryBuildTable(numbers, i, defaultLabel); if (table != null) { tables.Add(table); i += table.Entries.Count - table.Holes - 1; } else { rest.Add(new JumpEntry(numbers[i].Condition, numbers[i].Label)); } } }
/// <summary> /// Emits the displacement operand. /// </summary> /// <param name="displacement">The displacement operand.</param> public void WriteDisplacement(Operand displacement) { byte[] disp; MemberOperand member = displacement as MemberOperand; LabelOperand label = displacement as LabelOperand; SymbolOperand symbol = displacement as SymbolOperand; if (label != null) { int pos = (int)(_codeStream.Position - _codeStreamBasePosition); disp = LittleEndianBitConverter.GetBytes((uint)_linker.Link(LinkType.AbsoluteAddress | LinkType.I4, _compiler.Method.ToString(), pos, 0, label.Name, IntPtr.Zero)); } else if (member != null) { int pos = (int)(_codeStream.Position - _codeStreamBasePosition); disp = LittleEndianBitConverter.GetBytes((uint)_linker.Link(LinkType.AbsoluteAddress | LinkType.I4, _compiler.Method.ToString(), pos, 0, member.Member.ToString(), member.Offset)); } else if (symbol != null) { int pos = (int)(_codeStream.Position - _codeStreamBasePosition); disp = LittleEndianBitConverter.GetBytes((uint)_linker.Link(LinkType.AbsoluteAddress | LinkType.I4, _compiler.Method.ToString(), pos, 0, symbol.Name, IntPtr.Zero)); } else { disp = LittleEndianBitConverter.GetBytes((displacement as MemoryOperand).Offset.ToInt32()); } _codeStream.Write(disp, 0, disp.Length); }
public FunctionContext(ExpressionCompiler compiler, string name) { _compiler = compiler; _instructions = new List<Instruction>(); _loopLabels = new IndexedStack<Tuple<LabelOperand, LabelOperand>>(); Name = name != null ? _compiler.Identifier(name) : null; Label = _compiler.MakeLabel("function"); IdentifierCount = 0; }
/// <summary> /// This function emits a constant variable into the read-only data section. /// </summary> /// <param name="op">The operand to emit as a constant.</param> /// <returns>An operand, which represents the reference to the read-only constant.</returns> /// <remarks> /// This function checks if the given operand needs to be moved into the read-only data /// section of the executable. For x86 this concerns only floating point operands, as these /// can't be specified in inline assembly.<para/> /// This function checks if the given operand needs to be moved and rewires the operand, if /// it must be moved. /// </remarks> protected Operand EmitConstant(Operand op) { ConstantOperand cop = op as ConstantOperand; if (cop != null && (cop.StackType == StackTypeCode.F || cop.StackType == StackTypeCode.Int64)) { int size, alignment; architecture.GetTypeRequirements(cop.Type, out size, out alignment); string name = String.Format("C_{0}", Guid.NewGuid()); using (Stream stream = methodCompiler.Linker.Allocate(name, SectionKind.ROData, size, alignment)) { byte[] buffer; switch (cop.Type.Type) { case CilElementType.R4: buffer = LittleEndianBitConverter.GetBytes((float)cop.Value); break; case CilElementType.R8: buffer = LittleEndianBitConverter.GetBytes((double)cop.Value); break; case CilElementType.I8: buffer = LittleEndianBitConverter.GetBytes((long)cop.Value); break; case CilElementType.U8: buffer = LittleEndianBitConverter.GetBytes((ulong)cop.Value); break; default: throw new NotSupportedException(); } stream.Write(buffer, 0, buffer.Length); } // FIXME: Attach the label operand to the linker symbol // FIXME: Rename the operand to SymbolOperand // FIXME: Use the provided name to link LabelOperand lop = new LabelOperand(cop.Type, name); op = lop; } return(op); }
private Instruction decodePcRelative(uint index, uint data) { var rs = new RegisterOperand(data, 21); var offset = new LabelOperand(getSymbolName(index, (ushort)data << 2)); switch ((data >> 16) & 0x1f) { case 0: addXref(index - 4, (uint)((index + (short)data) << 2)); m_analysisQueue.Enqueue(index + (uint)((short)data << 2)); return(new ConditionalBranchInstruction(ConditionalBranchInstruction.Operation.SignedLess, rs, new ImmediateOperand(0), offset)); case 1: addXref(index - 4, (uint)((index + (short)data) << 2)); m_analysisQueue.Enqueue(index + (uint)((short)data << 2)); return(new ConditionalBranchInstruction(ConditionalBranchInstruction.Operation.SignedGreaterEqual, rs, new ImmediateOperand(0), offset)); case 16: addCall(index - 4, (uint)((index + (short)data) << 2)); m_analysisQueue.Enqueue(index + (uint)((short)data << 2)); return(new ConditionalCallInstruction(ConditionalBranchInstruction.Operation.SignedLess, rs, new ImmediateOperand(0), offset)); case 17: addCall(index - 4, (uint)((index + (short)data) << 2)); m_analysisQueue.Enqueue(index + (uint)((short)data << 2)); return(new ConditionalCallInstruction(ConditionalBranchInstruction.Operation.SignedGreaterEqual, rs, new ImmediateOperand(0), offset)); default: return(new WordData(data)); } }
public SwitchInstruction(LabelOperand caseTable, uint caseCount, LabelOperand defaultLabel, Register caseValueRegister, Register boolTestRegister, Register shiftedCaseValue) { _caseTable = caseTable; _caseCount = caseCount; _defaultLabel = defaultLabel; _caseValueRegister = caseValueRegister; _boolTestRegister = boolTestRegister; _shiftedCaseValue = shiftedCaseValue; Operands = new IOperand[] { caseTable, new ImmediateOperand(caseCount), defaultLabel, new RegisterOperand(caseValueRegister), new RegisterOperand(boolTestRegister) }; }
public FunctionContext(ExpressionCompiler compiler, int argIndex, int localIndex, Scope prevScope, string parentName, string name) { _instructions = new List<Instruction>(); _loopLabels = new IndexedStack<Tuple<LabelOperand, LabelOperand>>(); Compiler = compiler; ArgIndex = argIndex; LocalIndex = localIndex; Scope = prevScope; ParentName = parentName; Name = name; FullName = string.Format("{0}{1}{2}", parentName, string.IsNullOrEmpty(parentName) ? "" : ".", Name ?? ""); AssignedName = name != null ? prevScope.Get(name) : null; Label = Compiler.MakeLabel("function"); IdentifierCount = 0; }
public override void CompileBody(FunctionContext context) { var stack = 0; EndLabel = context.MakeLabel("state_end"); stack += context.Bind(context.Label); stack += context.Enter(); // jump to state label stack += context.Load(State); stack += context.JumpTable(0, _stateLabels); stack += context.Jump(EndLabel); // first state stack += context.Bind(MakeStateLabel(context)); // compile body stack += Block.Compile(context); // set enumerator.current to undefined // do this before EndLabel so we dont overwrite return values stack += context.LoadUndefined(); stack += context.Load(Enumerable); stack += context.StoreField(context.String("current")); stack += context.Bind(EndLabel); // set state to end stack += context.Load(context.Number(-1)); stack += context.Store(State); stack += context.LoadFalse(); stack += context.Return(); CheckStack(stack, 0); }
/// <summary> /// Emits the displacement operand. /// </summary> /// <param name="displacement">The displacement operand.</param> private void EmitDisplacement(MemoryOperand displacement) { byte[] disp; MemberOperand member = displacement as MemberOperand; LabelOperand label = displacement as LabelOperand; if (null != label) { int pos = (int)(_codeStream.Position - _codeStreamBasePosition); disp = LittleEndianBitConverter.GetBytes((uint)_linker.Link(LinkType.AbsoluteAddress | LinkType.I4, _compiler.Method, pos, 0, label.Name, IntPtr.Zero)); } else if (null != member) { int pos = (int)(_codeStream.Position - _codeStreamBasePosition); disp = LittleEndianBitConverter.GetBytes((uint)_linker.Link(LinkType.AbsoluteAddress | LinkType.I4, _compiler.Method, pos, 0, member.Member, member.Offset)); } else { disp = LittleEndianBitConverter.GetBytes(displacement.Offset.ToInt32()); } _codeStream.Write(disp, 0, disp.Length); }
public override int Compile(FunctionContext context) { context.Position(Token); var stack = 0; var caseLabels = new List <LabelOperand>(Branches.Count); var caseEnd = context.MakeLabel("caseEnd"); LabelOperand caseDefault = null; BlockExpression defaultBlock = null; for (var i = 0; i < Branches.Count; i++) { var label = context.MakeLabel("caseBranch_" + i); caseLabels.Add(label); var conditions = Branches[i].Conditions; if (conditions.Any(c => c == null)) { caseDefault = label; if (conditions.Count == 1) { defaultBlock = Branches[i].Block; } } } var emptyDefault = caseDefault == null; if (emptyDefault) { caseDefault = context.MakeLabel("caseDefault"); } context.PushScope(); context.Statement(Expression); stack += Expression.Compile(context); var flattenedBranches = FlattenBranches(Branches, caseLabels, caseDefault); BuildTables(flattenedBranches, caseDefault, out var tables, out var rest); foreach (var table in tables) { var start = table.Entries[0].Value; var labels = table.Entries.Select(e => e.Label).ToList(); stack += context.Dup(); stack += context.JumpTable(start, labels); } foreach (var entry in rest) { stack += context.Dup(); stack += entry.Condition.Compile(context); stack += context.BinaryOperation(TokenType.EqualTo); stack += context.JumpTrue(entry.Label); } stack += context.Jump(caseDefault); context.PushLoop(null, caseEnd); for (var i = 0; i < Branches.Count; i++) { var branchStack = stack; var branch = Branches[i]; branchStack += context.Bind(caseLabels[i]); branchStack += context.Drop(); branchStack += branch.Block.Compile(context); branchStack += context.Jump(caseEnd); CheckStack(branchStack, 0); } // only bind if we need a default block if (emptyDefault || defaultBlock != null) { stack += context.Bind(caseDefault); } // always drop the switch value stack += context.Drop(); if (defaultBlock != null) { stack += defaultBlock.Compile(context); } context.PopLoop(); stack += context.Bind(caseEnd); context.PopScope(); CheckStack(stack, 0); return(stack); }
public CaseTableEntry([NotNull] LabelOperand labelOperand) { _labelOperand = labelOperand; }
public override void PushLoop(LabelOperand continueTarget, LabelOperand breakTarget) { _parent.PushLoop(continueTarget, breakTarget); }
static JumpTable TryBuildTable(IList <JumpTableEntry <int> > jumps, int offset, LabelOperand defaultLabel) { var tableEntries = new List <JumpTableEntry <int> >(); var tableHoles = 0; var prev = jumps[offset].Value; for (var i = offset; i < jumps.Count; i++) { var holeSize = jumps[i].Value - prev; if (holeSize < 0) { throw new Exception("not sorted"); } holeSize--; if (holeSize > 3) { break; } for (var j = 0; j < holeSize; j++) { tableEntries.Add(new JumpTableEntry <int>(null, 0, defaultLabel)); } tableEntries.Add(jumps[i]); tableHoles += Math.Max(holeSize, 0); prev = jumps[i].Value; } if (tableEntries.Count < 3) { return(null); } if ((double)tableHoles / tableEntries.Count >= 0.25) // TODO: allow more holes for large tables? { return(null); } return(new JumpTable(tableEntries, tableHoles)); }
public JumpTableEntry(Expression condition, T value, LabelOperand label) { Condition = condition; Value = value; Label = label; }
static IEnumerable <JumpEntry> FlattenBranches(IList <Branch> branches, IList <LabelOperand> labels, LabelOperand defaultLabel) { var branchConditions = new HashSet <MondValue>(); for (var i = 0; i < branches.Count; i++) { foreach (var condition in branches[i].Conditions) { if (condition == null) // default { yield return(new JumpEntry(null, defaultLabel)); continue; } var constantExpression = condition as IConstantExpression; if (constantExpression == null) { throw new MondCompilerException(condition, CompilerError.ExpectedConstant); } if (!branchConditions.Add(constantExpression.GetValue())) { throw new MondCompilerException(condition, CompilerError.DuplicateCase); } yield return(new JumpEntry(condition, labels[i])); } } }
public void JumpTruePeek(LabelOperand label) { Emit(new Instruction(InstructionType.JmpTrueP, label)); }
public JumpEntry(Expression condition, LabelOperand label) { Condition = condition; Label = label; }
public void PushLoop(LabelOperand continueTarget, LabelOperand breakTarget) { _loopLabels.Push(Tuple.Create(continueTarget, breakTarget)); }
public void TailCall(int argumentCount, LabelOperand label) { Emit(new Instruction(InstructionType.TailCall, new ImmediateOperand(argumentCount), label)); }
public void Jump(LabelOperand label) { Emit(new Instruction(InstructionType.Jmp, label)); }
public void Closure(LabelOperand label) { Emit(new Instruction(InstructionType.Closure, label)); }
public void Bind(LabelOperand label) { Emit(new Instruction(InstructionType.Label, label)); }