/// <summary>
        /// Smooths the provided vertexsequence. Will iterate round all the vertices in the contour
        /// and will average out vertex positions based on thepositions of its neighbours. This will
        /// smooth out the edges of the contour and remove sharp angles.
        /// </summary>
        /// <param name="vs">The vertex sequence to smooth</param>
        private void SmoothContour(VertexSequence vs)
        {
            VertexSequence smooth = new VertexSequence();

            for (int i = 0; i < vs.Count; i++)
            {
                float x = 0;
                float y = 0;
                int   w = 0;
                for (int j = -m_smoothWeights.Length / 2; j <= m_smoothWeights.Length / 2; j++)
                {
                    x += vs[i + j].x * m_smoothWeights[j + (m_smoothWeights.Length / 2)];
                    y += vs[i + j].y * m_smoothWeights[j + (m_smoothWeights.Length / 2)];
                    w += m_smoothWeights[j + (m_smoothWeights.Length / 2)];
                }
                x /= w;
                y /= w;
                smooth.Add(new Vector2()
                {
                    x = x, y = y
                });
            }

            vs.CopyFrom(smooth);
        }
Beispiel #2
0
 public VCGenStroke()
 {
     m_stroker      = new MathStroke <T>();
     m_src_vertices = new VertexSequence <T>();
     m_out_vertices = new PointDVector <T>();
     m_status       = Status.Initial;
 }
 public StrokeGenerator()
 {
     m_stroker      = new StrokeMath();
     m_src_vertices = new VertexSequence();
     m_out_vertices = new Vector2Container();
     m_status       = StrokeMath.status_e.initial;
 }
		public ContourGenerator()
		{
			m_stroker = new StrokeMath();
			m_width = 1;
			m_src_vertices = new VertexSequence();
			m_out_vertices = new Vector2Container();
			m_status = StrokeMath.status_e.initial;
			m_src_vertex = 0;
			m_closed = false;
			m_orientation = 0;
			m_auto_detect = false;
		}
 public ContourGenerator()
 {
     m_stroker      = new StrokeMath();
     m_width        = 1;
     m_src_vertices = new VertexSequence();
     m_out_vertices = new Vector2Container();
     m_status       = StrokeMath.status_e.initial;
     m_src_vertex   = 0;
     m_closed       = false;
     m_orientation  = 0;
     m_auto_detect  = false;
 }
        /// <summary>
        /// Removes vertices from the provided vertex sequence. This will scan round all vertices in the contour
        /// and if the vector to and from each vertex to its neighbours is the same (i.e. 3 vertices are in a straight
        /// line), then the center vertex is culled. Reducing the amount of vertices in the contour but retaining the shape.
        /// </summary>
        /// <param name="vs">The vertex sequence to cull vertices from.</param>
        private void RemoveVertices(VertexSequence vs)
        {
            int count = 0;

            for (int i = 0; i < vs.Count; i++)
            {
                Vector2 a = vs[i - 1];
                Vector2 b = vs[i];
                Vector2 c = vs[i + 1];

                //Remove b if its the same X or same Y as a and c
                bool abX = UnityEngine.Mathf.Approximately(a.x, b.x);
                bool bcX = UnityEngine.Mathf.Approximately(b.x, c.x);
                bool abY = UnityEngine.Mathf.Approximately(a.y, b.y);
                bool bcY = UnityEngine.Mathf.Approximately(b.y, c.y);
                if ((abX && bcX) || (abY && bcY))
                {
                    count++;
                    vs.Remove(b);
                    i--;
                }
            }
        }
        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            // This node does not trigger generation of other nodes.
            if (relocsOnly)
                return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolNode[] { this });

            var writer = new NativeWriter();
            var typeMapHashTable = new VertexHashtable();

            Section hashTableSection = writer.NewSection();
            hashTableSection.Place(typeMapHashTable);

            // Get a list of all methods that have a method body and metadata from the metadata manager.
            foreach (var mappingEntry in factory.MetadataManager.GetMethodMapping())
            {
                MethodDesc method = mappingEntry.Entity;

                // The current format requires us to have an EEType for the owning type. We might want to lift this.
                if (!factory.MetadataManager.TypeGeneratesEEType(method.OwningType))
                    continue;

                // We have a method body, we have a metadata token, but we can't get an invoke stub. Bail.
                if (!factory.MetadataManager.HasReflectionInvokeStub(method))
                    continue;

                InvokeTableFlags flags = 0;

                if (method.HasInstantiation)
                    flags |= InvokeTableFlags.IsGenericMethod;

                if (method.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg())
                    flags |= InvokeTableFlags.RequiresInstArg;

                // TODO: better check for default public(!) constructor
                if (method.IsConstructor && method.Signature.Length == 0)
                    flags |= InvokeTableFlags.IsDefaultConstructor;

                // TODO: HasVirtualInvoke

                if (!method.IsAbstract)
                    flags |= InvokeTableFlags.HasEntrypoint;

                // Once we have a true multi module compilation story, we'll need to start emitting entries where this is not set.
                flags |= InvokeTableFlags.HasMetadataHandle;

                // TODO: native signature for P/Invokes and NativeCallable methods
                if (method.IsRawPInvoke() || method.IsNativeCallable)
                    continue;

                // Grammar of an entry in the hash table:
                // Flags + DeclaringType + MetadataHandle/NameAndSig + Entrypoint + DynamicInvokeMethod + [NumGenericArgs + GenericArgs]

                Vertex vertex = writer.GetUnsignedConstant((uint)flags);

                if ((flags & InvokeTableFlags.HasMetadataHandle) != 0)
                {
                    // Only store the offset portion of the metadata handle to get better integer compression
                    vertex = writer.GetTuple(vertex,
                        writer.GetUnsignedConstant((uint)(mappingEntry.MetadataHandle & MetadataGeneration.MetadataOffsetMask)));
                }
                else
                {
                    // TODO: no MD handle case
                }

                // Go with a necessary type symbol. It will be upgraded to a constructed one if a constructed was emitted.
                IEETypeNode owningTypeSymbol = factory.NecessaryTypeSymbol(method.OwningType);
                vertex = writer.GetTuple(vertex,
                    writer.GetUnsignedConstant(_externalReferences.GetIndex(owningTypeSymbol)));

                if ((flags & InvokeTableFlags.HasEntrypoint) != 0)
                {
                    vertex = writer.GetTuple(vertex,
                        writer.GetUnsignedConstant(_externalReferences.GetIndex(
                            factory.MethodEntrypoint(method.GetCanonMethodTarget(CanonicalFormKind.Specific)))));
                }

                // TODO: data to generate the generic dictionary with the type loader
                MethodDesc invokeStubMethod = factory.MetadataManager.GetReflectionInvokeStub(method);
                MethodDesc canonInvokeStubMethod = invokeStubMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
                if (invokeStubMethod != canonInvokeStubMethod)
                {
                    vertex = writer.GetTuple(vertex,
                        writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.FatFunctionPointer(invokeStubMethod), FatFunctionPointerConstants.Offset) << 1));
                }
                else
                {
                    vertex = writer.GetTuple(vertex,
                        writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(invokeStubMethod)) << 1));
                }

                if ((flags & InvokeTableFlags.IsGenericMethod) != 0)
                {
                    if ((flags & InvokeTableFlags.RequiresInstArg) == 0 || (flags & InvokeTableFlags.HasEntrypoint) == 0)
                    {
                        VertexSequence args = new VertexSequence();
                        for (int i = 0; i < method.Instantiation.Length; i++)
                        {
                            uint argId = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(method.Instantiation[i]));
                            args.Append(writer.GetUnsignedConstant(argId));
                        }
                        vertex = writer.GetTuple(vertex, args);
                    }
                    else
                    {
                        uint dictionaryId = _externalReferences.GetIndex(factory.MethodGenericDictionary(method));
                        vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(dictionaryId));
                    }
                }

                int hashCode = method.GetCanonMethodTarget(CanonicalFormKind.Specific).OwningType.GetHashCode();
                typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex));
            }

            MemoryStream ms = new MemoryStream();
            writer.Save(ms);
            byte[] hashTableBytes = ms.ToArray();

            _endSymbol.SetSymbolOffset(hashTableBytes.Length);

            return new ObjectData(hashTableBytes, Array.Empty<Relocation>(), 1, new ISymbolNode[] { this, _endSymbol });
        }
