public override RloMethod GenerateMethod(Compiler compiler, MethodInstantiationPath instantiationPath)
        {
            HighLocal[] locals = new HighLocal[0];
            HighLocal[] args = new HighLocal[0];
            HighLocal instanceLocal = new HighLocal(m_bt, HighLocal.ETypeOfType.Value);

            Stack<HighField> fieldStack = new Stack<HighField>();

            uint getHashCodeSlot = m_vtCache.GetGetHashCodeVTableSlot(compiler);
            HighSsaRegister result = new HighSsaRegister(HighValueType.ValueValue, m_vtCache.GetSystemInt32Type(compiler), null);

            MethodSignatureTag methodSignature = new MethodSignatureTag(0, m_vtCache.GetSystemInt32Type(compiler), new MethodSignatureParam[0]);
            methodSignature = compiler.TagRepository.InternMethodSignature(methodSignature);

            if (RecursiveFindHashableField(compiler, m_bt.ContainedType, fieldStack))
            {
                // Found a field that can be hashed
                Queue<HighField> fieldQueue = new Queue<HighField>();
                while (fieldStack.Count > 0)
                    fieldQueue.Enqueue(fieldStack.Pop());

                HighSsaRegister thisRef = new HighSsaRegister(HighValueType.BoxedValue, m_bt.ContainedType, null);
                HighSsaRegister thisPtr = new HighSsaRegister(HighValueType.ManagedPtr, m_bt.ContainedType, null);

                HighCfgNodeHandle unboxHdl = new HighCfgNodeHandle();
                HighCfgNodeHandle locateAndHashFieldHdl = new HighCfgNodeHandle();

                {
                    List<HighInstruction> instrs = new List<HighInstruction>();
                    instrs.Add(new Rpa.Instructions.LoadLocalInstruction(null, thisRef, instanceLocal));
                    Rpa.Instructions.UnboxPtrInstruction unboxInstr = new Rpa.Instructions.UnboxPtrInstruction(null, thisPtr, thisRef);
                    unboxInstr.ContinuationEdge = new HighCfgEdge(unboxInstr, locateAndHashFieldHdl);
                    instrs.Add(unboxInstr);

                    unboxHdl.Value = new HighCfgNode(new HighCfgNodeHandle[0], new HighPhi[0], instrs.ToArray());
                }

                HighSsaRegister hashablePtr = thisPtr;

                List<HighInstruction> lahInstrs = new List<HighInstruction>();
                while (fieldQueue.Count > 0)
                {
                    HighField fld = fieldQueue.Dequeue();

                    HighSsaRegister nextFldPtr = new HighSsaRegister(HighValueType.ManagedPtr, fld.Type, null);
                    lahInstrs.Add(new Rpa.Instructions.PtrFieldInstruction(null, nextFldPtr, hashablePtr, fld.Name));
                    hashablePtr = nextFldPtr;
                }

                if (compiler.TypeIsValueType(hashablePtr.Type))
                {
                    HighCfgNodeHandle returnResultHdl = new HighCfgNodeHandle();

                    CliClass cls = compiler.GetClosedClass((TypeSpecClassTag)hashablePtr.Type);

                    CliMethodIndex vtableHashCodeIndex = cls.VTable[getHashCodeSlot].MethodIndex;
                    if (vtableHashCodeIndex.Depth == 0)
                    {
                        HighMethod method = cls.Methods[vtableHashCodeIndex.Index];

                        Instructions.CallRloVirtualMethodInstruction callInstr = new Instructions.CallRloVirtualMethodInstruction(null, getHashCodeSlot, result, hashablePtr, new HighSsaRegister[0]);
                        callInstr.ContinuationEdge = new HighCfgEdge(callInstr, returnResultHdl);
                        lahInstrs.Add(callInstr);
                    }
                    else
                    {
                        // Base class GetHashCode, but field was found as hashable, which means it's POD
                        MethodDeclTag hashBytesDecl = m_vtCache.GetHashBytesDeclTag(compiler);

                        MethodSpecTag methodSpec = new MethodSpecTag(MethodSlotType.Static, new TypeSpecTag[] { hashablePtr.Type }, m_vtCache.GetClarityToolsType(compiler), hashBytesDecl);
                        methodSpec = compiler.TagRepository.InternMethodSpec(methodSpec);

                        MethodHandle methodHandle = compiler.InstantiateMethod(new MethodSpecMethodKey(methodSpec), instantiationPath);

                        Instructions.CallRloStaticMethodInstruction callInstr = new Instructions.CallRloStaticMethodInstruction(null, methodHandle, result, new HighSsaRegister[] { hashablePtr });
                        callInstr.ContinuationEdge = new HighCfgEdge(callInstr, returnResultHdl);
                        lahInstrs.Add(callInstr);
                    }

                    // Add return block
                    {
                        List<HighInstruction> rrInstrs = new List<HighInstruction>();
                        rrInstrs.Add(new Rpa.Instructions.ReturnValueInstruction(null, result));

                        returnResultHdl.Value = new HighCfgNode(new HighCfgNodeHandle[0], new HighPhi[0], rrInstrs.ToArray());
                    }
                }
                else
                {
                    HighCfgNodeHandle fldNullHdl = new HighCfgNodeHandle();
                    HighCfgNodeHandle callGetHashCodeHdl = new HighCfgNodeHandle();
                    HighCfgNodeHandle returnResultHdl = new HighCfgNodeHandle();

                    HighSsaRegister fldValue = new HighSsaRegister(HighValueType.ReferenceValue, hashablePtr.Type, null);

                    lahInstrs.Add(new Rpa.Instructions.LoadPtrInstruction(null, fldValue, hashablePtr));
                    lahInstrs.Add(new Rpa.Instructions.BranchRefNullInstruction(null, fldValue, fldNullHdl, callGetHashCodeHdl));

                    {
                        HighSsaRegister zeroConstant = new HighSsaRegister(HighValueType.ConstantValue, m_vtCache.GetSystemInt32Type(compiler), 0);

                        List<HighInstruction> instrs = new List<HighInstruction>();
                        instrs.Add(new Rpa.Instructions.ReturnValueInstruction(null, zeroConstant));
                        fldNullHdl.Value = new HighCfgNode(instrs.ToArray());
                    }

                    {
                        List<HighInstruction> instrs = new List<HighInstruction>();

                        Instructions.CallRloVirtualMethodInstruction callInstr = new Instructions.CallRloVirtualMethodInstruction(null, getHashCodeSlot, result, fldValue, new HighSsaRegister[0]);
                        callInstr.ContinuationEdge = new HighCfgEdge(callInstr, returnResultHdl);

                        callGetHashCodeHdl.Value = new HighCfgNode(instrs.ToArray());
                    }

                    {
                        List<HighInstruction> instrs = new List<HighInstruction>();
                        instrs.Add(new Rpa.Instructions.ReturnValueInstruction(null, result));
                        returnResultHdl.Value = new HighCfgNode(instrs.ToArray());
                    }
                }

                HighCfgNodeHandle entryHdl = new HighCfgNodeHandle(new HighCfgNode(lahInstrs.ToArray()));
                HighRegion region = new HighRegion(entryHdl);
                RloMethodBody methodBody = new RloMethodBody(instanceLocal, args, locals, m_vtCache.GetSystemInt32Type(compiler), region, methodSignature, instantiationPath);

                return new RloMethod(methodBody);
            }
            else
            {
                // No fields can be POD hashed, hash the type instead
                HighSsaRegister type = new HighSsaRegister(HighValueType.ReferenceValue, m_vtCache.GetSystemTypeType(compiler), null);

                HighCfgNodeHandle entryHdl = new HighCfgNodeHandle();
                HighCfgNodeHandle returnResultHdl = new HighCfgNodeHandle();

                {
                    List<HighInstruction> instrs = new List<HighInstruction>();
                    instrs.Add(new Rpa.Instructions.GetTypeInfoInstruction(null, type, m_bt.ContainedType));
                    Instructions.CallRloVirtualMethodInstruction callInstr = new Instructions.CallRloVirtualMethodInstruction(null, getHashCodeSlot, result, type, new HighSsaRegister[0]);
                    callInstr.ContinuationEdge = new HighCfgEdge(callInstr, returnResultHdl);
                    instrs.Add(callInstr);
                    entryHdl.Value = new HighCfgNode(instrs.ToArray());
                }

                {
                    List<HighInstruction> instrs = new List<HighInstruction>();
                    instrs.Add(new Rpa.Instructions.ReturnValueInstruction(null, result));
                    returnResultHdl.Value = new HighCfgNode(instrs.ToArray());
                }

                HighRegion region = new HighRegion(entryHdl);
                RloMethodBody methodBody = new RloMethodBody(instanceLocal, args, locals, m_vtCache.GetSystemInt32Type(compiler), region, methodSignature, instantiationPath);
                return new RloMethod(methodBody);
            }
        }
