/// <summary> /// Compiles this tree into a NativeSDF instance that can be used to efficiently sample the distance /// field represented by this hierarchy. A compiled NativeSDF instance will not reflect any changes /// made to the hierarchy after the compile step. /// /// The resulting NativeSDF instance can also be used inside of the Unity Job system, and is compatible /// with the Unity Burst compiler. /// </summary> public NativeSDF Compile(Allocator allocator = Allocator.Persistent) { var countVisitor = new InstructionCountVisitor(); VisitInstructions(ref countVisitor); var sizeVisitor = new BufferSizeVisitor(); VisitInstructions(ref sizeVisitor); var stackVisitor = new StackSizeVisitor(); VisitInstructions(ref stackVisitor); IntPtr instructions; unsafe { instructions = (IntPtr)UnsafeUtility.Malloc(sizeVisitor.BufferSize, sizeof(float), allocator); } var bufferWriter = new InstructionWriteVisitor(); bufferWriter.ptr = instructions; bufferWriter.byteOffset = 0; VisitInstructions(ref bufferWriter); return(new NativeSDF(instructions, countVisitor.InstructionCount, stackVisitor.MaxStack, allocator)); }
public Stmt Create() { var mDef = this.ctx.MRef.Resolve(); if (!mDef.HasBody) { throw new ArgumentException("Method has no body, cannot create AST"); } var body = mDef.Body; // Pre-calculate all method block starts this.methodBlockStarts = body.Instructions .SelectMany(x => { switch (x.OpCode.FlowControl) { case FlowControl.Cond_Branch: case FlowControl.Branch: if (x.OpCode.Code == Code.Switch) { return(((Instruction[])x.Operand).Concat(x.Next)); } else { return(new[] { (Instruction)x.Operand, x.Next }); } case FlowControl.Throw: case FlowControl.Return: return(new[] { x.Next }); default: return(Enumerable.Empty <Instruction>()); } }) .Concat(body.ExceptionHandlers.SelectMany(x => new[] { x.TryStart, x.TryEnd, x.HandlerStart, x.HandlerEnd })) .Concat(body.Instructions.First()) .Where(x => x != null) .Distinct() .OrderBy(x => x.Offset) .ToArray(); // Create all method blocks this.CreatePart(body.Instructions, body.ExceptionHandlers); // Map continuations and try statements // Must continue to outermost Try statement, if one exists, rather than directly to the first CIL block foreach (var mappable in this.mappable) { mappable.Map(this.blockMap); } var stmt0 = this.blockMap[body.Instructions.First()].First(); var vStackSize = new StackSizeVisitor(); vStackSize.Visit(stmt0); // Create entry block, and return it var entryBlock = new StmtCil(this.ctx, null, new StmtContinuation(this.ctx, stmt0, false), StmtCil.SpecialBlock.Start); return(entryBlock); }
public Stmt Create() { var mDef = this.ctx.MRef.Resolve(); if (!mDef.HasBody) { throw new ArgumentException("Method has no body, cannot create AST"); } var body = mDef.Body; // Pre-calculate all method block starts this.methodBlockStarts = body.Instructions .SelectMany(x => { switch (x.OpCode.FlowControl) { case FlowControl.Cond_Branch: case FlowControl.Branch: if (x.OpCode.Code == Code.Switch) { return ((Instruction[])x.Operand).Concat(x.Next); } else { return new[] { (Instruction)x.Operand, x.Next }; } case FlowControl.Throw: case FlowControl.Return: return new[] { x.Next }; default: return Enumerable.Empty<Instruction>(); } }) .Concat(body.ExceptionHandlers.SelectMany(x => new[] { x.TryStart, x.TryEnd, x.HandlerStart, x.HandlerEnd })) .Concat(body.Instructions.First()) .Where(x => x != null) .Distinct() .OrderBy(x => x.Offset) .ToArray(); // Create all method blocks this.CreatePart(body.Instructions, body.ExceptionHandlers); // Map continuations and try statements // Must continue to outermost Try statement, if one exists, rather than directly to the first CIL block foreach (var mappable in this.mappable) { mappable.Map(this.blockMap); } var stmt0 = this.blockMap[body.Instructions.First()].First(); var vStackSize = new StackSizeVisitor(); vStackSize.Visit(stmt0); // Create entry block, and return it var entryBlock = new StmtCil(this.ctx, null, new StmtContinuation(this.ctx, stmt0, false), StmtCil.SpecialBlock.Start); return entryBlock; }