Beispiel #8
0
        protected override void BuildLipForContour(GroundChunk chunk, VertexSequence contour, Material material)
        {
            //Prepare Unity Gameobject data
            Mesh lip = new Mesh();

            lip.name = "GroundChunkLipMesh";

            List <IntPoint> outerLipPath = new List <IntPoint>();
            List <IntPoint> innerLipPath = new List <IntPoint>();

            GameObject   lipObjt = new GameObject("GroundChunkLip");
            MeshFilter   mf      = lipObjt.AddComponent <MeshFilter>();
            MeshRenderer mr      = lipObjt.AddComponent <MeshRenderer>();

            mf.mesh     = lip;
            mr.material = Materials_Lips[chunk.GroundType];

            //Each point the contour has 3 verts connected to the next point on the contour. The verts are in an L-Shape
            //It sits over the edge of the main contour mesh
            int totalVerts = contour.Count * 3;
            int totalTris  = contour.Count * 4;

            Vector3[] verts = new Vector3[totalVerts];
            Vector3[] norms = new Vector3[totalVerts];
            Vector2[] uvs   = new Vector2[totalVerts];

            //The L-Shape has 4 tris per segment. 2 forming the rectangle on the face, 2 forming the rectangle on the "floor/roof/depth"
            //Everything is multiplied by 3 as its 3 verts per tri...(the verts are index)
            int[] tris = new int[totalTris * 3];

            int     t            = 0;
            int     v            = 0;
            Vector2 previousNorm = new Vector2();

            for (int i = 0; i < contour.Count; i++)
            {
                Vector2 p = contour[i - 1];
                Vector2 q = contour[i];
                Vector2 r = contour[i + 1];

                //TODO Rotation, use p and r to work out the "normal" direciton of q so we rotate the lip correctly...
                Vector2 qp = (p - q).normalized;
                Vector2 qr = (r - q).normalized;

                Vector2 norm = (qp + qr).normalized;
                norm *= sLipSize;

                //Convex/Concave flip
                var cross = Vector2DExtensionMethods.Cross(qp, qr);
                if (cross < 0)
                {
                    norm = -norm;
                }

                //If we have a perfectly straight line, then the normal (or bisect) will be 0,0
                //So as a simple fix for this, we just copy the lip vector from the previous lip
                if (Mathf.Approximately(qp.x, -qr.x) &&
                    Mathf.Approximately(qp.y, -qr.y))
                {
                    norm = previousNorm;
                }

                previousNorm = norm;

                //Add top surface
                verts[v++] = new Vector3(q.x, q.y, sLipOverhang);
                verts[v++] = new Vector3(q.x, q.y, sLipDepth);
                verts[v++] = new Vector3(q.x + norm.x, q.y + norm.y, sLipOverhang);

                //Add outer lip point
                outerLipPath.Add(new IntPoint(q.x, q.y));
                //Add inner lip point
                innerLipPath.Add(new IntPoint(q.x + norm.x, q.y + norm.y));

                //Add tris to the next indices
                //Note - Last segment wraps round to the first indices...
                if (i == contour.Count - 1)
                {
                    //TOP
                    tris[t++] = v - 3; tris[t++] = v - 2; tris[t++] = 0;
                    tris[t++] = v - 2; tris[t++] = 1; tris[t++] = 0;

                    //LIP
                    tris[t++] = v - 3; tris[t++] = 0; tris[t++] = 2;
                    tris[t++] = v - 1; tris[t++] = v - 3; tris[t++] = 2;
                }
                else
                {
                    //TOP
                    tris[t++] = v - 3; tris[t++] = v - 2; tris[t++] = v;
                    tris[t++] = v - 2; tris[t++] = v + 1; tris[t++] = v;

                    //LIP
                    tris[t++] = v - 3; tris[t++] = v; tris[t++] = v + 2;
                    tris[t++] = v - 1; tris[t++] = v - 3; tris[t++] = v + 2;
                }
            }

            //Clipper union on the lip face in the XY-axis
            innerLipPath.Reverse();
            var polys = Clipper.SimplifyPolygons(new List <List <IntPoint> > {
                outerLipPath, innerLipPath
            });

            //Triangulate using Poly2Tri

            lip.vertices  = verts;
            lip.normals   = norms;
            lip.triangles = tris;
            lip.uv        = uvs;

            lip.RecalculateNormals();

            chunk.Lips.Add(lipObjt);
            chunk.LipMeshes.Add(lip);
        }
        public void March(int xx, int yy, int ww, int hh, Ground ground, out Dictionary <int, GroundChunk> chunks)
        {
            chunks = new Dictionary <int, GroundChunk>();

            for (int y = yy; y < yy + hh; y++)
            {
                for (int x = xx; x < xx + ww; x++)
                {
                    int g = ground.Dots[y, x].Value;
                    int c = ground.Dots[y, x].Chunk;

                    if (g == 0 || c != 0)
                    {
                        continue;
                    }

                    //Get Left, Below and Left/Below Diag values to see if they are the same
                    //This is used to check holes and know which chunk to assign holes too
                    int lg  = ground.Dots[y, x - 1].Value;
                    int bg  = ground.Dots[y - 1, x].Value;
                    int lbg = ground.Dots[y - 1, x - 1].Value;

                    bool neighbourSame = lg == g || bg == g || lbg == g;

                    //Is this an edge
                    int marchVal = MarchingValue(x, y, g, ground.Dots);
                    if (marchVal != 0 && marchVal != 15)
                    {
                        //New edge....get the contour and either make a new Ground Chunk or assign it as a Hole to an existing one
                        GroundChunk owner = null;

                        int cID = 0;
                        if (neighbourSame)
                        {
                            if (lg == g)
                            {
                                cID = ground.Dots[y, x - 1].Chunk;
                            }
                            else if (bg == g)
                            {
                                cID = ground.Dots[y - 1, x].Chunk;
                            }
                            else if (lbg == g)
                            {
                                cID = ground.Dots[y - 1, x - 1].Chunk;
                            }
                            else
                            {
                                UnityEngine.Debug.LogWarning("NO NEIGHBOUR FOUND");
                            }

                            owner = ground.Chunks[cID];
                        }
                        else
                        {
                            owner            = new GroundChunk();
                            owner.GroundType = g;
                            cID = owner.ID;
                            ground.Chunks.Add(cID, owner);

                            chunks.Add(cID, owner);
                        }

                        //Get Contour
                        VertexSequence contour = FindContour(x, y, g, owner, ground);

                        if (neighbourSame)
                        {
                            owner.Holes.Add(contour);
                        }
                        else
                        {
                            owner.Edge = contour;
                        }
                    }
                    else if (neighbourSame)
                    {
                        //Mark this non edge as being "owned" by the neighbouring chunk (i.e. its inside a chunk)
                        if (lg == g)
                        {
                            ground.Dots[y, x].Chunk = ground.Dots[y, x - 1].Chunk;
                        }
                        else if (bg == g)
                        {
                            ground.Dots[y, x].Chunk = ground.Dots[y - 1, x].Chunk;
                        }
                        else if (lbg == g)
                        {
                            ground.Dots[y, x].Chunk = ground.Dots[y - 1, x - 1].Chunk;
                        }
                    }
                }
            }
        }