Пример #2
0
        public override RloMethod GenerateMethod(Compiler compiler, MethodInstantiationPath instantiationPath)
        {
            VTableGenerationCache vtCache = m_vtCache;
            HighTypeDef typeDef = compiler.GetTypeDef(m_bt.ContainedType.TypeName);

            switch (typeDef.Semantics)
            {
                case TypeSemantics.Enum:
                case TypeSemantics.Struct:
                    break;
                default:
                    throw new ArgumentException("Unknown method type");
            }

            CliClass cls = compiler.GetClosedClass(m_bt.ContainedType);

            HighLocal instanceLocal = new HighLocal(m_bt, HighLocal.ETypeOfType.Value);
            HighLocal[] args = new HighLocal[] { new HighLocal(vtCache.GetSystemObjectType(compiler), HighLocal.ETypeOfType.Value) };
            HighLocal[] locals = new HighLocal[0];

            HighCfgNodeHandle returnFalseHdl = new HighCfgNodeHandle();

            HighCfgNodeHandle entryHdl = new HighCfgNodeHandle();
            HighCfgNodeHandle getOtherTypeHdl = new HighCfgNodeHandle();
            HighCfgNodeHandle checkTypeHdl = new HighCfgNodeHandle();
            HighCfgNodeHandle unboxThisHdl = new HighCfgNodeHandle();
            HighCfgNodeHandle unboxOtherHdl = new HighCfgNodeHandle();
            HighCfgNodeHandle nextFieldCheckHdl = new HighCfgNodeHandle();

            HighSsaRegister thisRef = new HighSsaRegister(HighValueType.ReferenceValue, vtCache.GetSystemObjectType(compiler), null);
            HighSsaRegister otherRef = new HighSsaRegister(HighValueType.ReferenceValue, vtCache.GetSystemObjectType(compiler), null);

            HighSsaRegister thisType = new HighSsaRegister(HighValueType.ReferenceValue, vtCache.GetSystemTypeType(compiler), null);
            HighSsaRegister otherType = new HighSsaRegister(HighValueType.ReferenceValue, vtCache.GetSystemTypeType(compiler), null);
            HighSsaRegister unboxedThisPtr = new HighSsaRegister(HighValueType.ManagedPtr, m_bt.ContainedType, null);
            HighSsaRegister unboxedOtherPtr = new HighSsaRegister(HighValueType.ManagedPtr, m_bt.ContainedType, null);

            TypeSpecClassTag boolType = vtCache.GetSystemBoolType(compiler);

            {
                List<HighInstruction> instrs = new List<HighInstruction>();
                instrs.Add(new Rpa.Instructions.LoadLocalInstruction(null, thisRef, instanceLocal));
                instrs.Add(new Rpa.Instructions.LoadLocalInstruction(null, otherRef, args[0]));
                instrs.Add(new Rpa.Instructions.BranchRefNullInstruction(null, otherRef, returnFalseHdl, getOtherTypeHdl));
                entryHdl.Value = new HighCfgNode(new HighCfgNodeHandle[0], new HighPhi[0], instrs.ToArray());
            }

            {
                List<HighInstruction> instrs = new List<HighInstruction>();
                Instructions.CallRloInstanceMethodInstruction callInstr = new Instructions.CallRloInstanceMethodInstruction(null, vtCache.GetSystemObjectGetType(compiler), otherType, otherRef, new HighSsaRegister[0]);
                callInstr.ContinuationEdge = new HighCfgEdge(callInstr, checkTypeHdl);
                instrs.Add(callInstr);
                getOtherTypeHdl.Value = new HighCfgNode(new HighCfgNodeHandle[0], new HighPhi[0], instrs.ToArray());
            }

            {
                List<HighInstruction> instrs = new List<HighInstruction>();
                instrs.Add(new Rpa.Instructions.GetTypeInfoInstruction(null, thisType, m_bt.ContainedType));
                instrs.Add(new Rpa.Instructions.BranchCompareRefsInstruction(null, thisType, otherType, unboxThisHdl, returnFalseHdl));
                checkTypeHdl.Value = new HighCfgNode(new HighCfgNodeHandle[0], new HighPhi[0], instrs.ToArray());
            }

            {
                List<HighInstruction> instrs = new List<HighInstruction>();
                Rpa.Instructions.UnboxPtrInstruction unboxInstr = new Rpa.Instructions.UnboxPtrInstruction(null, unboxedThisPtr, thisRef);
                unboxInstr.ContinuationEdge = new HighCfgEdge(unboxInstr, unboxOtherHdl);
                instrs.Add(unboxInstr);
                unboxThisHdl.Value = new HighCfgNode(new HighCfgNodeHandle[0], new HighPhi[0], instrs.ToArray());
            }

            {
                List<HighInstruction> instrs = new List<HighInstruction>();
                Rpa.Instructions.UnboxPtrInstruction unboxInstr = new Rpa.Instructions.UnboxPtrInstruction(null, unboxedOtherPtr, otherRef);
                unboxInstr.ContinuationEdge = new HighCfgEdge(unboxInstr, nextFieldCheckHdl);
                instrs.Add(unboxInstr);
                unboxOtherHdl.Value = new HighCfgNode(new HighCfgNodeHandle[0], new HighPhi[0], instrs.ToArray());
            }

            if ((vtCache.GetClassPodFlags(compiler, cls) & VTableGenerationCache.PodFlags.Equality) != VTableGenerationCache.PodFlags.None)
            {
                HighCfgNodeHandle nextHdl = new HighCfgNodeHandle();
                List<HighInstruction> instrs = new List<HighInstruction>();
                instrs.Add(new Instructions.BranchComparePodInstruction(null, unboxedThisPtr, unboxedOtherPtr, nextHdl, returnFalseHdl));
                nextFieldCheckHdl.Value = new HighCfgNode(new HighCfgNodeHandle[0], new HighPhi[0], instrs.ToArray());

                nextFieldCheckHdl = nextHdl;
            }
            else
            {
                foreach (HighField fld in cls.InstanceFields)
                {
                    HighCfgNodeHandle nextHdl = new HighCfgNodeHandle();

                    TypeSpecTag fldType = fld.Type;
                    HighSsaRegister thisFldPtr = new HighSsaRegister(HighValueType.ManagedPtr, fldType, null);
                    HighSsaRegister otherFldPtr = new HighSsaRegister(HighValueType.ManagedPtr, fldType, null);

                    {
                        List<HighInstruction> instrs = new List<HighInstruction>();
                        instrs.Add(new Rpa.Instructions.PtrFieldInstruction(null, thisFldPtr, unboxedThisPtr, fld.Name));
                        instrs.Add(new Rpa.Instructions.PtrFieldInstruction(null, otherFldPtr, unboxedOtherPtr, fld.Name));

                        if (compiler.TypeIsValueType(fldType) &&
                            (((m_vtCache.GetClassPodFlags(compiler, compiler.GetClosedClass((TypeSpecClassTag)fldType))) & VTableGenerationCache.PodFlags.Equality) != VTableGenerationCache.PodFlags.None))
                        {
                            instrs.Add(new Instructions.BranchComparePodInstruction(null, thisFldPtr, otherFldPtr, nextHdl, returnFalseHdl));
                        }
                        else
                        {
                            HighCfgNodeHandle checkResultHdl = new HighCfgNodeHandle();
                            HighSsaRegister result = new HighSsaRegister(HighValueType.ValueValue, vtCache.GetSystemBoolType(compiler), null);
                            HighSsaRegister resultInt = new HighSsaRegister(HighValueType.ValueValue, vtCache.GetSystemBoolType(compiler), null);
                            HighSsaRegister zeroConstant = new HighSsaRegister(HighValueType.ConstantValue, vtCache.GetSystemInt32Type(compiler), 0);

                            TypeSpecClassTag clarityToolsClass = vtCache.GetClarityToolsType(compiler);
                            MethodDeclTag compareFieldsDeclTag = vtCache.GetCompareFieldsDeclTag(compiler);
                            MethodSpecTag compareMethodSpec = new MethodSpecTag(MethodSlotType.Static, new TypeSpecTag[] { fldType }, clarityToolsClass, compareFieldsDeclTag);

                            MethodHandle compareHdl = compiler.InstantiateMethod(new MethodSpecMethodKey(compareMethodSpec), instantiationPath);
                            Instructions.CallRloStaticMethodInstruction callInstr = new Instructions.CallRloStaticMethodInstruction(null, compareHdl, result, new HighSsaRegister[] { thisFldPtr, otherFldPtr });

                            callInstr.ContinuationEdge = new HighCfgEdge(callInstr, checkResultHdl);
                            instrs.Add(callInstr);

                            List<HighInstruction> checkResultsInstrs = new List<HighInstruction>();
                            checkResultsInstrs.Add(new Instructions.RloConvertNumberInstruction(null, resultInt, result, Instructions.RloConvertNumberInstruction.NumConversionType.ZeroExtend, 32, 8));
                            checkResultsInstrs.Add(new Rpa.Instructions.BranchCompareNumbersInstruction(null, Rpa.Instructions.NumberCompareOperation.Equal, Rpa.Instructions.NumberArithType.Int32, resultInt, zeroConstant, returnFalseHdl, nextHdl));
                            checkResultHdl.Value = new HighCfgNode(new HighCfgNodeHandle[0], new HighPhi[0], checkResultsInstrs.ToArray());
                        }

                        nextFieldCheckHdl.Value = new HighCfgNode(new HighCfgNodeHandle[0], new HighPhi[0], instrs.ToArray());
                    }

                    nextFieldCheckHdl = nextHdl;
                }

                // Generate terminators
                {
                    HighSsaRegister falseConstant = new HighSsaRegister(HighValueType.ConstantValue, boolType, false);
                    List<HighInstruction> instrs = new List<HighInstruction>();
                    instrs.Add(new Rpa.Instructions.ReturnValueInstruction(null, falseConstant));
                    returnFalseHdl.Value = new HighCfgNode(new HighCfgNodeHandle[0], new HighPhi[0], instrs.ToArray());
                }

                {
                    HighSsaRegister trueConstant = new HighSsaRegister(HighValueType.ConstantValue, boolType, false);
                    List<HighInstruction> instrs = new List<HighInstruction>();
                    instrs.Add(new Rpa.Instructions.ReturnValueInstruction(null, trueConstant));
                    nextFieldCheckHdl.Value = new HighCfgNode(new HighCfgNodeHandle[0], new HighPhi[0], instrs.ToArray());
                }
            }

            MethodSignatureTag methodSignature = new MethodSignatureTag(0, m_vtCache.GetSystemBoolType(compiler),
                new MethodSignatureParam[] {
                    new MethodSignatureParam(m_vtCache.GetSystemObjectType(compiler), new MethodSignatureParamTypeOfType(MethodSignatureParamTypeOfType.Values.Value))
                });
            methodSignature = compiler.TagRepository.InternMethodSignature(methodSignature);

            HighRegion region = new HighRegion(entryHdl);
            RloMethodBody body = new RloMethodBody(instanceLocal, args, locals, boolType, region, methodSignature, instantiationPath);
            return new RloMethod(body);
        }