Beispiel #10
0
        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            // This node does not trigger generation of other nodes.
            if (relocsOnly)
            {
                return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this }));
            }

            Dictionary <EcmaMethod, HashSet <EcmaMethod> > inlineeToInliners = new Dictionary <EcmaMethod, HashSet <EcmaMethod> >();

            // Build a map from inlinee to the list of inliners
            // We are only interested in the generic definitions of these.
            foreach (MethodWithGCInfo methodNode in factory.EnumerateCompiledMethods())
            {
                MethodDesc[] inlinees          = methodNode.InlinedMethods;
                MethodDesc   inliner           = methodNode.Method;
                MethodDesc   inlinerDefinition = inliner.GetTypicalMethodDefinition();

                foreach (MethodDesc inlinee in inlinees)
                {
                    MethodDesc inlineeDefinition = inlinee.GetTypicalMethodDefinition();
                    if (!(inlineeDefinition is EcmaMethod ecmaInlineeDefinition))
                    {
                        // We don't record non-ECMA methods because they don't have tokens that
                        // diagnostic tools could reason about anyway.
                        continue;
                    }

                    if (!inlineeToInliners.TryGetValue(ecmaInlineeDefinition, out HashSet <EcmaMethod> inliners))
                    {
                        inliners = new HashSet <EcmaMethod>();
                        inlineeToInliners.Add(ecmaInlineeDefinition, inliners);
                    }
                    inliners.Add((EcmaMethod)inlinerDefinition);
                }
            }

            // Serialize the map as a hash table
            NativeWriter writer  = new NativeWriter();
            Section      section = writer.NewSection();

            VertexHashtable hashtable = new VertexHashtable();

            section.Place(hashtable);

            foreach (var inlineeWithInliners in inlineeToInliners)
            {
                EcmaMethod inlinee    = inlineeWithInliners.Key;
                int        inlineeRid = MetadataTokens.GetRowNumber(inlinee.Handle);
                int        hashCode   = ReadyToRunHashCode.ModuleNameHashCode(inlinee.Module);
                hashCode ^= inlineeRid;

                // Format of the sequence:
                // Inlinee RID with flag in the lowest bit
                // - if flag is set, followed by module ID
                // Followed by inliner RIDs deltas with flag in the lowest bit
                // - if flag is set, followed by module ID

                var sig = new VertexSequence();

                bool isForeignInlinee = inlinee.Module != _globalContext;
                sig.Append(new UnsignedConstant((uint)(inlineeRid << 1 | (isForeignInlinee ? 1 : 0))));
                if (isForeignInlinee)
                {
                    sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inlinee.Module)));
                }

                List <EcmaMethod> sortedInliners = new List <EcmaMethod>(inlineeWithInliners.Value);
                sortedInliners.Sort((a, b) =>
                {
                    if (a == b)
                    {
                        return(0);
                    }

                    int aRid = MetadataTokens.GetRowNumber(a.Handle);
                    int bRid = MetadataTokens.GetRowNumber(b.Handle);
                    if (aRid < bRid)
                    {
                        return(-1);
                    }
                    else if (aRid > bRid)
                    {
                        return(1);
                    }

                    int result = a.Module.CompareTo(b.Module);
                    Debug.Assert(result != 0);
                    return(result);
                });

                int baseRid = 0;
                foreach (EcmaMethod inliner in sortedInliners)
                {
                    int inlinerRid = MetadataTokens.GetRowNumber(inliner.Handle);
                    int ridDelta   = inlinerRid - baseRid;
                    baseRid = inlinerRid;
                    Debug.Assert(ridDelta >= 0);
                    bool isForeignInliner = inliner.Module != _globalContext;
                    sig.Append(new UnsignedConstant((uint)(ridDelta << 1 | (isForeignInliner ? 1 : 0))));
                    if (isForeignInliner)
                    {
                        sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inliner.Module)));
                    }
                }

                hashtable.Append((uint)hashCode, section.Place(sig));
            }

            MemoryStream writerContent = new MemoryStream();

            writer.Save(writerContent);

            return(new ObjectData(
                       data: writerContent.ToArray(),
                       relocs: null,
                       alignment: 8,
                       definedSymbols: new ISymbolDefinitionNode[] { this }));
        }
Beispiel #11
0
        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            // This node does not trigger generation of other nodes.
            if (relocsOnly)
            {
                return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this }));
            }

            // Ensure the native layout blob has been saved
            factory.MetadataManager.NativeLayoutInfo.SaveNativeLayoutInfoWriter(factory);

            var writer           = new NativeWriter();
            var typeMapHashTable = new VertexHashtable();

            Section hashTableSection = writer.NewSection();

            hashTableSection.Place(typeMapHashTable);

            // Get a list of all methods that have a method body and metadata from the metadata manager.
            foreach (var mappingEntry in factory.MetadataManager.GetMethodMapping(factory))
            {
                MethodDesc method = mappingEntry.Entity;

                // The current format requires us to have an EEType for the owning type. We might want to lift this.
                if (!factory.MetadataManager.TypeGeneratesEEType(method.OwningType))
                {
                    continue;
                }

                // We have a method body, we have a metadata token, but we can't get an invoke stub. Bail.
                if (!factory.MetadataManager.IsReflectionInvokable(method))
                {
                    continue;
                }

                InvokeTableFlags flags = 0;

                if (method.HasInstantiation)
                {
                    flags |= InvokeTableFlags.IsGenericMethod;
                }

                if (method.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg())
                {
                    flags |= InvokeTableFlags.RequiresInstArg;
                }

                if (method.IsDefaultConstructor)
                {
                    flags |= InvokeTableFlags.IsDefaultConstructor;
                }

                if (ReflectionVirtualInvokeMapNode.NeedsVirtualInvokeInfo(method))
                {
                    flags |= InvokeTableFlags.HasVirtualInvoke;
                }

                if (!method.IsAbstract)
                {
                    flags |= InvokeTableFlags.HasEntrypoint;
                }

                if (mappingEntry.MetadataHandle != 0)
                {
                    flags |= InvokeTableFlags.HasMetadataHandle;
                }

                if (!factory.MetadataManager.HasReflectionInvokeStubForInvokableMethod(method))
                {
                    flags |= InvokeTableFlags.NeedsParameterInterpretation;
                }

                if (method.IsCanonicalMethod(CanonicalFormKind.Universal))
                {
                    flags |= InvokeTableFlags.IsUniversalCanonicalEntry;
                }

                // TODO: native signature for P/Invokes and NativeCallable methods
                if (method.IsRawPInvoke() || method.IsNativeCallable)
                {
                    continue;
                }

                // Grammar of an entry in the hash table:
                // Flags + DeclaringType + MetadataHandle/NameAndSig + Entrypoint + DynamicInvokeMethod + [NumGenericArgs + GenericArgs]

                Vertex vertex = writer.GetUnsignedConstant((uint)flags);

                if ((flags & InvokeTableFlags.HasMetadataHandle) != 0)
                {
                    // Only store the offset portion of the metadata handle to get better integer compression
                    vertex = writer.GetTuple(vertex,
                                             writer.GetUnsignedConstant((uint)(mappingEntry.MetadataHandle & MetadataManager.MetadataOffsetMask)));
                }
                else
                {
                    var nameAndSig = factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition()));
                    vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)nameAndSig.SavedVertex.VertexOffset));
                }

                // Go with a necessary type symbol. It will be upgraded to a constructed one if a constructed was emitted.
                IEETypeNode owningTypeSymbol = factory.NecessaryTypeSymbol(method.OwningType);
                vertex = writer.GetTuple(vertex,
                                         writer.GetUnsignedConstant(_externalReferences.GetIndex(owningTypeSymbol)));

                if ((flags & InvokeTableFlags.HasEntrypoint) != 0)
                {
                    bool useUnboxingStub = method.OwningType.IsValueType && !method.Signature.IsStatic;
                    vertex = writer.GetTuple(vertex,
                                             writer.GetUnsignedConstant(_externalReferences.GetIndex(
                                                                            factory.MethodEntrypoint(method.GetCanonMethodTarget(CanonicalFormKind.Specific), useUnboxingStub))));
                }

                if ((flags & InvokeTableFlags.NeedsParameterInterpretation) == 0)
                {
                    MethodDesc canonInvokeStubMethod = factory.MetadataManager.GetCanonicalReflectionInvokeStub(method);
                    if (canonInvokeStubMethod.IsSharedByGenericInstantiations)
                    {
                        vertex = writer.GetTuple(vertex,
                                                 writer.GetUnsignedConstant(((uint)factory.MetadataManager.DynamicInvokeTemplateData.GetIdForMethod(canonInvokeStubMethod) << 1) | 1));
                    }
                    else
                    {
                        vertex = writer.GetTuple(vertex,
                                                 writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(canonInvokeStubMethod)) << 1));
                    }
                }

                if ((flags & InvokeTableFlags.IsGenericMethod) != 0)
                {
                    if ((flags & InvokeTableFlags.IsUniversalCanonicalEntry) != 0)
                    {
                        var nameAndSigGenericMethod = factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.MethodNameAndSignatureVertex(method));
                        vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)nameAndSigGenericMethod.SavedVertex.VertexOffset));
                    }
                    else if ((flags & InvokeTableFlags.RequiresInstArg) == 0 || (flags & InvokeTableFlags.HasEntrypoint) == 0)
                    {
                        VertexSequence args = new VertexSequence();
                        for (int i = 0; i < method.Instantiation.Length; i++)
                        {
                            uint argId = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(method.Instantiation[i]));
                            args.Append(writer.GetUnsignedConstant(argId));
                        }
                        vertex = writer.GetTuple(vertex, args);
                    }
                    else
                    {
                        uint dictionaryId = _externalReferences.GetIndex(factory.MethodGenericDictionary(method));
                        vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(dictionaryId));
                    }
                }

                int hashCode = method.GetCanonMethodTarget(CanonicalFormKind.Specific).OwningType.GetHashCode();
                typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex));
            }

            byte[] hashTableBytes = writer.Save();

            _endSymbol.SetSymbolOffset(hashTableBytes.Length);

            return(new ObjectData(hashTableBytes, Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol }));
        }
        private VertexSequence FindContour(int x, int y, int g, GroundChunk owner, Ground ground)
        {
            //Contour
            VertexSequence contour = new VertexSequence();
            //Found a dot to trace
            int  startx = x; int starty = y;
            int  curx = x; int cury = y;
            int  prevx = -1; int prevy = -1;
            int  nextx = -1; int nexty = -1;
            int  bits     = 0;
            bool addPoint = true;

            //Predict an error with Marching Squares here
            bits = MarchingValue(curx, cury, g, ground.Dots);
            if (bits == 6 || bits == 9)
            {
                UnityEngine.Debug.LogWarning("MARCHING MIGHT CRASH");
            }
            if (bits == 15)
            {
                UnityEngine.Debug.LogWarning("MARCHING IS STARTING IN ERROR!!!");
            }

            do
            {
                nextx = curx;
                nexty = cury;

                bits     = MarchingValue(curx, cury, g, ground.Dots);
                addPoint = true;
                switch (bits)
                {
                case 1: nexty -= 1; break;

                case 2: nextx += 1; break;

                case 3: nextx += 1; break;

                case 4: nextx -= 1; break;

                case 5: nexty -= 1; break;

                case 6: if (prevx == curx && prevy == cury + 1)
                    {
                        nextx -= 1;
                    }
                    else
                    {
                        nextx += 1;
                    } break;                                                                                   //What if prev is null as we have just started, we could actually go the wrong way

                case 7: nextx += 1; break;

                case 8: nexty += 1; break;

                case 9: if (prevx == curx - 1 && prevy == cury)
                    {
                        nexty -= 1;
                    }
                    else
                    {
                        nexty += 1;
                    } break;                                                                                   //What if prev is null as we have just started, we could actually go the wrong way

                case 10: nexty += 1; break;

                case 11: nexty += 1; break;

                case 12: nextx -= 1; break;

                case 13: nexty -= 1; break;

                case 14: nextx -= 1; break;

                case 15: nextx -= 1; addPoint = false; break;

                default: throw new ArgumentException(string.Format("Value was {0} prev was {1}, {2}", bits, prevx, prevy));
                }

                if (addPoint)
                {
                    if (contour.Count == 0)
                    {
                        startx = curx;
                        starty = cury;
                    }

                    if (ground.Dots[cury, curx].Value == g)
                    {
                        ground.Dots[cury, curx].Chunk = owner.ID;
                    }

                    contour.Add(new Vector2()
                    {
                        x = curx - 0.5f, y = cury - 0.5f
                    });
                    prevx = curx;
                    prevy = cury;
                }

                curx = nextx;
                cury = nexty;
            }while (curx != startx || cury != starty);

            return(contour);
        }
        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            // Dependencies for this node are tracked by the method code nodes
            if (relocsOnly)
            {
                return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this }));
            }

            // Ensure the native layout data has been saved, in order to get valid Vertex offsets for the signature Vertices
            factory.MetadataManager.NativeLayoutInfo.SaveNativeLayoutInfoWriter(factory);

            NativeWriter    nativeWriter  = new NativeWriter();
            VertexHashtable hashtable     = new VertexHashtable();
            Section         nativeSection = nativeWriter.NewSection();

            nativeSection.Place(hashtable);


            foreach (MethodDesc method in factory.MetadataManager.GetCompiledMethods())
            {
                if (!IsMethodEligibleForTracking(method))
                {
                    continue;
                }

                // Get the method pointer vertex

                bool        getUnboxingStub      = method.OwningType.IsValueType && !method.Signature.IsStatic;
                IMethodNode methodEntryPointNode = factory.MethodEntrypoint(method, getUnboxingStub);
                Vertex      methodPointer        = nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(methodEntryPointNode));

                // Get native layout vertices for the declaring type

                ISymbolNode declaringTypeNode = factory.NecessaryTypeSymbol(method.OwningType);
                Vertex      declaringType     = nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(declaringTypeNode));

                // Get a vertex sequence for the method instantiation args if any

                VertexSequence arguments = new VertexSequence();
                foreach (var arg in method.Instantiation)
                {
                    ISymbolNode argNode = factory.NecessaryTypeSymbol(arg);
                    arguments.Append(nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(argNode)));
                }

                // Get the name and sig of the method.
                // Note: the method name and signature are stored in the NativeLayoutInfo blob, not in the hashtable we build here.

                NativeLayoutMethodNameAndSignatureVertexNode nameAndSig       = factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition());
                NativeLayoutPlacedSignatureVertexNode        placedNameAndSig = factory.NativeLayout.PlacedSignatureVertex(nameAndSig);
                Debug.Assert(placedNameAndSig.SavedVertex != null);
                Vertex placedNameAndSigOffsetSig = nativeWriter.GetOffsetSignature(placedNameAndSig.SavedVertex);

                // Get the vertex for the completed method signature

                Vertex methodSignature = nativeWriter.GetTuple(declaringType, placedNameAndSigOffsetSig, arguments);

                // Make the generic method entry vertex

                Vertex entry = nativeWriter.GetTuple(methodSignature, methodPointer);

                // Add to the hash table, hashed by the containing type's hashcode
                uint hashCode = (uint)method.OwningType.GetHashCode();
                hashtable.Append(hashCode, nativeSection.Place(entry));
            }

            byte[] streamBytes = nativeWriter.Save();

            _endSymbol.SetSymbolOffset(streamBytes.Length);

            return(new ObjectData(streamBytes, Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol }));
        }
Beispiel #14
0
 // TODO would be nice for this to actually review poly surface area....but for now lets keep
 // it super simple and just cull any contours under a certain vertex length...as we can assume they
 // will be too small.
 private bool ContourIsTooSmall(VertexSequence seq)
 {
     return((seq == null) ? true : seq.Count < cMinVertexCount);
 }
Beispiel #15
0
		//-------------------------------------------------------calc_polygon_area
		public static double calc_polygon_area(VertexSequence st)
		{
			int i;
			double sum = 0.0;
			double x = st[0].x;
			double y = st[0].y;
			double xs = x;
			double ys = y;

			for (i = 1; i < st.size(); i++)
			{
				VertexDistance v = st[i];
				sum += x * v.y - y * v.x;
				x = v.x;
				y = v.y;
			}
			return (sum + x * ys - y * xs) * 0.5;
		}
Beispiel #16
0
        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            // This node does not trigger generation of other nodes.
            if (relocsOnly)
            {
                return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this }));
            }

            Dictionary <EcmaMethod, HashSet <EcmaMethod> > inlineeToInliners = new Dictionary <EcmaMethod, HashSet <EcmaMethod> >();

            // Build a map from inlinee to the list of inliners
            // We are only interested in the generic definitions of these.
            foreach (MethodWithGCInfo methodNode in factory.EnumerateCompiledMethods(_module, CompiledMethodCategory.All))
            {
                MethodDesc[] inlinees          = methodNode.InlinedMethods;
                MethodDesc   inliner           = methodNode.Method;
                EcmaMethod   inlinerDefinition = (EcmaMethod)inliner.GetTypicalMethodDefinition();

                if (inlinerDefinition.IsNonVersionable())
                {
                    // Non-versionable methods don't need to be reported
                    continue;
                }

                // Only encode inlining info for inliners within the active module, or if cross module inline format is in use
                Debug.Assert(AllowCrossModuleInlines || (inlinerDefinition.Module == _module));

                bool inlinerReportAllVersionsWithInlinee = !AllowCrossModuleInlines || factory.CompilationModuleGroup.CrossModuleCompileable(inlinerDefinition);

                foreach (MethodDesc inlinee in inlinees)
                {
                    MethodDesc inlineeDefinition = inlinee.GetTypicalMethodDefinition();
                    if (!(inlineeDefinition is EcmaMethod ecmaInlineeDefinition))
                    {
                        // We don't record non-ECMA methods because they don't have tokens that
                        // diagnostic tools could reason about anyway.
                        continue;
                    }

                    if (inlinee.IsNonVersionable())
                    {
                        // Non-versionable methods don't need to be reported
                        continue;
                    }

                    if (ReportAllInlinesInSearch)
                    {
                        // We'll definitely track this inline
                    }
                    else if (factory.CompilationModuleGroup.VersionsWithMethodBody(inlineeDefinition))
                    {
                        if (!inlinerReportAllVersionsWithInlinee)
                        {
                            // We'll won't report this method
                            continue;
                        }
                    }
                    else
                    {
                        Debug.Assert(factory.CompilationModuleGroup.CrossModuleInlineable(inlineeDefinition));
                        if (_inlineInfoType != InfoType.CrossModuleInliningForCrossModuleDataOnly)
                        {
                            // We'll won't report this method
                            continue;
                        }
                    }

                    if (!inlineeToInliners.TryGetValue(ecmaInlineeDefinition, out HashSet <EcmaMethod> inliners))
                    {
                        inliners = new HashSet <EcmaMethod>();
                        inlineeToInliners.Add(ecmaInlineeDefinition, inliners);
                    }
                    inliners.Add((EcmaMethod)inlinerDefinition);
                }
            }

            // Serialize the map as a hash table
            NativeWriter writer  = new NativeWriter();
            Section      section = writer.NewSection();

            VertexHashtable hashtable = new VertexHashtable();

            section.Place(hashtable);

            foreach (var inlineeWithInliners in inlineeToInliners)
            {
                EcmaMethod inlinee    = inlineeWithInliners.Key;
                int        inlineeRid = MetadataTokens.GetRowNumber(inlinee.Handle);
                int        hashCode;

                if (AllowCrossModuleInlines)
                {
                    // CrossModuleInlineInfo format
                    hashCode = ReadyToRunHashCode.MethodHashCode(inlinee);
                }
                else
                {
                    // InliningInfo2 format
                    hashCode  = ReadyToRunHashCode.ModuleNameHashCode(inlinee.Module);
                    hashCode ^= inlineeRid;
                }

                var sig = new VertexSequence();

                if (!AllowCrossModuleInlines)
                {
                    // Format of the sequence:
                    // FOR InliningInfo2 table format
                    //    Inlinee RID with flag in the lowest bit
                    //    - if flag is set, followed by module ID
                    //    Followed by inliner RIDs deltas with flag in the lowest bit
                    //    - if flag is set, followed by module ID
                    Debug.Assert(_module != null);
                    bool isForeignInlinee = inlinee.Module != _module;
                    sig.Append(new UnsignedConstant((uint)(inlineeRid << 1 | (isForeignInlinee ? 1 : 0))));
                    if (isForeignInlinee)
                    {
                        sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inlinee.Module)));
                    }

                    List <EcmaMethod> sortedInliners = new List <EcmaMethod>(inlineeWithInliners.Value);
                    sortedInliners.MergeSort((a, b) =>
                    {
                        if (a == b)
                        {
                            return(0);
                        }

                        int aRid = MetadataTokens.GetRowNumber(a.Handle);
                        int bRid = MetadataTokens.GetRowNumber(b.Handle);
                        if (aRid < bRid)
                        {
                            return(-1);
                        }
                        else if (aRid > bRid)
                        {
                            return(1);
                        }

                        int result = a.Module.CompareTo(b.Module);
                        Debug.Assert(result != 0);
                        return(result);
                    });

                    int baseRid = 0;
                    foreach (EcmaMethod inliner in sortedInliners)
                    {
                        int inlinerRid = MetadataTokens.GetRowNumber(inliner.Handle);
                        int ridDelta   = inlinerRid - baseRid;
                        baseRid = inlinerRid;
                        Debug.Assert(ridDelta >= 0);
                        bool isForeignInliner = inliner.Module != _module;
                        sig.Append(new UnsignedConstant((uint)(ridDelta << 1 | (isForeignInliner ? 1 : 0))));
                        if (isForeignInliner)
                        {
                            sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inliner.Module)));
                        }
                    }
                }
                else
                {
                    // Format of the sequence:
                    // FOR CrossModuleInlineInfo format
                    //    Index with 2 flags field in lowest 2 bits to define the inlinee
                    //      - If flags & 1 == 0 then index is a MethodDef RID, and if the module is a composite image, a module index of the method follows
                    //      - If flags & 1 == 1, then index is an index into the ILBody import section
                    //      - If flags & 2 == 0 then what follows is:
                    //        - Inliner RID deltas - See definition below
                    //      - if flags & 2 == 2 then what follows is:
                    //        - count of delta encoded indices into the ILBody import section
                    //        - the sequence of delta encoded indices into the ILBody import section
                    //        - Inliner RID deltas - See definition below
                    //
                    //      Inliner RID deltas (for multi-module version bubble images (specified by the module having the READYTORUN_FLAG_MULTIMODULE_VERSION_BUBBLE flag set)
                    //        - a sequence of inliner RID deltas with flag in the lowest bit
                    //          - if flag is set, the inliner RID is followed by a module ID
                    //          - otherwise the module is the same as the module of the inlinee method
                    //
                    //      Inliner RID deltas (for single module version bubble images)
                    //        - a sequence of inliner RID deltas

                    bool crossModuleMultiModuleFormat = (factory.CompilationModuleGroup.GetReadyToRunFlags() & ReadyToRunFlags.READYTORUN_FLAG_MultiModuleVersionBubble) != 0;

                    Debug.Assert(_module == null);
                    bool isCrossModuleInlinee = !factory.CompilationModuleGroup.VersionsWithMethodBody(inlinee);
                    Debug.Assert(!isCrossModuleInlinee || factory.CompilationModuleGroup.CrossModuleInlineable(inlinee));

                    EcmaMethod[] sortedInliners = new EcmaMethod[inlineeWithInliners.Value.Count];
                    inlineeWithInliners.Value.CopyTo(sortedInliners);

                    sortedInliners.MergeSort((a, b) =>
                    {
                        if (a == b)
                        {
                            return(0);
                        }

                        bool isCrossModuleInlinerA = !factory.CompilationModuleGroup.VersionsWithMethodBody(a);
                        bool isCrossModuleInlinerB = !factory.CompilationModuleGroup.VersionsWithMethodBody(b);
                        if (isCrossModuleInlinerA != isCrossModuleInlinerB)
                        {
                            if (isCrossModuleInlinerA)
                            {
                                return(-1);
                            }
                            else
                            {
                                return(1);
                            }
                        }

                        int result;
                        if (isCrossModuleInlinerA)
                        {
                            int indexA = _symbolNodeFactory.CheckILBodyFixupSignature(a).IndexFromBeginningOfArray;
                            int indexB = _symbolNodeFactory.CheckILBodyFixupSignature(b).IndexFromBeginningOfArray;
                            Debug.Assert(indexA != indexB);
                            result = indexA.CompareTo(indexB);
                        }
                        else
                        {
                            int aRid = MetadataTokens.GetRowNumber(a.Handle);
                            int bRid = MetadataTokens.GetRowNumber(b.Handle);
                            if (aRid < bRid)
                            {
                                return(-1);
                            }
                            else if (aRid > bRid)
                            {
                                return(1);
                            }

                            result = a.Module.CompareTo(b.Module);
                        }
                        Debug.Assert(result != 0);
                        return(result);
                    });

                    uint crossModuleInlinerCount = 0;
                    foreach (var method in sortedInliners)
                    {
                        if (factory.CompilationModuleGroup.VersionsWithMethodBody(method))
                        {
                            break;
                        }

                        Debug.Assert(factory.CompilationModuleGroup.CrossModuleInlineable(method));
                        crossModuleInlinerCount++;
                    }

                    uint encodedInlinee;
                    checked
                    {
                        uint indexOfInlinee;
                        if (isCrossModuleInlinee)
                        {
                            indexOfInlinee = (uint)_symbolNodeFactory.CheckILBodyFixupSignature(inlinee).IndexFromBeginningOfArray;
                        }
                        else
                        {
                            indexOfInlinee = (uint)MetadataTokens.GetRowNumber(inlinee.Handle);
                        }

                        encodedInlinee = indexOfInlinee << (int)ReadyToRunCrossModuleInlineFlags.CrossModuleInlinerIndexShift;

                        if (isCrossModuleInlinee)
                        {
                            encodedInlinee |= (uint)ReadyToRunCrossModuleInlineFlags.CrossModuleInlinee;
                        }

                        if (crossModuleInlinerCount > 0)
                        {
                            encodedInlinee |= (uint)ReadyToRunCrossModuleInlineFlags.HasCrossModuleInliners;
                        }

                        sig.Append(new UnsignedConstant(encodedInlinee));
                        if (crossModuleMultiModuleFormat && !isCrossModuleInlinee)
                        {
                            sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inlinee.Module)));
                        }

                        int inlinerIndex = 0;
                        if (crossModuleInlinerCount > 0)
                        {
                            sig.Append(new UnsignedConstant(crossModuleInlinerCount));
                            uint baseIndex = 0;
                            for (; inlinerIndex < crossModuleInlinerCount; inlinerIndex++)
                            {
                                var inliner = sortedInliners[inlinerIndex];

                                uint ilBodyIndex = (uint)_symbolNodeFactory.CheckILBodyFixupSignature(inliner).IndexFromBeginningOfArray;
                                uint ridDelta    = ilBodyIndex - baseIndex;
                                sig.Append(new UnsignedConstant(ridDelta));
                            }
                        }

                        uint baseRid = 0;
                        for (; inlinerIndex < sortedInliners.Length; inlinerIndex++)
                        {
                            var  inliner    = sortedInliners[inlinerIndex];
                            uint inlinerRid = (uint)MetadataTokens.GetRowNumber(inliner.Handle);
                            uint ridDelta   = inlinerRid - baseRid;
                            baseRid = inlinerRid;
                            bool isForeignInliner = inliner.Module != inlinee.Module;
                            Debug.Assert(!isForeignInliner || crossModuleMultiModuleFormat);

                            if (crossModuleMultiModuleFormat)
                            {
                                uint encodedRid = ridDelta << (int)ReadyToRunCrossModuleInlineFlags.InlinerRidShift;
                                if (isForeignInliner)
                                {
                                    encodedRid |= (uint)ReadyToRunCrossModuleInlineFlags.InlinerRidHasModule;
                                }

                                sig.Append(new UnsignedConstant(encodedRid));
                                if (isForeignInliner)
                                {
                                    sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inliner.Module)));
                                }
                            }
                            else
                            {
                                sig.Append(new UnsignedConstant(ridDelta));
                            }
                        }
                    }
                }

                hashtable.Append((uint)hashCode, section.Place(sig));
            }

            MemoryStream writerContent = new MemoryStream();

            writer.Save(writerContent);

            return(new ObjectData(
                       data: writerContent.ToArray(),
                       relocs: null,
                       alignment: 8,
                       definedSymbols: new ISymbolDefinitionNode[] { this }));
        }
Beispiel #17
0
		static public void shorten_path(VertexSequence vs, double s, int closed)
		{
			if (s > 0.0 && vs.size() > 1)
			{
				double d;
				int n = (int)(vs.size() - 2);
				while (n != 0)
				{
					d = vs[n].dist;
					if (d > s) break;
					vs.RemoveLast();
					s -= d;
					--n;
				}
				if (vs.size() < 2)
				{
					vs.remove_all();
				}
				else
				{
					n = (int)vs.size() - 1;
					VertexDistance prev = vs[n - 1];
					VertexDistance last = vs[n];
					d = (prev.dist - s) / prev.dist;
					double x = prev.x + (last.x - prev.x) * d;
					double y = prev.y + (last.y - prev.y) * d;
					last.x = x;
					last.y = y;
					if (!prev.IsEqual(last)) vs.RemoveLast();
					vs.close(closed != 0);
				}
			}
		}
Beispiel #18
0
        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            // This node does not trigger generation of other nodes.
            if (relocsOnly)
            {
                return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolNode[] { this }));
            }

            var writer           = new NativeWriter();
            var typeMapHashTable = new VertexHashtable();

            Section hashTableSection = writer.NewSection();

            hashTableSection.Place(typeMapHashTable);

            // Get a list of all methods that have a method body and metadata from the metadata manager.
            foreach (var mappingEntry in factory.MetadataManager.GetMethodMapping())
            {
                MethodDesc method = mappingEntry.Entity;

                // The current format requires us to have an EEType for the owning type. We might want to lift this.
                if (!factory.MetadataManager.TypeGeneratesEEType(method.OwningType))
                {
                    continue;
                }

                // We have a method body, we have a metadata token, but we can't get an invoke stub. Bail.
                if (!factory.MetadataManager.HasReflectionInvokeStub(method))
                {
                    continue;
                }

                InvokeTableFlags flags = 0;

                if (method.HasInstantiation)
                {
                    flags |= InvokeTableFlags.IsGenericMethod;
                }

                if (method.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg())
                {
                    flags |= InvokeTableFlags.RequiresInstArg;
                }

                // TODO: better check for default public(!) constructor
                if (method.IsConstructor && method.Signature.Length == 0)
                {
                    flags |= InvokeTableFlags.IsDefaultConstructor;
                }

                // TODO: HasVirtualInvoke

                if (!method.IsAbstract)
                {
                    flags |= InvokeTableFlags.HasEntrypoint;
                }

                // Once we have a true multi module compilation story, we'll need to start emitting entries where this is not set.
                flags |= InvokeTableFlags.HasMetadataHandle;

                // TODO: native signature for P/Invokes and NativeCallable methods
                if (method.IsRawPInvoke() || method.IsNativeCallable)
                {
                    continue;
                }

                // Grammar of an entry in the hash table:
                // Flags + DeclaringType + MetadataHandle/NameAndSig + Entrypoint + DynamicInvokeMethod + [NumGenericArgs + GenericArgs]

                Vertex vertex = writer.GetUnsignedConstant((uint)flags);

                if ((flags & InvokeTableFlags.HasMetadataHandle) != 0)
                {
                    // Only store the offset portion of the metadata handle to get better integer compression
                    vertex = writer.GetTuple(vertex,
                                             writer.GetUnsignedConstant((uint)(mappingEntry.MetadataHandle & MetadataGeneration.MetadataOffsetMask)));
                }
                else
                {
                    // TODO: no MD handle case
                }

                // Go with a necessary type symbol. It will be upgraded to a constructed one if a constructed was emitted.
                IEETypeNode owningTypeSymbol = factory.NecessaryTypeSymbol(method.OwningType);
                vertex = writer.GetTuple(vertex,
                                         writer.GetUnsignedConstant(_externalReferences.GetIndex(owningTypeSymbol)));

                if ((flags & InvokeTableFlags.HasEntrypoint) != 0)
                {
                    vertex = writer.GetTuple(vertex,
                                             writer.GetUnsignedConstant(_externalReferences.GetIndex(
                                                                            factory.MethodEntrypoint(method.GetCanonMethodTarget(CanonicalFormKind.Specific)))));
                }

                // TODO: data to generate the generic dictionary with the type loader
                MethodDesc invokeStubMethod      = factory.MetadataManager.GetReflectionInvokeStub(method);
                MethodDesc canonInvokeStubMethod = invokeStubMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
                if (invokeStubMethod != canonInvokeStubMethod)
                {
                    vertex = writer.GetTuple(vertex,
                                             writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.FatFunctionPointer(invokeStubMethod), FatFunctionPointerConstants.Offset) << 1));
                }
                else
                {
                    vertex = writer.GetTuple(vertex,
                                             writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(invokeStubMethod)) << 1));
                }

                if ((flags & InvokeTableFlags.IsGenericMethod) != 0)
                {
                    if ((flags & InvokeTableFlags.RequiresInstArg) == 0 || (flags & InvokeTableFlags.HasEntrypoint) == 0)
                    {
                        VertexSequence args = new VertexSequence();
                        for (int i = 0; i < method.Instantiation.Length; i++)
                        {
                            uint argId = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(method.Instantiation[i]));
                            args.Append(writer.GetUnsignedConstant(argId));
                        }
                        vertex = writer.GetTuple(vertex, args);
                    }
                    else
                    {
                        uint dictionaryId = _externalReferences.GetIndex(factory.MethodGenericDictionary(method));
                        vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(dictionaryId));
                    }
                }

                int hashCode = method.GetCanonMethodTarget(CanonicalFormKind.Specific).OwningType.GetHashCode();
                typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex));
            }

            MemoryStream ms = new MemoryStream();

            writer.Save(ms);
            byte[] hashTableBytes = ms.ToArray();

            _endSymbol.SetSymbolOffset(hashTableBytes.Length);

            return(new ObjectData(hashTableBytes, Array.Empty <Relocation>(), 1, new ISymbolNode[] { this, _endSymbol }));
        }
        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            // This node does not trigger generation of other nodes.
            if (relocsOnly)
            {
                return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolNode[] { this }));
            }

            // Ensure the native layout data has been saved, in order to get valid Vertex offsets for the signature Vertices
            factory.MetadataManager.NativeLayoutInfo.SaveNativeLayoutInfoWriter(factory);

            NativeWriter    nativeWriter  = new NativeWriter();
            VertexHashtable hashtable     = new VertexHashtable();
            Section         nativeSection = nativeWriter.NewSection();

            nativeSection.Place(hashtable);

            foreach (var dictionaryNode in factory.MetadataManager.GetCompiledGenericDictionaries())
            {
                MethodGenericDictionaryNode methodDictionary = dictionaryNode as MethodGenericDictionaryNode;
                if (methodDictionary == null)
                {
                    continue;
                }

                MethodDesc method = methodDictionary.OwningMethod;

                Debug.Assert(method.HasInstantiation && !method.IsCanonicalMethod(CanonicalFormKind.Any));

                Vertex fullMethodSignature;
                {
                    // Method's containing type
                    IEETypeNode containingTypeNode = factory.NecessaryTypeSymbol(method.OwningType);
                    Vertex      containingType     = nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(containingTypeNode));

                    // Method's instantiation arguments
                    VertexSequence arguments = new VertexSequence();
                    for (int i = 0; i < method.Instantiation.Length; i++)
                    {
                        IEETypeNode argNode = factory.NecessaryTypeSymbol(method.Instantiation[i]);
                        arguments.Append(nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(argNode)));
                    }

                    // Method name and signature
                    NativeLayoutVertexNode      nameAndSig       = factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition());
                    NativeLayoutSavedVertexNode placedNameAndSig = factory.NativeLayout.PlacedSignatureVertex(nameAndSig);
                    Vertex placedNameAndSigVertexOffset          = nativeWriter.GetUnsignedConstant((uint)placedNameAndSig.SavedVertex.VertexOffset);

                    fullMethodSignature = nativeWriter.GetTuple(containingType, placedNameAndSigVertexOffset, arguments);
                }

                // Method's dictionary pointer
                Vertex dictionaryVertex = nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(dictionaryNode));

                Vertex entry = nativeWriter.GetTuple(dictionaryVertex, fullMethodSignature);

                hashtable.Append((uint)method.GetHashCode(), nativeSection.Place(entry));
            }

            byte[] streamBytes = nativeWriter.Save();

            _endSymbol.SetSymbolOffset(streamBytes.Length);

            return(new ObjectData(streamBytes, Array.Empty <Relocation>(), 1, new ISymbolNode[] { this, _endSymbol }));
        }