private TypeSpecTag GetOrReturnTypeSpec(ref TypeSpecTag typeSpecTag, string typeName) { if (typeSpecTag == null) { TypeNameTag nameTag = new TypeNameTag("mscorlib", "System", typeName); nameTag = m_compiler.TagRepository.InternTypeName(nameTag); TypeSpecTag typeSpec = new TypeSpecClassTag(nameTag, new TypeSpecTag[0]); typeSpecTag = m_compiler.TagRepository.InternTypeSpec(typeSpec); } return typeSpecTag; }
private CliClass(CliClass baseClass, Compiler compiler, TypeSpecTag[] argTypes) { if (!baseClass.m_isCreated) throw new Exception("Can't instantiate an open class that hasn't been processed"); m_typeName = baseClass.m_typeName; m_parentClassSpec = (TypeSpecClassTag)baseClass.m_parentClassSpec.Instantiate(compiler.TagRepository, argTypes); m_parentClass = compiler.GetClosedClass(m_parentClassSpec); m_isSealed = baseClass.m_isSealed; m_isAbstract = baseClass.m_isAbstract; m_isStruct = baseClass.m_isStruct; m_typeSpec = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(new TypeSpecClassTag(m_typeName, argTypes)); m_isCreated = baseClass.m_isCreated; m_numGenericParameters = baseClass.m_numGenericParameters; List<HighField> staticFields = new List<HighField>(); foreach (HighField fld in baseClass.m_staticFields) staticFields.Add(fld.Instantiate(compiler.TagRepository, argTypes)); m_staticFields = staticFields.ToArray(); List<HighMethod> methods = new List<HighMethod>(); foreach (HighMethod method in baseClass.m_methods) methods.Add(method.Instantiate(compiler.TagRepository, argTypes)); m_methods = methods.ToArray(); List<HighField> instanceFields = new List<HighField>(); foreach (HighField fld in baseClass.m_instanceFields) instanceFields.Add(fld.Instantiate(compiler.TagRepository, argTypes)); m_instanceFields = instanceFields.ToArray(); List<CliVtableSlot> vtableSlots = new List<CliVtableSlot>(); foreach (CliVtableSlot slot in baseClass.m_vtable) vtableSlots.Add(slot.Instantiate(compiler, argTypes)); m_vtable = vtableSlots.ToArray(); List<CliInterfaceImpl> interfaceImpls = new List<CliInterfaceImpl>(); foreach (CliInterfaceImpl ifcImpl in baseClass.m_interfaceImpls) interfaceImpls.Add(ifcImpl.Instantiate(compiler, argTypes)); m_interfaceImpls = interfaceImpls.ToArray(); List<TypeSpecClassTag> explicitInterfaces = new List<TypeSpecClassTag>(); foreach (TypeSpecClassTag ifc in baseClass.m_explicitInterfaceSpecs) explicitInterfaces.Add((TypeSpecClassTag)ifc.Instantiate(compiler.TagRepository, argTypes)); m_explicitInterfaceSpecs = explicitInterfaces.ToArray(); m_declTagToMethod = baseClass.m_declTagToMethod; m_declTagToVTableSlot = baseClass.m_declTagToVTableSlot; m_ifcToIfcSlot = baseClass.m_ifcToIfcSlot; m_nameToInstanceFieldSlot = baseClass.m_nameToInstanceFieldSlot; m_nameToStaticFieldSlot = baseClass.m_nameToStaticFieldSlot; }
public AssignabilityResolver(Compiler compiler) { m_compiler = compiler; m_objectType = ResolveSimpleType("System", "Object"); m_arrayType = ResolveSimpleType("System", "Array"); m_refSZArrayName = compiler.TagRepository.InternTypeName(new TypeNameTag("mscorlib", "Clarity", "RefSZArray")); m_valueSZArrayName = compiler.TagRepository.InternTypeName(new TypeNameTag("mscorlib", "Clarity", "ValueSZArray`1", 1, null)); m_nullableSZArrayName = compiler.TagRepository.InternTypeName(new TypeNameTag("mscorlib", "Clarity", "NullableSZArray`1", 1, null)); m_nullableName = compiler.TagRepository.InternTypeName(new TypeNameTag("mscorlib", "System", "Nullable`1", 1, null)); m_ilistName = compiler.TagRepository.InternTypeName(new TypeNameTag("mscorlib", "System.Collections.Generic", "IList`1", 1, null)); m_icollectionName = compiler.TagRepository.InternTypeName(new TypeNameTag("mscorlib", "System.Collections.Generic", "ICollection`1", 1, null)); m_ienumerableName = compiler.TagRepository.InternTypeName(new TypeNameTag("mscorlib", "System.Collections.Generic", "IEnumerable`1", 1, null)); }
private CliInterface(HighTypeDef typeDef, TypeSpecClassTag typeSpec, TypeSpecTag[] genericParameters, TypeSpecClassTag[] parentInterfaces, HighClassVtableSlot[] slots, Dictionary<MethodDeclTag, uint> slotTagToCliSlot, Dictionary<MethodDeclTag, uint> slotTagToRealSlot, uint numRealSlots, TypeSpecClassTag[] interfaceImpls) { m_typeDef = typeDef; m_typeSpec = typeSpec; m_genericParameters = genericParameters; m_slots = slots; m_slotTagToCliSlot = slotTagToCliSlot; m_slotTagToRealSlot = slotTagToRealSlot; m_numRealSlots = numRealSlots; m_interfaceImpls = interfaceImpls; m_isCreated = true; }
public RloInitPass(Compiler compiler, RloMethodBody methodBody, RloFindPredecessorsAndSuccessorsPass psPass) : base(compiler, methodBody) { m_psPass = psPass; m_addTypeVisitor = AddSsaTypes; TagRepository repo = compiler.TagRepository; m_boolType = GetBuiltinType(repo, "System", "Boolean"); m_charType = GetBuiltinType(repo, "System", "Char"); m_int8Type = GetBuiltinType(repo, "System", "SByte"); m_int16Type = GetBuiltinType(repo, "System", "Int16"); m_int32Type = GetBuiltinType(repo, "System", "Int32"); m_int64Type = GetBuiltinType(repo, "System", "Int64"); m_uint8Type = GetBuiltinType(repo, "System", "Byte"); m_uint16Type = GetBuiltinType(repo, "System", "UInt16"); m_uint32Type = GetBuiltinType(repo, "System", "UInt32"); m_uint64Type = GetBuiltinType(repo, "System", "UInt64"); m_float32Type = GetBuiltinType(repo, "System", "Single"); m_float64Type = GetBuiltinType(repo, "System", "Double"); m_nativeIntType = GetBuiltinType(repo, "System", "IntPtr"); m_nativeUIntType = GetBuiltinType(repo, "System", "UIntPtr"); m_objectType = GetBuiltinType(repo, "System", "Object"); m_runtimeTypeHandleType = GetBuiltinType(repo, "System", "RuntimeTypeHandle"); m_runtimeFieldHandleType = GetBuiltinType(repo, "System", "RuntimeFieldHandle"); m_simplifiedNumberType = new Dictionary<TypeSpecTag, TypeSpecClassTag>(); m_simplifiedNumberType.Add(m_boolType, m_int32Type); m_simplifiedNumberType.Add(m_charType, m_int32Type); m_simplifiedNumberType.Add(m_int8Type, m_int32Type); m_simplifiedNumberType.Add(m_int16Type, m_int32Type); m_simplifiedNumberType.Add(m_int32Type, m_int32Type); m_simplifiedNumberType.Add(m_int64Type, m_int64Type); m_simplifiedNumberType.Add(m_uint8Type, m_int32Type); m_simplifiedNumberType.Add(m_uint16Type, m_int32Type); m_simplifiedNumberType.Add(m_uint32Type, m_int32Type); m_simplifiedNumberType.Add(m_uint64Type, m_int64Type); m_simplifiedNumberType.Add(m_nativeIntType, m_nativeIntType); m_simplifiedNumberType.Add(m_nativeUIntType, m_nativeIntType); m_simplifiedNumberType.Add(m_float32Type, m_float64Type); m_simplifiedNumberType.Add(m_float64Type, m_float64Type); }
private List<MethodSpecTag> GenerateMethodSpecsForClass(Compiler compiler, TypeSpecClassTag typeSpec) { CliClass cls = compiler.GetClosedClass(typeSpec); List<MethodSpecTag> methodSpecs = new List<MethodSpecTag>(); foreach (CliVtableSlot vtableSlot in cls.VTable) { if (vtableSlot.MethodSignature.NumGenericParameters > 0) { methodSpecs.Add(null); continue; } CliMethodIndex methodIndex = vtableSlot.MethodIndex; if (methodIndex == null) throw new RpaCompileException("Can't generate vtable slot for abstract method"); methodSpecs.Add(ResolveVirtualMethod(compiler, cls, methodIndex)); } return methodSpecs; }
public RloMethodBody(Compiler compiler, HighMethod method, MethodSpecTag methodSpec, TypeSpecClassTag thisType, bool isStruct, RloInstantiationParameters instParams, MethodInstantiationPath methodInstantiationPath) { m_instantiationPath = methodInstantiationPath; m_methodSpec = methodSpec; HighMethodBody methodBody = method.MethodBody; TagRepository tagRepo = compiler.TagRepository; // Validate locals uint numParamArgs = (uint)method.MethodSignature.ParamTypes.Length; if (method.IsStatic) { if (methodBody.InstanceLocal != null) throw new Exception("Instance local in static method"); } else { HighLocal thisLocal = methodBody.InstanceLocal; if (thisLocal == null) throw new Exception("Missing instance local in instance method"); HighLocal.ETypeOfType expectedTypeOfType = isStruct ? HighLocal.ETypeOfType.ByRef : HighLocal.ETypeOfType.Value; if (thisLocal.TypeOfType != expectedTypeOfType || thisLocal.Type.Instantiate(tagRepo, instParams.TypeParams, instParams.MethodParams) != thisType) throw new Exception("Invalid this type for method"); } if (numParamArgs != (uint)methodBody.Args.Length) throw new Exception("Mismatched argument count in method body and signature"); for (uint i = 0; i < numParamArgs; i++) { HighLocal bodyArg = methodBody.Args[i]; MethodSignatureParam methodSigParam = method.MethodSignature.ParamTypes[i]; MethodSignatureParamTypeOfType tot = methodSigParam.TypeOfType; HighLocal.ETypeOfType expectedTypeOfType; switch (tot.Value) { case MethodSignatureParamTypeOfType.Values.ByRef: expectedTypeOfType = HighLocal.ETypeOfType.ByRef; break; case MethodSignatureParamTypeOfType.Values.TypedByRef: expectedTypeOfType = HighLocal.ETypeOfType.TypedByRef; break; case MethodSignatureParamTypeOfType.Values.Value: expectedTypeOfType = HighLocal.ETypeOfType.Value; break; default: throw new ArgumentException(); } if (bodyArg.TypeOfType != expectedTypeOfType) throw new Exception("Method body arg doesn't match signature"); } HighLocal instanceLocal = methodBody.InstanceLocal; RloMethodConverter methodConverter = new RloMethodConverter(compiler.TagRepository, instParams, method.MethodSignature.RetType, instanceLocal, methodBody.Args, methodBody.Locals); RloRegionConverter regionConverter = new RloRegionConverter(methodConverter, methodBody.MainRegion, true); m_locals = methodConverter.Locals2; m_args = methodConverter.Args; m_instanceLocal = methodConverter.InstanceLocal; m_returnType = methodConverter.ReturnType; m_entryRegion = new HighRegion(regionConverter.EntryNode); m_methodSignature = method.MethodSignature; RloFindPredecessorsAndSuccessorsPass psPass = new RloFindPredecessorsAndSuccessorsPass(compiler, this); psPass.Run(); RloCanonicalizeSsaTypesPass cstPass = new RloCanonicalizeSsaTypesPass(compiler, this); cstPass.Run(); RloInitPass initPass = new RloInitPass(compiler, this, psPass); initPass.Run(); RloInitExceptionsPass exceptionInitPass = new RloInitExceptionsPass(compiler, this); exceptionInitPass.Run(); }
public bool Create(Compiler compiler) { HighTypeDef typeDef = m_typeDef; foreach (TypeSpecClassTag ii in typeDef.ParentInterfaces) { if (!compiler.HaveCliOpenInterface(ii.TypeName)) return false; } Dictionary<TypeSpecClassTag, int> uniqueDeps = new Dictionary<TypeSpecClassTag, int>(); foreach (TypeSpecClassTag pi in typeDef.ParentInterfaces) { CliInterface ifc = compiler.GetClosedInterface(pi); if (!ifc.IsCreated) { ifc = compiler.GetClosedInterface(pi); throw new Exception(); } foreach (TypeSpecClassTag pipi in ifc.InterfaceImpls2) AddUniqueInterface(uniqueDeps, pipi); AddUniqueInterface(uniqueDeps, pi); } m_interfaceImpls = UnrollUniqueInterfaces(uniqueDeps); m_parentInterfaces = typeDef.ParentInterfaces; m_slots = typeDef.NewSlots; m_slotTagToCliSlot = new Dictionary<MethodDeclTag, uint>(); m_slotTagToRealSlot = new Dictionary<MethodDeclTag, uint>(); uint numGenericParameters = typeDef.NumGenericParameters; TypeSpecTag[] genericParameters = new TypeSpecTag[numGenericParameters]; for (uint i = 0; i < numGenericParameters; i++) { TypeSpecGenericParamTypeTag paramType = new TypeSpecGenericParamTypeTag(TypeSpecGenericParamTypeTag.Values.Var); TypeSpecTag paramTag = new TypeSpecGenericParamTag(paramType, i); paramTag = compiler.TagRepository.InternTypeSpec(paramTag); genericParameters[i] = paramTag; } m_numRealSlots = 0; uint cliSlot = 0; foreach (HighClassVtableSlot slot in m_slots) { if (m_slotTagToCliSlot.ContainsKey(slot.SlotTag)) throw new Exception("Duplicate interface vtable slot"); m_slotTagToCliSlot.Add(slot.SlotTag, cliSlot++); if (slot.Signature.NumGenericParameters > 0) m_slotTagToRealSlot.Add(slot.SlotTag, m_numRealSlots); } m_typeSpec = new TypeSpecClassTag(m_typeDef.TypeName, genericParameters); m_typeSpec = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(m_typeSpec); m_isCreated = true; return true; }
public CliInterface GetClosedInterface(TypeSpecClassTag typeSpec) { CliInterface ifc; if (m_closedInterfaces.TryGetValue(typeSpec, out ifc)) return ifc; ifc = m_openInterfaces.Lookup(typeSpec.TypeName).Instantiate(this, typeSpec.ArgTypes); m_closedInterfaces.Add(typeSpec, ifc); return ifc; }
private static TypeSpecClassTag[] UnrollUniqueInterfaces(Dictionary<TypeSpecClassTag, int> uniqueDeps) { TypeSpecClassTag[] interfaceImpls = new TypeSpecClassTag[uniqueDeps.Count]; foreach (KeyValuePair<TypeSpecClassTag, int> kvp in uniqueDeps) interfaceImpls[kvp.Value] = kvp.Key; return interfaceImpls; }
public CliClass GetClosedClass(TypeSpecClassTag typeSpec) { CliClass cls; if (m_closedClasses.TryGetValue(typeSpec, out cls)) return cls; cls = m_openClasses.Lookup(typeSpec.TypeName).Instantiate(this, typeSpec.ArgTypes); m_closedClasses.Add(typeSpec, cls); return cls; }
private uint RecursiveDevirtualizeInterfaceMethod(CliClass cls, TypeSpecClassTag ifcSpec, uint ifcSlotIndex) { // First, look for an exact match, but only on this class level foreach (CliInterfaceImpl impl in cls.InterfaceImpls) { if (impl.Interface == ifcSpec) { CliInterfaceImplSlot slot = impl.IfcSlotToClassVtableSlot[ifcSlotIndex]; // Only use the exact match if it has a new implementation. // This is non-standard, but reflects .NET's behavior. // See TestInheritedImplementationDeprioritization. if (slot.HaveNewImpl) return slot.ClassVTableSlot; break; } } // Otherwise, check all interfaces uint? bestSlotTDO = null; CliInterfaceImplSlot? bestSlot = null; foreach (CliInterfaceImpl impl in cls.InterfaceImpls) { TypeSpecClassTag implInterface = impl.Interface; if (m_assignabilityResolver.ResolveGenericVariantAssignableTo(ifcSpec, implInterface) == AssignabilityResolver.ConversionType.InterfaceToInterface) { CliInterfaceImplSlot slot = impl.IfcSlotToClassVtableSlot[ifcSlotIndex]; if (slot.HaveNewImpl) { uint tdo = cls.TypeDeclarationOrder[implInterface]; if (bestSlotTDO.HasValue == false || tdo < bestSlotTDO) { bestSlotTDO = tdo; bestSlot = slot; } } } } if (bestSlot.HasValue) return bestSlot.Value.ClassVTableSlot; CliClass parentClass = cls.ParentClass; if (parentClass == null) throw new Exception("Internal error: Unresolvable interface method"); return RecursiveDevirtualizeInterfaceMethod(parentClass, ifcSpec, ifcSlotIndex); }
public override TypeSpecTag Instantiate(TagRepository repo, TypeSpecTag[] argTypes) { if (m_argTypes.Length == 0) return this; List<TypeSpecTag> newArgTypes = new List<TypeSpecTag>(); foreach (TypeSpecTag argType in m_argTypes) newArgTypes.Add(argType.Instantiate(repo, argTypes)); TypeSpecClassTag newSpec = new TypeSpecClassTag(m_typeNameTag, newArgTypes.ToArray()); return repo.InternTypeSpec(newSpec); }
public TypeSpecMulticastDelegateTag(TypeSpecClassTag delegateClass) { m_delegateClass = delegateClass; }
private List<MethodHandle> GenerateVTableForBox(Compiler compiler, TypeSpecBoxTag typeSpec, VTableGenerationCache vtCache) { TypeSpecClassTag containedType = typeSpec.ContainedType; List<MethodSpecTag> baseSpecs = GenerateMethodSpecsForClass(compiler, containedType); IList<MethodSpecTag> vtMethodSpecs = vtCache.ValueTypeMethodSpecs; if (vtMethodSpecs == null) { TypeNameTag valueTypeName = new TypeNameTag("mscorlib", "System", "ValueType"); valueTypeName = compiler.TagRepository.InternTypeName(valueTypeName); TypeSpecClassTag valueTypeSpec = new TypeSpecClassTag(valueTypeName, new TypeSpecTag[0]); valueTypeSpec = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(valueTypeSpec); vtMethodSpecs = GenerateMethodSpecsForClass(compiler, valueTypeSpec); vtCache.ValueTypeMethodSpecs = vtMethodSpecs; } List<MethodHandle> methodHandles = new List<MethodHandle>(); for (int slotIndex = 0; slotIndex < baseSpecs.Count; slotIndex++) { MethodSpecTag methodSpec = baseSpecs[slotIndex]; if (methodSpec == null) { methodHandles.Add(null); continue; } if (slotIndex < vtMethodSpecs.Count && vtMethodSpecs[slotIndex] == methodSpec) { MethodSpecTag slotSpec = vtMethodSpecs[slotIndex]; if (slotSpec == methodSpec) { MethodDeclTag slotDecl = vtMethodSpecs[slotIndex].MethodDecl; // Generate implementations for value-sensitive slots if (slotDecl.Name == "Equals") { methodHandles.Add(compiler.InstantiateMethod(new GeneratedMethods.GMBoxedValueTypeEquals(typeSpec, vtCache), m_instantiationPath)); continue; } else if (slotDecl.Name == "GetHashCode") { methodHandles.Add(compiler.InstantiateMethod(new GeneratedMethods.GMBoxedValueTypeGetHashCode(typeSpec, vtCache), m_instantiationPath)); continue; } } } // If not sensitive, then use the method spec and generate a box thunk methodHandles.Add(compiler.InstantiateMethod(new GeneratedMethods.GMBoxThunk(methodSpec), m_instantiationPath)); } return methodHandles; }
private static void CheckArithOperand(HighSsaRegister reg, TypeSpecClassTag expectedType) { if (reg.ValueType != HighValueType.ConstantValue && reg.ValueType != HighValueType.ValueValue) throw new RpaCompileException("Unexpected value type in arith instruction"); if (reg.Type != expectedType) throw new RpaCompileException("Unexpected operand type in arith instruction"); }
private void ReadClassDefinitions(TagRepository rpa, CatalogReader catalog, BinaryReader reader) { m_parentClass = null; if (m_semantics == TypeSemantics.Class) { m_isSealed = reader.ReadBoolean(); m_isAbstract = reader.ReadBoolean(); uint parentClassIndex = reader.ReadUInt32(); if (parentClassIndex == 0) { if (m_typeName.AssemblyName != "mscorlib" || m_typeName.TypeNamespace != "System" || m_typeName.TypeName != "Object") throw new Exception("Parentless class is not System.Object"); } else { TypeSpecTag parentClass = catalog.GetTypeSpec(parentClassIndex - 1); TypeSpecClassTag clsTag = parentClass as TypeSpecClassTag; if (clsTag == null) throw new Exception("Parent class spec wasn't a class"); m_parentClass = clsTag; } } if (m_semantics == TypeSemantics.Struct || m_semantics == TypeSemantics.Enum) { m_isSealed = true; m_isAbstract = false; } if (m_semantics == TypeSemantics.Interface) { m_isSealed = false; m_isAbstract = true; ReadGenericParameterVariance(reader); } uint numInterfaces = reader.ReadUInt32(); TypeSpecClassTag[] interfaces = new TypeSpecClassTag[numInterfaces]; for (uint i = 0; i < numInterfaces; i++) { TypeSpecTag typeSpec = catalog.GetTypeSpec(reader.ReadUInt32()); TypeSpecClassTag classTag = typeSpec as TypeSpecClassTag; if (classTag == null) throw new RpaLoadException("Interface implementation is not a class tag"); interfaces[i] = classTag; } m_parentInterfaces = interfaces; this.ReadVtableThunks(rpa, catalog, reader); if (m_semantics == TypeSemantics.Class || m_semantics == TypeSemantics.Struct) { uint numMethods = reader.ReadUInt32(); m_methods = new HighMethod[numMethods]; for (uint i = 0; i < numMethods; i++) { HighMethod method = HighMethod.Read(rpa, catalog, reader, m_typeName); m_methods[i] = method; } uint numInstanceFields = reader.ReadUInt32(); m_instanceFields = new HighField[numInstanceFields]; for (uint i = 0; i < numInstanceFields; i++) { HighField field = HighField.Read(rpa, catalog, reader); m_instanceFields[i] = field; } this.ReadInterfaceImplementations(rpa, catalog, reader); } }
private CliInterfaceImpl(CliInterfaceImpl baseImpl, Compiler compiler, TypeSpecTag[] argTypes) { m_interface = (TypeSpecClassTag)baseImpl.m_interface.Instantiate(compiler.TagRepository, argTypes); m_ifcSlotToClassVtableSlot = baseImpl.m_ifcSlotToClassVtableSlot; }
public CliInterfaceImpl(TypeSpecClassTag ifc, CliInterfaceImplSlot[] ifcSlotToClassVtableSlot) { m_interface = ifc; m_ifcSlotToClassVtableSlot = ifcSlotToClassVtableSlot; }
public TypeSpecBoxTag(TypeSpecClassTag containedType) { m_containedType = containedType; }
public GMMulticastDelegateInvoke(TypeSpecClassTag dt, VTableGenerationCache vtCache) { m_dt = dt; m_vtCache = vtCache; }
private void ProcessInstruction(HighCfgNode cfgNode, HighInstruction instr, List<HighInstruction> newInstrs) { bool validationOnly = true; { IBranchingInstruction brInstr = instr as IBranchingInstruction; if (brInstr != null) { brInstr.VisitSuccessors(delegate (ref HighCfgEdge edge) { HighCfgNode dest = edge.Dest.Value; foreach (HighCfgNodeHandle pred in dest.Predecessors) if (pred.Value == cfgNode) return; throw new RpaCompileException("Branching instruction jumps to undeclared predecessor"); }); } } switch (instr.Opcode) { case HighInstruction.Opcodes.LoadLocal: { LoadLocalInstruction tInstr = (LoadLocalInstruction)instr; HighSsaRegister dest = tInstr.Dest; HighLocal local = tInstr.Local; switch (local.TypeOfType) { case HighLocal.ETypeOfType.ByRef: if (dest.ValueType != HighValueType.ManagedPtr) throw new RpaCompileException("Illegal LoadLocal"); break; case HighLocal.ETypeOfType.TypedByRef: throw new NotImplementedException(); case HighLocal.ETypeOfType.Value: if (dest.ValueType != HighValueType.ValueValue && dest.ValueType != HighValueType.ReferenceValue) throw new RpaCompileException("Illegal LoadLocal"); break; default: throw new Exception(); } if (dest.Type != local.Type) throw new RpaCompileException("Type mismatch in LoadLocal"); } break; case HighInstruction.Opcodes.AllocArray: { AllocArrayInstruction tInstr = (AllocArrayInstruction)instr; HighSsaRegister dest = tInstr.Dest; if (dest == null) throw new RpaCompileException("AllocArray has no destination"); if (dest.ValueType != HighValueType.ReferenceValue || !(dest.Type is TypeSpecArrayTag)) throw new RpaCompileException("AllocArray destination is not an array"); TypeSpecArrayTag type = (TypeSpecArrayTag)dest.Type; if (type.Rank != (uint)tInstr.Sizes.Length) throw new RpaCompileException("AllocArray index count doesn't match destination type rank"); foreach (HighSsaRegister sz in tInstr.Sizes) { switch (sz.ValueType) { case HighValueType.ConstantValue: case HighValueType.ValueValue: break; default: throw new RpaCompileException("AllocArray index is invalid"); } if (sz.Type != m_nativeIntType) throw new RpaCompileException("AllocArray index is invalid"); } this.Compiler.GetRloVTable(dest.Type, GenerateMethodInstantiationPath(tInstr.CodeLocation)); } break; case HighInstruction.Opcodes.AllocObj: { AllocObjInstruction tInstr = (AllocObjInstruction)instr; HighSsaRegister dest = tInstr.Dest; if (dest == null) throw new RpaCompileException("AllocObj has no destination"); if (dest.ValueType != HighValueType.ReferenceValue) throw new RpaCompileException("AllocObj destination is not a reference type"); TypeSpecClassTag destType = dest.Type as TypeSpecClassTag; if (destType == null) throw new RpaCompileException("AllocObj destination type is not a class"); HighTypeDef typeDef = this.Compiler.GetTypeDef(destType.TypeName); if (typeDef.Semantics != TypeSemantics.Class) throw new RpaCompileException("AllocObj created non-class"); if (typeDef.IsAbstract) throw new RpaCompileException("AllocObj created class is abstract"); this.Compiler.GetRloVTable(destType, GenerateMethodInstantiationPath(tInstr.CodeLocation)); } break; case HighInstruction.Opcodes.Box: { BoxInstruction tInstr = (BoxInstruction)instr; HighSsaRegister dest = tInstr.Dest; HighSsaRegister src = tInstr.Src; if (dest == null) throw new RpaCompileException("Box has no destination"); if ((src.ValueType == HighValueType.ConstantValue || src.ValueType == HighValueType.ValueValue) && dest.ValueType == HighValueType.BoxedValue) { // Normally don't do anything, leave box as canonical // In the case of Nullable`1 only, convert the box instruction if (dest.Type != src.Type) { if (!(src.Type is TypeSpecClassTag)) throw new RpaCompileException("Invalid box source type"); TypeSpecClassTag srcClass = (TypeSpecClassTag)src.Type; TypeNameTag srcClassName = srcClass.TypeName; if (srcClassName.ContainerType != null || srcClassName.AssemblyName != "mscorlib" || srcClassName.TypeNamespace != "System" || srcClassName.TypeName != "Nullable`1" || srcClass.ArgTypes.Length != 1) throw new RpaCompileException("Invalid box source type"); TypeSpecTag srcSubType = srcClass.ArgTypes[0]; if (dest.Type != srcSubType) throw new RpaCompileException("Nullable box type mixmatch"); validationOnly = false; TypeNameTag clarityToolsName = new TypeNameTag("mscorlib", "Clarity", "Tools"); clarityToolsName = this.Compiler.TagRepository.InternTypeName(clarityToolsName); TypeSpecClassTag clarityToolsClass = new TypeSpecClassTag(clarityToolsName, new TypeSpecTag[0]); clarityToolsClass = (TypeSpecClassTag)this.Compiler.TagRepository.InternTypeSpec(clarityToolsClass); TypeNameTag nullableName = new TypeNameTag("mscorlib", "System", "Nullable`1", 1, null); nullableName = this.Compiler.TagRepository.InternTypeName(nullableName); TypeSpecGenericParamTypeTag mArgType = new TypeSpecGenericParamTypeTag(TypeSpecGenericParamTypeTag.Values.MVar); TypeSpecGenericParamTag m0Type = new TypeSpecGenericParamTag(mArgType, 0); m0Type = (TypeSpecGenericParamTag)this.Compiler.TagRepository.InternTypeSpec(m0Type); TypeSpecClassTag nullableM0Class = new TypeSpecClassTag(nullableName, new TypeSpecTag[] { m0Type }); nullableM0Class = (TypeSpecClassTag)this.Compiler.TagRepository.InternTypeSpec(nullableM0Class); MethodSignatureParam[] bnDeclParams = new MethodSignatureParam[] { new MethodSignatureParam(nullableM0Class, new MethodSignatureParamTypeOfType(MethodSignatureParamTypeOfType.Values.Value)) }; MethodSignatureTag bnDeclSignature = new MethodSignatureTag(1, m_objectType, bnDeclParams); bnDeclSignature = this.Compiler.TagRepository.InternMethodSignature(bnDeclSignature); MethodDeclTag boxNullableDecl = new MethodDeclTag("BoxNullable", bnDeclSignature, clarityToolsName); boxNullableDecl = this.Compiler.TagRepository.InternMethodDeclTag(boxNullableDecl); MethodSpecTag bnMethodSpec = new MethodSpecTag(MethodSlotType.Static, new TypeSpecTag[] { srcSubType }, clarityToolsClass, boxNullableDecl); bnMethodSpec = this.Compiler.TagRepository.InternMethodSpec(bnMethodSpec); MethodHandle hdl = this.Compiler.InstantiateMethod(new MethodSpecMethodKey(bnMethodSpec), GenerateMethodInstantiationPath(tInstr.CodeLocation)); newInstrs.Add(new Instructions.CallRloStaticMethodInstruction(tInstr.CodeLocation, hdl, dest, new HighSsaRegister[] { src })); } else { TypeSpecBoxTag boxType = new TypeSpecBoxTag((TypeSpecClassTag)dest.Type); boxType = (TypeSpecBoxTag)this.Compiler.TagRepository.InternTypeSpec(boxType); this.Compiler.GetRloVTable(boxType, GenerateMethodInstantiationPath(tInstr.CodeLocation)); } } else if (src.ValueType == HighValueType.ReferenceValue && dest.ValueType == HighValueType.ReferenceValue) { if (dest.Type != src.Type) throw new RpaCompileException("Box instruction destination is a different type from source"); // Source should never be ConstantString at this stage. // Boxing a reference type converts to a copy validationOnly = false; newInstrs.Add(new Instructions.CopyInstruction(tInstr.CodeLocation, dest, src)); } } break; case HighInstruction.Opcodes.Arith: { ArithInstruction tInstr = (ArithInstruction)instr; TypeSpecClassTag expectedClass = ExpectedClassForArithType(tInstr.ArithType); if (tInstr.CheckOverflow) { switch (tInstr.ArithType) { case NumberArithType.Int32: case NumberArithType.Int64: case NumberArithType.NativeInt: case NumberArithType.NativeUInt: case NumberArithType.UInt32: case NumberArithType.UInt64: break; case NumberArithType.Float32: case NumberArithType.Float64: throw new RpaCompileException("Check overflow flag on flowing point arith operation"); default: throw new Exception(); } } CheckArithDest(tInstr.Dest, expectedClass); CheckArithOperand(tInstr.Left, expectedClass); CheckArithOperand(tInstr.Right, expectedClass); } break; case HighInstruction.Opcodes.BranchCompareNumbers: { BranchCompareNumbersInstruction tInstr = (BranchCompareNumbersInstruction)instr; TypeSpecClassTag expectedClass = ExpectedClassForArithType(tInstr.ArithType); CheckArithOperand(tInstr.Left, expectedClass); CheckArithOperand(tInstr.Right, expectedClass); } break; case HighInstruction.Opcodes.DynamicCast: { DynamicCastInstruction tInstr = (DynamicCastInstruction)instr; if (tInstr.Dest != null) { switch (tInstr.Dest.ValueType) { case HighValueType.BoxedValue: case HighValueType.ReferenceValue: break; default: throw new RpaCompileException("Illegal destination type for dynamic cast instruction"); } } switch (tInstr.Src.ValueType) { case HighValueType.BoxedValue: case HighValueType.ConstantString: case HighValueType.Null: case HighValueType.ReferenceValue: break; default: throw new RpaCompileException("Illegal source type for dynamic cast instruction."); } } break; case HighInstruction.Opcodes.ForceDynamicCast: { ForceDynamicCastInstruction tInstr = (ForceDynamicCastInstruction)instr; if (tInstr.Dest != null) { switch (tInstr.Dest.ValueType) { case HighValueType.BoxedValue: case HighValueType.ReferenceValue: break; default: throw new RpaCompileException("Illegal destination type for force dynamic cast instruction"); } } switch (tInstr.Src.ValueType) { case HighValueType.BoxedValue: case HighValueType.ConstantString: case HighValueType.Null: case HighValueType.ReferenceValue: break; default: throw new RpaCompileException("Illegal source type for force dynamic cast instruction."); } } break; case HighInstruction.Opcodes.GetArrayElementPtr: { GetArrayElementPtrInstruction tInstr = (GetArrayElementPtrInstruction)instr; HighSsaRegister arraySrc = tInstr.ArraySrc; if (arraySrc.ValueType != HighValueType.ReferenceValue) throw new RpaCompileException("GetArrayElementPtr instruction array is not a reference"); TypeSpecArrayTag arrayType = arraySrc.Type as TypeSpecArrayTag; if (arrayType == null) throw new RpaCompileException("GetArrayElementPtr instruction arrays source is not an array"); if ((uint)tInstr.Indexes.Length != arrayType.Rank) throw new RpaCompileException("GetArrayElementPtr instruction array source rank doesn't match index count"); HighSsaRegister dest = tInstr.Dest; if (dest != null) { if (dest.ValueType != HighValueType.ManagedPtr) throw new RpaCompileException("GetArrayElementPtr destination is not a managed pointer"); if (dest.Type != arrayType.SubscriptType) throw new RpaCompileException("GetArrayElementPtr destination does not match subscript type"); } } break; case HighInstruction.Opcodes.CompareRefs: { CompareRefsInstruction tInstr = (CompareRefsInstruction)instr; HighSsaRegister[] sources = new HighSsaRegister[2]; sources[0] = tInstr.SrcA; sources[1] = tInstr.SrcB; if (tInstr.Dest != null && tInstr.Dest.ValueType != HighValueType.ValueValue && tInstr.Dest.Type != m_int32Type) throw new RpaCompileException("CompareRefs destination is not an int"); bool isSideConverted = false; UpdateRefCompare(tInstr.CodeLocation, sources, newInstrs, out isSideConverted); if (isSideConverted) { validationOnly = false; newInstrs.Add(new CompareRefsInstruction(tInstr.CodeLocation, tInstr.Dest, sources[0], sources[1], tInstr.EqualValue, tInstr.NotEqualValue)); } } break; case HighInstruction.Opcodes.BranchCompareRefs: { BranchCompareRefsInstruction tInstr = (BranchCompareRefsInstruction)instr; HighSsaRegister[] sources = new HighSsaRegister[2]; sources[0] = tInstr.SrcA; sources[1] = tInstr.SrcB; bool isSideConverted = false; UpdateRefCompare(tInstr.CodeLocation, sources, newInstrs, out isSideConverted); if (isSideConverted) { validationOnly = false; newInstrs.Add(new BranchCompareRefsInstruction(tInstr.CodeLocation, sources[0], sources[1], tInstr.EqualEdge.Dest, tInstr.NotEqualEdge.Dest)); } } break; case HighInstruction.Opcodes.GetStaticFieldAddr: { GetStaticFieldAddrInstruction tInstr = (GetStaticFieldAddrInstruction)instr; TypeSpecClassTag classSpec = tInstr.StaticType as TypeSpecClassTag; if (classSpec == null) throw new RpaCompileException("GetStaticFieldAddr type is not a class"); CliClass cls = this.Compiler.GetClosedClass(classSpec); uint fieldIndex; if (!cls.NameToStaticFieldSlot.TryGetValue(tInstr.FieldName, out fieldIndex)) throw new RpaCompileException("GetStaticFieldAddr could not match static field name"); HighSsaRegister dest = tInstr.Dest; if (dest != null) { if (dest.ValueType != HighValueType.ManagedPtr) throw new RpaCompileException("GetStaticFieldAddr dest is not a managed pointer"); if (dest.Type != cls.StaticFields[fieldIndex].Type) throw new RpaCompileException("GetStaticFieldAddr dest type does not match field type"); } } break; case HighInstruction.Opcodes.BranchRefNull: { BranchRefNullInstruction tInstr = (BranchRefNullInstruction)instr; HighSsaRegister src = tInstr.Src; switch (src.ValueType) { case HighValueType.BoxedValue: case HighValueType.ConstantString: case HighValueType.Null: case HighValueType.ReferenceValue: break; default: throw new RpaCompileException("BranchRefNull source is not a reference"); } } break; case HighInstruction.Opcodes.GetTypeInfo: { GetTypeInfoInstruction tInstr = (GetTypeInfoInstruction)instr; if (tInstr.Dest.ValueType != HighValueType.ValueValue || tInstr.Dest.Type != m_runtimeTypeHandleType) throw new RpaCompileException("GetTypeInfo destination is not the correct type"); } break; case HighInstruction.Opcodes.LoadPtr: { LoadPtrInstruction tInstr = (LoadPtrInstruction)instr; if (tInstr.Dest != null) { switch (tInstr.Dest.ValueType) { case HighValueType.ReferenceValue: case HighValueType.ValueValue: break; default: throw new RpaCompileException("LoadPtr destination has an invalid value type"); } } if (tInstr.Src.ValueType != HighValueType.ManagedPtr) throw new RpaCompileException("LoadPtr source is not a managed pointer"); if (tInstr.Src.Type != tInstr.Dest.Type) throw new RpaCompileException("LoadPtr source type is not the same as dest type"); } break; case HighInstruction.Opcodes.PtrField: { PtrFieldInstruction tInstr = (PtrFieldInstruction)instr; HighSsaRegister dest = tInstr.Dest; HighSsaRegister src = tInstr.Src; if (src.ValueType != HighValueType.ManagedPtr) throw new RpaCompileException("PtrField source not a field"); TypeSpecClassTag classSpec = src.Type as TypeSpecClassTag; if (classSpec == null) throw new RpaCompileException("PtrField source is not a class"); CliClass cls = this.Compiler.GetClosedClass(classSpec); uint fieldIndex; if (!cls.NameToInstanceFieldSlot.TryGetValue(tInstr.FieldName, out fieldIndex)) throw new RpaCompileException("PtrField field does not exist"); if (dest != null) { if (dest.ValueType != HighValueType.ManagedPtr) throw new RpaCompileException("PtrField dest is not a field"); HighField fld = cls.InstanceFields[fieldIndex]; if (fld.Type != dest.Type) throw new RpaCompileException("PtrField dest type does not match field type"); } } break; case HighInstruction.Opcodes.RefField: { RefFieldInstruction tInstr = (RefFieldInstruction)instr; HighSsaRegister dest = tInstr.Dest; HighSsaRegister src = tInstr.Src; if (src.ValueType != HighValueType.ReferenceValue) throw new RpaCompileException("RefField source not a field"); TypeSpecClassTag classSpec = src.Type as TypeSpecClassTag; if (classSpec == null) throw new RpaCompileException("RefField source is not a class"); CliClass cls = this.Compiler.GetClosedClass(classSpec); uint fieldIndex; if (!cls.NameToInstanceFieldSlot.TryGetValue(tInstr.FieldName, out fieldIndex)) throw new RpaCompileException("RefField field does not exist"); if (dest != null) { if (dest.ValueType != HighValueType.ManagedPtr) throw new RpaCompileException("RefField dest is not a field"); HighField fld = cls.InstanceFields[fieldIndex]; if (fld.Type != dest.Type) throw new RpaCompileException("RefField dest type does not match field type"); } } break; case HighInstruction.Opcodes.CallInstanceMethod: { CallInstanceMethodInstruction tInstr = (CallInstanceMethodInstruction)instr; HighSsaRegister instance = tInstr.InstanceSrc; HighSsaRegister[] parameters = tInstr.Parameters; HighSsaRegister dest = tInstr.ReturnDest; TypeSpecClassTag classSpec = tInstr.MethodSpec.DeclaringClass; if (instance.Type != tInstr.MethodSpec.DeclaringClass) throw new RpaCompileException("CallInstanceMethod target is not the same class as the method being called"); HighTypeDef typeDef = this.Compiler.GetTypeDef(classSpec.TypeName); switch (typeDef.Semantics) { case TypeSemantics.Interface: throw new RpaCompileException("CallInstanceMethod target is an interface"); case TypeSemantics.Class: case TypeSemantics.Delegate: case TypeSemantics.Enum: case TypeSemantics.Struct: break; default: throw new ArgumentException(); } switch (instance.ValueType) { case HighValueType.ConstantString: case HighValueType.ReferenceValue: case HighValueType.ManagedPtr: break; // BoxedValues should never have methods called on them directly (use unbox first) // Calls on null at this stage are illegal default: throw new RpaCompileException("CallInstanceMethod source type is invalid"); } CliClass cliClass = this.Compiler.GetClosedClass(classSpec); MethodSpecTag methodSpec = tInstr.MethodSpec; if (methodSpec.MethodSlotType != MethodSlotType.Instance) throw new RpaCompileException("CallInstanceMethod method is not an instance method"); uint methodSlot; if (!cliClass.DeclTagToMethod.TryGetValue(methodSpec.MethodDecl, out methodSlot)) throw new RpaCompileException("CallInstanceMethod method wasn't found"); HighMethod method = cliClass.Methods[methodSlot]; if (method.IsStatic) throw new RpaCompileException("CallInstanceMethod method is static"); CheckMethodCall(methodSpec, dest, parameters, method.MethodSignature); MethodHandle methodHandle = this.Compiler.InstantiateMethod(new MethodSpecMethodKey(methodSpec), GenerateMethodInstantiationPath(tInstr.CodeLocation)); validationOnly = false; newInstrs.Add(new Instructions.CallRloInstanceMethodInstruction(tInstr.CodeLocation, methodHandle, tInstr.ReturnDest, tInstr.InstanceSrc, tInstr.Parameters)); } break; case HighInstruction.Opcodes.CallStaticMethod: { CallStaticMethodInstruction tInstr = (CallStaticMethodInstruction)instr; HighSsaRegister[] parameters = tInstr.Parameters; HighSsaRegister dest = tInstr.ReturnDest; TypeSpecClassTag classSpec = tInstr.MethodSpec.DeclaringClass; HighTypeDef typeDef = this.Compiler.GetTypeDef(classSpec.TypeName); switch (typeDef.Semantics) { case TypeSemantics.Interface: throw new RpaCompileException("CallStaticMethod target is an interface"); case TypeSemantics.Class: case TypeSemantics.Delegate: case TypeSemantics.Enum: case TypeSemantics.Struct: break; default: throw new ArgumentException(); } CliClass cliClass = this.Compiler.GetClosedClass(classSpec); MethodSpecTag methodSpec = tInstr.MethodSpec; if (methodSpec.MethodSlotType != MethodSlotType.Static) throw new RpaCompileException("CallStaticMethod method is not an instance method"); uint methodSlot; if (!cliClass.DeclTagToMethod.TryGetValue(methodSpec.MethodDecl, out methodSlot)) throw new RpaCompileException("CallStaticMethod method wasn't found"); HighMethod method = cliClass.Methods[methodSlot]; if (!method.IsStatic) throw new RpaCompileException("CallStaticMethod method is not static"); CheckMethodCall(methodSpec, dest, parameters, method.MethodSignature); MethodHandle methodHandle = this.Compiler.InstantiateMethod(new MethodSpecMethodKey(methodSpec), GenerateMethodInstantiationPath(tInstr.CodeLocation)); validationOnly = false; newInstrs.Add(new Instructions.CallRloStaticMethodInstruction(tInstr.CodeLocation, methodHandle, tInstr.ReturnDest, tInstr.Parameters)); } break; case HighInstruction.Opcodes.CallVirtualMethod: { CallVirtualMethodInstruction tInstr = (CallVirtualMethodInstruction)instr; HighSsaRegister instance = tInstr.InstanceSrc; HighSsaRegister[] parameters = tInstr.Parameters; HighSsaRegister dest = tInstr.ReturnDest; MethodSpecTag methodSpec = tInstr.MethodSpec; if (methodSpec.MethodSlotType != MethodSlotType.Virtual) throw new RpaCompileException("CallVirtualMethod target is not virtual"); TypeSpecClassTag classSpec = methodSpec.DeclaringClass; if (instance.Type != tInstr.MethodSpec.DeclaringClass) throw new RpaCompileException("CallVirtualMethod target is not the same class as the method being called"); HighTypeDef typeDef = this.Compiler.GetTypeDef(classSpec.TypeName); bool isInterface; switch (typeDef.Semantics) { case TypeSemantics.Interface: isInterface = true; break; case TypeSemantics.Class: case TypeSemantics.Delegate: case TypeSemantics.Enum: case TypeSemantics.Struct: isInterface = false; break; default: throw new ArgumentException(); } switch (instance.ValueType) { case HighValueType.ConstantString: case HighValueType.ReferenceValue: case HighValueType.ManagedPtr: break; // BoxedValues should never have methods called on them directly (use unbox first) // Calls on null at this stage are illegal default: throw new RpaCompileException("CallVirtualMethod source type is invalid"); } if (methodSpec.GenericParameters.Length != 0) throw new RpaCompileException("Can't call an unconstrained generic virtual method"); CliVtableSlot vtableSlot; uint vtableSlotIndex; MethodSignatureTag methodSignature; if (isInterface) { CliInterface ifc = this.Compiler.GetClosedInterface(classSpec); vtableSlotIndex = ifc.CliSlotForSlotTag(methodSpec.MethodDecl); methodSignature = ifc.Slots[vtableSlotIndex].Signature; } else { CliClass cliClass = this.Compiler.GetClosedClass(classSpec); if (!cliClass.DeclTagToVTableSlot.TryGetValue(methodSpec.MethodDecl, out vtableSlotIndex)) throw new RpaCompileException("CallVirtualMethod method wasn't found"); methodSignature = cliClass.VTable[vtableSlotIndex].MethodSignature; } if (methodSpec.MethodSlotType != MethodSlotType.Virtual) throw new RpaCompileException("CallVirtualMethod method is not an instance method"); CheckMethodCall(methodSpec, dest, parameters, methodSignature); validationOnly = false; if (isInterface) newInstrs.Add(new Instructions.CallRloVirtualMethodInstruction(tInstr.CodeLocation, vtableSlotIndex, tInstr.ReturnDest, tInstr.InstanceSrc, tInstr.Parameters)); else newInstrs.Add(new Instructions.CallRloInterfaceMethodInstruction(tInstr.CodeLocation, vtableSlotIndex, tInstr.ReturnDest, tInstr.InstanceSrc, tInstr.Parameters)); } break; case HighInstruction.Opcodes.CallConstrainedVirtualMethod: { validationOnly = false; CallConstrainedVirtualMethodInstruction tInstr = (CallConstrainedVirtualMethodInstruction)instr; HighSsaRegister refInstance = tInstr.InstanceSrc; HighSsaRegister[] parameters = tInstr.Parameters; HighSsaRegister dest = tInstr.ReturnDest; MethodSpecTag methodSpec = tInstr.MethodSpec; if (methodSpec.MethodSlotType != MethodSlotType.Virtual) throw new RpaCompileException("CallConstrainedVirtualMethod target is not virtual"); TypeSpecTag constraintType = tInstr.ConstraintType; if (refInstance.ValueType != HighValueType.ManagedPtr) throw new RpaCompileException("CallConstrainedVirtualMethod target is not a managed pointer"); if (refInstance.Type != constraintType) throw new RpaCompileException("CallConstrainedVirtualMethod target type is different from constraint type"); TypeSpecTag instanceType = refInstance.Type; bool isValueType; bool isInterface; switch (instanceType.SubType) { case TypeSpecTag.SubTypeCode.Array: isValueType = false; isInterface = false; break; case TypeSpecTag.SubTypeCode.Class: { TypeSpecClassTag instanceClassTag = (TypeSpecClassTag)instanceType; HighTypeDef instanceTypeDef = this.Compiler.GetTypeDef(instanceClassTag.TypeName); switch (instanceTypeDef.Semantics) { case TypeSemantics.Class: case TypeSemantics.Delegate: isValueType = false; isInterface = false; break; case TypeSemantics.Interface: isValueType = false; isInterface = true; break; case TypeSemantics.Enum: case TypeSemantics.Struct: isValueType = true; isInterface = false; break; default: throw new NotSupportedException(); } } break; default: throw new RpaCompileException("Invalid instance type in CallConstrainedVirtualMethod"); }; if (isValueType) { TypeSpecClassTag instanceClassTag = (TypeSpecClassTag)refInstance.Type; CliClass cls = this.Compiler.GetClosedClass(instanceClassTag); TypeSpecClassTag methodDeclaringClass = methodSpec.DeclaringClass; HighTypeDef methodTypeDef = this.Compiler.GetTypeDef(methodDeclaringClass.TypeName); HighMethod resolvedMethod; uint vtableSlotIndex; if (methodTypeDef.Semantics != TypeSemantics.Interface) { if (!cls.DeclTagToVTableSlot.TryGetValue(methodSpec.MethodDecl, out vtableSlotIndex)) throw new RpaCompileException("CallConstrainedVirtualMethod virtual method was not found"); } else { CliInterface ifc = this.Compiler.GetClosedInterface(methodDeclaringClass); uint ifcSlot = ifc.CliSlotForSlotTag(methodSpec.MethodDecl); vtableSlotIndex = this.Compiler.DevirtualizeInterfaceMethod(cls, methodDeclaringClass, ifcSlot); } CliMethodIndex methodIndex = cls.VTable[vtableSlotIndex].MethodIndex; if (methodIndex == null) throw new Exception("Invalid method index (???)"); uint depth = methodIndex.Depth; if (depth == 0) { resolvedMethod = cls.Methods[methodIndex.Index]; if (resolvedMethod.MethodSignature.NumGenericParameters != 0) throw new NotImplementedException(); if (cls.TypeSpec != instanceType) throw new RpaCompileException("CallConstrainedVirtualMethod instance type doesn't match method (???)"); int numParameters = parameters.Length; HighSsaRegister tempDest = null; HighSsaRegister[] tempParameters = new HighSsaRegister[numParameters]; MethodSignatureTag signature = resolvedMethod.MethodSignature; if (signature.ParamTypes.Length != numParameters) throw new RpaCompileException("CallConstrainedVirtualMethod method call parameter mismatch"); for (int i = 0; i < numParameters; i++) { HighValueType hvt; MethodSignatureParam sigParam = signature.ParamTypes[i]; switch (sigParam.TypeOfType.Value) { case MethodSignatureParamTypeOfType.Values.ByRef: hvt = HighValueType.ManagedPtr; break; case MethodSignatureParamTypeOfType.Values.Value: hvt = this.Compiler.TypeIsValueType(sigParam.Type) ? HighValueType.ValueValue : HighValueType.ReferenceValue; break; default: throw new NotImplementedException(); } if (hvt == HighValueType.ReferenceValue) { HighSsaRegister tempParam = new HighSsaRegister(hvt, sigParam.Type, null); EmitPassiveRefConversion(tInstr.CodeLocation, tempParam, parameters[i], newInstrs); tempParameters[i] = tempParam; } else tempParameters[i] = parameters[i]; } HighSsaRegister returnDest = tInstr.ReturnDest; HighSsaRegister tempReturn = returnDest; bool needReturnConversion = false; if (signature.RetType is TypeSpecVoidTag) { if (returnDest != null) throw new RpaCompileException("Return type is not void"); } else if (returnDest != null) { needReturnConversion = !this.Compiler.TypeIsValueType(signature.RetType); if (needReturnConversion) tempReturn = new HighSsaRegister(HighValueType.ReferenceValue, signature.RetType, null); } MethodSpecTag generatedMethodSpec = new MethodSpecTag(MethodSlotType.Instance, methodSpec.GenericParameters, cls.TypeSpec, resolvedMethod.MethodDeclTag); generatedMethodSpec = this.Compiler.TagRepository.InternMethodSpec(generatedMethodSpec); MethodHandle methodHandle = this.Compiler.InstantiateMethod(new MethodSpecMethodKey(generatedMethodSpec), GenerateMethodInstantiationPath(tInstr.CodeLocation)); CheckMethodCall(generatedMethodSpec, tempReturn, tempParameters, resolvedMethod.MethodSignature); newInstrs.Add(new Instructions.CallRloInstanceMethodInstruction(tInstr.CodeLocation, methodHandle, tempReturn, refInstance, tempParameters)); if (needReturnConversion) EmitPassiveRefConversion(tInstr.CodeLocation, returnDest, tempReturn, newInstrs); } else { CliClass resolvedClass = cls; while (depth > 0) { resolvedClass = this.Compiler.GetClosedClass(resolvedClass.ParentClassSpec); depth--; } resolvedMethod = resolvedClass.Methods[methodIndex.Index]; // Method is on the parent of a value type, so it must be boxed HighSsaRegister boxed = new HighSsaRegister(HighValueType.BoxedValue, instanceType, null); newInstrs.Add(new Clarity.Rpa.Instructions.BoxInstruction(tInstr.CodeLocation, boxed, refInstance)); HighSsaRegister newInstanceSrc = new HighSsaRegister(HighValueType.ReferenceValue, resolvedClass.TypeSpec, null); newInstrs.Add(new Instructions.ObjectToObjectInstruction(tInstr.CodeLocation, newInstanceSrc, boxed)); MethodSpecTag generatedMethodSpec = new MethodSpecTag(MethodSlotType.Instance, methodSpec.GenericParameters, resolvedClass.TypeSpec, resolvedMethod.MethodDeclTag); generatedMethodSpec = this.Compiler.TagRepository.InternMethodSpec(generatedMethodSpec); MethodHandle methodHandle = this.Compiler.InstantiateMethod(new MethodSpecMethodKey(generatedMethodSpec), GenerateMethodInstantiationPath(tInstr.CodeLocation)); CheckMethodCall(generatedMethodSpec, dest, parameters, resolvedMethod.MethodSignature); newInstrs.Add(new Instructions.CallRloInstanceMethodInstruction(tInstr.CodeLocation, methodHandle, dest, newInstanceSrc, parameters)); } } else { HighSsaRegister loadedInstance = new HighSsaRegister(HighValueType.ReferenceValue, refInstance.Type, null); newInstrs.Add(new LoadPtrInstruction(tInstr.CodeLocation, loadedInstance, refInstance)); if (methodSpec.GenericParameters.Length == 0) { HighSsaRegister instance = new HighSsaRegister(HighValueType.ReferenceValue, constraintType, null); EmitPassiveRefConversion(tInstr.CodeLocation, instance, loadedInstance, newInstrs); if (isInterface) { CliInterface ifc = this.Compiler.GetClosedInterface((TypeSpecClassTag)constraintType); uint vtableSlotIndex = ifc.CliSlotForSlotTag(methodSpec.MethodDecl); MethodSignatureTag methodSignature = ifc.Slots[vtableSlotIndex].Signature; CheckMethodCall(methodSpec, dest, parameters, methodSignature); newInstrs.Add(new Instructions.CallRloInterfaceMethodInstruction(tInstr.CodeLocation, vtableSlotIndex, dest, instance, parameters)); } else { if (constraintType is TypeSpecClassTag || constraintType is TypeSpecArrayTag) { TypeSpecClassTag methodInstanceClass = methodSpec.DeclaringClass; if (this.Compiler.TypeIsValueType(methodInstanceClass)) throw new RpaCompileException("CallConstrainedVirtualMethod method spec is from a value type"); HighSsaRegister convertedInstance = new HighSsaRegister(HighValueType.ReferenceValue, methodInstanceClass, null); EmitPassiveRefConversion(tInstr.CodeLocation, convertedInstance, loadedInstance, newInstrs); if (this.Compiler.TypeIsInterface(methodInstanceClass)) { CliInterface ifcClass = this.Compiler.GetClosedInterface(methodInstanceClass); uint vtableSlotIndex; vtableSlotIndex = ifcClass.CliSlotForSlotTag(methodSpec.MethodDecl); MethodSignatureTag methodSignature = ifcClass.Slots[vtableSlotIndex].Signature; CheckMethodCall(methodSpec, dest, parameters, methodSignature); newInstrs.Add(new Instructions.CallRloInterfaceMethodInstruction(tInstr.CodeLocation, vtableSlotIndex, dest, convertedInstance, parameters)); } else { CliClass cliClass = this.Compiler.GetClosedClass(methodInstanceClass); uint vtableSlotIndex; if (!cliClass.DeclTagToVTableSlot.TryGetValue(methodSpec.MethodDecl, out vtableSlotIndex)) throw new RpaCompileException("CallConstrainedVirtualMethod method wasn't found"); MethodSignatureTag methodSignature = cliClass.VTable[vtableSlotIndex].MethodSignature; CheckMethodCall(methodSpec, dest, parameters, methodSignature); newInstrs.Add(new Instructions.CallRloVirtualMethodInstruction(tInstr.CodeLocation, vtableSlotIndex, dest, convertedInstance, parameters)); } } else throw new RpaCompileException("Unexpected constraint type"); } } else { // Constrained generic call on a reference value TypeSpecClassTag declaringClass = methodSpec.DeclaringClass; HighTypeDef typeDef = this.Compiler.GetTypeDef(declaringClass.TypeName); TypeSpecClassTag instanceClassTag = instanceType as TypeSpecClassTag; if (instanceClassTag == null) throw new RpaCompileException("Constrained generic call site a non-class"); HighTypeDef instanceTypeDef = this.Compiler.GetTypeDef(instanceClassTag.TypeName); if (instanceTypeDef.Semantics != TypeSemantics.Class) { MethodInstantiationPath path = GenerateMethodInstantiationPath(tInstr.CodeLocation); throw new RpaCompileException("Constrained generic call on a non-class: " + path.ToString()); } if (!instanceTypeDef.IsSealed) { MethodInstantiationPath path = GenerateMethodInstantiationPath(tInstr.CodeLocation); throw new RpaCompileException("Constrained generic call on a class that isn't sealed: " + path.ToString()); } CliClass instanceClass = this.Compiler.GetClosedClass(instanceClassTag); uint vtableSlotIndex; switch (typeDef.Semantics) { case TypeSemantics.Interface: { CliInterface ifc = this.Compiler.GetClosedInterface(declaringClass); uint ifcSlot = ifc.CliSlotForSlotTag(methodSpec.MethodDecl); vtableSlotIndex = this.Compiler.DevirtualizeInterfaceMethod(instanceClass, declaringClass, ifcSlot); } break; case TypeSemantics.Class: { CliClass cls = this.Compiler.GetClosedClass(declaringClass); if (!cls.DeclTagToVTableSlot.TryGetValue(methodSpec.MethodDecl, out vtableSlotIndex)) throw new RpaCompileException("CallConstrainedVirtualMethod vtable slot had no match"); } break; default: throw new RpaCompileException("Unexpected semantics on generic call on reference type"); } CliVtableSlot vtableSlot = instanceClass.VTable[vtableSlotIndex]; CliMethodIndex methodIndex = vtableSlot.MethodIndex; uint depth = methodIndex.Depth; CliClass instanceConversionTargetClass = instanceClass; while (depth > 0) { instanceConversionTargetClass = instanceConversionTargetClass.ParentClass; depth--; } HighMethod resolvedMethod = instanceConversionTargetClass.Methods[methodIndex.Index]; if (resolvedMethod.MethodSignature.NumGenericParameters != methodSpec.GenericParameters.Length) throw new RpaCompileException("Constrained generic call parameter type mismatch"); // Convert instance HighSsaRegister convertedInstance = new HighSsaRegister(HighValueType.ReferenceValue, instanceConversionTargetClass.TypeSpec, null); EmitPassiveRefConversion(tInstr.CodeLocation, convertedInstance, loadedInstance, newInstrs); // Convert parameters MethodSignatureTag methodSignature = resolvedMethod.MethodSignature.Instantiate(this.Compiler.TagRepository, new TypeSpecTag[0], methodSpec.GenericParameters); int numParameters = methodSignature.ParamTypes.Length; if (numParameters != parameters.Length) throw new RpaCompileException("Constrained generic call parameter count mismatch"); List<HighSsaRegister> convertedParameters = new List<HighSsaRegister>(); for (int i = 0; i < numParameters; i++) { MethodSignatureParam param = methodSignature.ParamTypes[i]; switch (param.TypeOfType.Value) { case MethodSignatureParamTypeOfType.Values.ByRef: convertedParameters.Add(parameters[i]); break; case MethodSignatureParamTypeOfType.Values.Value: { if (this.Compiler.TypeIsValueType(param.Type)) convertedParameters.Add(parameters[i]); else { HighSsaRegister convertedParameter = new HighSsaRegister(HighValueType.ReferenceValue, param.Type, null); EmitPassiveRefConversion(tInstr.CodeLocation, convertedParameter, parameters[i], newInstrs); convertedParameters.Add(convertedParameter); } } break; default: throw new NotImplementedException(); } } parameters = convertedParameters.ToArray(); HighSsaRegister unconvertedReturnDest = tInstr.ReturnDest; HighSsaRegister convertedReturnDest = null; if (unconvertedReturnDest != null) { if (this.Compiler.TypeIsValueType(methodSignature.RetType)) convertedReturnDest = unconvertedReturnDest; else { unconvertedReturnDest = new HighSsaRegister(HighValueType.ReferenceValue, methodSignature.RetType, null); convertedReturnDest = tInstr.ReturnDest; } } MethodSpecTag generatedMethodSpec = new MethodSpecTag(MethodSlotType.Instance, methodSpec.GenericParameters, instanceConversionTargetClass.TypeSpec, resolvedMethod.MethodDeclTag); generatedMethodSpec = this.Compiler.TagRepository.InternMethodSpec(generatedMethodSpec); MethodHandle methodHandle = this.Compiler.InstantiateMethod(new MethodSpecMethodKey(generatedMethodSpec), GenerateMethodInstantiationPath(tInstr.CodeLocation)); CheckMethodCall(generatedMethodSpec, unconvertedReturnDest, parameters, resolvedMethod.MethodSignature); newInstrs.Add(new Instructions.CallRloInstanceMethodInstruction(tInstr.CodeLocation, methodHandle, unconvertedReturnDest, convertedInstance, parameters)); if (unconvertedReturnDest != convertedReturnDest) EmitPassiveRefConversion(tInstr.CodeLocation, convertedReturnDest, unconvertedReturnDest, newInstrs); } } } break; case HighInstruction.Opcodes.CompareNumbers: { CompareNumbersInstruction tInstr = (CompareNumbersInstruction)instr; HighSsaRegister dest = tInstr.Dest; if (dest == null) throw new RpaCompileException("CompareNumbers has no destination"); if (dest.ValueType != HighValueType.ValueValue || dest.Type != m_boolType) throw new RpaCompileException("CompareNumbers has an invalid destination type"); TypeSpecClassTag expectedType = ExpectedClassForArithType(tInstr.NumberType); switch (tInstr.Left.ValueType) { case HighValueType.ConstantValue: case HighValueType.ValueValue: break; default: throw new RpaCompileException("CompareNumbers has an invalid operand"); } switch (tInstr.Right.ValueType) { case HighValueType.ConstantValue: case HighValueType.ValueValue: break; default: throw new RpaCompileException("CompareNumbers has an invalid operand"); } if (tInstr.Left.Type != expectedType || tInstr.Right.Type != expectedType) throw new RpaCompileException("CompareNumbers operands are the wrong type"); } break; case HighInstruction.Opcodes.GetArrayLength: { GetArrayLengthInstruction tInstr = (GetArrayLengthInstruction)instr; HighSsaRegister dest = tInstr.Dest; HighSsaRegister src = tInstr.Src; if (dest != null) { if (dest.ValueType != HighValueType.ValueValue || dest.Type != m_nativeUIntType) throw new RpaCompileException("GetArrayLength invalid destination type"); } switch (src.ValueType) { case HighValueType.Null: break; case HighValueType.ReferenceValue: { TypeSpecArrayTag srcType = src.Type as TypeSpecArrayTag; if (srcType == null) throw new RpaCompileException("GetArrayLength operand isn't an array"); if (srcType.Rank != 1) throw new RpaCompileException("GetArrayLength operand isn't 1-rank"); } break; default: throw new RpaCompileException("GetArrayLength operand isn't a reference"); } } break; case HighInstruction.Opcodes.ReturnValue: { ReturnValueInstruction tInstr = (ReturnValueInstruction)instr; HighSsaRegister value = tInstr.Value; TypeSpecTag retType = this.MethodBody.ReturnType; if (retType is TypeSpecVoidTag) throw new RpaCompileException("ReturnValue in a function that has no return type"); bool isValueType = this.Compiler.TypeIsValueType(retType); bool expectValueType; switch (tInstr.Value.ValueType) { case HighValueType.Null: case HighValueType.ConstantString: case HighValueType.ReferenceValue: expectValueType = false; break; case HighValueType.ConstantValue: case HighValueType.ValueValue: expectValueType = true; break; default: throw new RpaCompileException("ReturnValue invalid return value type"); } if (expectValueType != isValueType) throw new RpaCompileException("Incompatible return value type"); if (tInstr.Value.ValueType != HighValueType.Null && tInstr.Value.Type != retType) throw new RpaCompileException("Incompatible return value type"); } break; case HighInstruction.Opcodes.GetLocalPtr: { GetLocalPtrInstruction tInstr = (GetLocalPtrInstruction)instr; HighLocal local = tInstr.Local; if (local.TypeOfType != HighLocal.ETypeOfType.Value) throw new RpaCompileException("GetLocalPtr local isn't a value"); HighSsaRegister dest = tInstr.Dest; if (dest == null) throw new RpaCompileException("GetLocalPtr has no destination"); if (dest.ValueType != HighValueType.ManagedPtr) throw new RpaCompileException("GetLocalPtr destination isn't a managed pointer"); if (dest.Type != local.Type) throw new RpaCompileException("GetLocalPtr destination isn't the same type as the local"); } break; case HighInstruction.Opcodes.UnaryArith: { UnaryArithInstruction tInstr = (UnaryArithInstruction)instr; if (tInstr.Dest == null) throw new RpaCompileException("UnaryArith has no destination"); TypeSpecClassTag expectedClass = ExpectedClassForArithType(tInstr.ArithType); switch (tInstr.Src.ValueType) { case HighValueType.ConstantValue: case HighValueType.ValueValue: break; default: throw new RpaCompileException("UnaryArith source type is invalid"); } if (tInstr.Dest.ValueType != HighValueType.ValueValue) throw new RpaCompileException("UnaryArith destination type is invalid"); if (tInstr.Src.Type != expectedClass || tInstr.Dest.Type != expectedClass) throw new RpaCompileException("UnaryArith type doesn't match"); } break; case HighInstruction.Opcodes.StoreLocal: { StoreLocalInstruction tInstr = (StoreLocalInstruction)instr; HighLocal local = tInstr.Local; HighSsaRegister src = tInstr.Src; switch (local.TypeOfType) { case HighLocal.ETypeOfType.ByRef: if (src.ValueType != HighValueType.ManagedPtr) throw new RpaCompileException("StoreLocal type mismatch"); if (src.Type != local.Type) throw new RpaCompileException("StoreLocal type mismatch"); break; case HighLocal.ETypeOfType.Value: { bool isValueType = this.Compiler.TypeIsValueType(local.Type); if (isValueType) { switch (src.ValueType) { case HighValueType.ConstantValue: case HighValueType.ValueValue: if (src.Type != local.Type) throw new RpaCompileException("StoreLocal type mismatch"); break; default: throw new RpaCompileException("StoreLocal source type is invalid"); } } else { switch (src.ValueType) { case HighValueType.ConstantString: case HighValueType.ReferenceValue: if (src.Type != local.Type) throw new RpaCompileException("StoreLocal type mismatch"); break; case HighValueType.Null: break; default: throw new RpaCompileException("StoreLocal source type is invalid"); } } } break; case HighLocal.ETypeOfType.TypedByRef: throw new NotImplementedException(); default: throw new ArgumentException(); } } break; case HighInstruction.Opcodes.UnboxPtr: { UnboxPtrInstruction tInstr = (UnboxPtrInstruction)instr; if (tInstr.Dest == null) throw new RpaCompileException("UnboxPtr has no destination"); if (tInstr.Dest.ValueType != HighValueType.ManagedPtr) throw new RpaCompileException("UnboxPtr destination isn't a managed pointer"); if (!this.Compiler.TypeIsValueType(tInstr.Dest.Type)) throw new RpaCompileException("UnboxPtr type isn't a value type"); switch (tInstr.Src.ValueType) { case HighValueType.BoxedValue: case HighValueType.ConstantString: // Grumble grumble case HighValueType.Null: case HighValueType.ReferenceValue: break; default: throw new RpaCompileException("UnboxPtr source isn't a reference type"); } if (tInstr.Src.Type != m_objectType) throw new RpaCompileException("UnboxPtr source isn't System.Object"); } break; case HighInstruction.Opcodes.ZeroFillPtr: { ZeroFillPtrInstruction tInstr = (ZeroFillPtrInstruction)instr; if (tInstr.Target.ValueType != HighValueType.ManagedPtr) throw new RpaCompileException("ZeroFillPtr target isn't a managed pointer"); } break; case HighInstruction.Opcodes.UnboxValue: { UnboxValueInstruction tInstr = (UnboxValueInstruction)instr; if (tInstr.Dest == null) throw new RpaCompileException("UnboxValue has no destination"); switch (tInstr.Src.ValueType) { case HighValueType.BoxedValue: case HighValueType.ConstantString: // Grumble grumble case HighValueType.Null: case HighValueType.ReferenceValue: break; default: throw new RpaCompileException("UnboxValue source isn't a reference type"); } if (tInstr.Src.Type != m_objectType) throw new RpaCompileException("UnboxValue source isn't System.Object"); validationOnly = true; switch (tInstr.Dest.ValueType) { case HighValueType.ValueValue: { HighSsaRegister ptr = new HighSsaRegister(HighValueType.ManagedPtr, tInstr.Dest.Type, null); newInstrs.Add(new UnboxPtrInstruction(tInstr.CodeLocation, ptr, tInstr.Src)); newInstrs.Add(new LoadPtrInstruction(tInstr.CodeLocation, tInstr.Dest, ptr)); } break; case HighValueType.ReferenceValue: newInstrs.Add(new ForceDynamicCastInstruction(tInstr.CodeLocation, tInstr.Dest, tInstr.Src, tInstr.Dest.Type)); break; default: throw new RpaCompileException("UnboxValue destination is invalid"); } } break; case HighInstruction.Opcodes.Switch: { SwitchInstruction tInstr = (SwitchInstruction)instr; switch (tInstr.Value.ValueType) { case HighValueType.ConstantValue: case HighValueType.ValueValue: break; default: throw new RpaCompileException("Switch source is invalid"); } if (tInstr.Value.Type != m_uint32Type) throw new RpaCompileException("Switch source isn't a UInt32"); } break; case HighInstruction.Opcodes.Throw: { ThrowInstruction tInstr = (ThrowInstruction)instr; switch (tInstr.Exception.ValueType) { case HighValueType.BoxedValue: case HighValueType.ConstantString: case HighValueType.Null: case HighValueType.ReferenceValue: break; default: throw new RpaCompileException("Throw instruction doesn't throw an object"); } } break; case HighInstruction.Opcodes.StorePtr: { StorePtrInstruction tInstr = (StorePtrInstruction)instr; if (tInstr.Ptr.ValueType != HighValueType.ManagedPtr) throw new RpaCompileException("StorePtr destination isn't a managed pointer"); bool isValueType = this.Compiler.TypeIsValueType(tInstr.Ptr.Type); switch (tInstr.Value.ValueType) { case HighValueType.ConstantString: case HighValueType.ConstantValue: case HighValueType.ReferenceValue: case HighValueType.ValueValue: if (tInstr.Value.Type != tInstr.Ptr.Type) throw new RpaCompileException("StorePtr type mismatch"); break; case HighValueType.Null: if (isValueType) throw new RpaCompileException("StorePtr type mismatch"); break; default: throw new RpaCompileException("StorePtr source is invalid"); } } break; case HighInstruction.Opcodes.GetFieldInfo: { GetFieldInfoInstruction tInstr = (GetFieldInfoInstruction)instr; TypeSpecClassTag typeClassSpec = tInstr.Type as TypeSpecClassTag; if (typeClassSpec == null) throw new RpaCompileException("GetFieldInfo type isn't a class"); if (!this.Compiler.HaveCliOpenClass(typeClassSpec.TypeName)) throw new RpaCompileException("GetFieldInfo type name isn't a class"); CliClass cls = this.Compiler.GetClosedClass(typeClassSpec); if (tInstr.Dest == null) throw new RpaCompileException("GetFieldInfo has no destination"); if (tInstr.Dest.ValueType != HighValueType.ValueValue && tInstr.Type != m_runtimeFieldHandleType) throw new RpaCompileException("GetFieldInfo destination is invalid"); IDictionary<string, uint> fieldDict = tInstr.IsStatic ? cls.NameToStaticFieldSlot : cls.NameToInstanceFieldSlot; uint fieldIndex; if (!fieldDict.TryGetValue(tInstr.FieldName, out fieldIndex)) throw new RpaCompileException("GetFieldInfo field not found"); validationOnly = false; newInstrs.Add(new Instructions.GetRloFieldInfoInstruction(tInstr.CodeLocation, tInstr.Dest, tInstr.Type, fieldIndex, tInstr.IsStatic)); } break; case HighInstruction.Opcodes.LoadValueField: { LoadValueFieldInstruction tInstr = (LoadValueFieldInstruction)instr; validationOnly = false; if (tInstr.Src.ValueType != HighValueType.ValueValue) throw new RpaCompileException("LoadValueField source is invalid"); TypeSpecClassTag typeClassSpec = tInstr.Src.Type as TypeSpecClassTag; if (typeClassSpec == null) throw new RpaCompileException("LoadValueField type isn't a class"); if (!this.Compiler.HaveCliOpenClass(typeClassSpec.TypeName)) throw new RpaCompileException("LoadValueField type name isn't a class"); CliClass cls = this.Compiler.GetClosedClass(typeClassSpec); uint fieldIndex; if (!cls.NameToInstanceFieldSlot.TryGetValue(tInstr.FieldName, out fieldIndex)) throw new RpaCompileException("LoadValueField field not found"); HighField fld = cls.InstanceFields[fieldIndex]; switch (tInstr.Dest.ValueType) { case HighValueType.ValueValue: case HighValueType.ReferenceValue: break; default: throw new RpaCompileException("LoadValueField destination isn't a value"); } if (tInstr.Dest.Type != fld.Type) throw new RpaCompileException("LoadValueField destination type mismatch"); validationOnly = false; newInstrs.Add(new Instructions.LoadValueRloFieldInstruction(tInstr.CodeLocation, tInstr.Dest, tInstr.Src, fieldIndex)); } break; case HighInstruction.Opcodes.BindStaticDelegate: { BindStaticDelegateInstruction tInstr = (BindStaticDelegateInstruction)instr; if (tInstr.Dest == null) throw new RpaCompileException("BindStaticDelegate has no destination"); if (tInstr.Dest.ValueType != HighValueType.ReferenceValue) throw new RpaCompileException("BindStaticDelegate target isn't a reference"); TypeSpecClassTag destClass = tInstr.Dest.Type as TypeSpecClassTag; if (destClass == null) throw new RpaCompileException("BindStaticDelegate destination isn't a class"); HighTypeDef typeDef = this.Compiler.GetTypeDef(destClass.TypeName); if (typeDef.Semantics != TypeSemantics.Delegate) throw new RpaCompileException("BindStaticDelegate destination isn't a delegate"); if (tInstr.MethodSpec.MethodSlotType != MethodSlotType.Static) throw new RpaCompileException("BindStaticDelegate method spec isn't static"); TypeSpecDelegateTag dgTag = new TypeSpecDelegateTag(destClass, tInstr.MethodSpec); dgTag = (TypeSpecDelegateTag)this.Compiler.TagRepository.InternTypeSpec(dgTag); validationOnly = true; HighSsaRegister sdInstance = new HighSsaRegister(HighValueType.ReferenceValue, dgTag, null); newInstrs.Add(new AllocObjInstruction(tInstr.CodeLocation, sdInstance, dgTag)); newInstrs.Add(new Instructions.ObjectToObjectInstruction(tInstr.CodeLocation, tInstr.Dest, sdInstance)); this.Compiler.GetRloVTable(dgTag, GenerateMethodInstantiationPath(tInstr.CodeLocation)); } break; case HighInstruction.Opcodes.BindInstanceDelegate: { BindInstanceDelegateInstruction tInstr = (BindInstanceDelegateInstruction)instr; if (tInstr.Dest == null) throw new RpaCompileException("BindInstanceDelegate has no destination"); if (tInstr.Dest.ValueType != HighValueType.ReferenceValue) throw new RpaCompileException("BindInstanceDelegate target isn't a reference"); TypeSpecClassTag destClass = tInstr.Dest.Type as TypeSpecClassTag; if (destClass == null) throw new RpaCompileException("BindInstanceDelegate destination isn't a class"); HighTypeDef typeDef = this.Compiler.GetTypeDef(destClass.TypeName); if (typeDef.Semantics != TypeSemantics.Delegate) throw new RpaCompileException("BindInstanceDelegate destination isn't a delegate"); if (tInstr.MethodSpec.MethodSlotType != MethodSlotType.Instance) throw new RpaCompileException("BindInstanceDelegate method spec isn't an instance method"); switch (tInstr.Object.ValueType) { case HighValueType.BoxedValue: case HighValueType.ConstantString: case HighValueType.Null: case HighValueType.ReferenceValue: break; default: throw new RpaCompileException("BindInstanceDelegate object is invalid"); } if (tInstr.MethodSpec.DeclaringClass != tInstr.Object.Type) throw new RpaCompileException("BindInstanceDelegate method spec type doesn't match source"); if (tInstr.MethodSpec.MethodSlotType != MethodSlotType.Instance) throw new RpaCompileException("BindInstanceDelegate method spec isn't an instance method"); TypeSpecDelegateTag dgTag = new TypeSpecDelegateTag(destClass, tInstr.MethodSpec); dgTag = (TypeSpecDelegateTag)this.Compiler.TagRepository.InternTypeSpec(dgTag); validationOnly = true; HighSsaRegister dgInstance = new HighSsaRegister(HighValueType.ReferenceValue, dgTag, null); newInstrs.Add(new Instructions.AllocInstanceDelegateInstruction(tInstr.CodeLocation, dgTag, dgInstance, tInstr.Object)); newInstrs.Add(new Instructions.ObjectToObjectInstruction(tInstr.CodeLocation, tInstr.Dest, dgInstance)); this.Compiler.GetRloVTable(dgTag, GenerateMethodInstantiationPath(tInstr.CodeLocation)); } break; case HighInstruction.Opcodes.BindVirtualDelegate: { BindVirtualDelegateInstruction tInstr = (BindVirtualDelegateInstruction)instr; if (tInstr.Dest == null) throw new RpaCompileException("BindVirtualDelegate has no destination"); if (tInstr.Dest.ValueType != HighValueType.ReferenceValue) throw new RpaCompileException("BindVirtualDelegate target isn't a reference"); TypeSpecClassTag destClass = tInstr.Dest.Type as TypeSpecClassTag; if (destClass == null) throw new RpaCompileException("BindVirtualDelegate destination isn't a class"); HighTypeDef typeDef = this.Compiler.GetTypeDef(destClass.TypeName); if (typeDef.Semantics != TypeSemantics.Delegate) throw new RpaCompileException("BindVirtualDelegate destination isn't a delegate"); if (tInstr.MethodSpec.MethodSlotType != MethodSlotType.Virtual) throw new RpaCompileException("BindVirtualDelegate method spec isn't an instance method"); switch (tInstr.Object.ValueType) { case HighValueType.BoxedValue: case HighValueType.ConstantString: case HighValueType.Null: case HighValueType.ReferenceValue: break; default: throw new RpaCompileException("BindInstanceDelegate object is invalid"); } if (tInstr.MethodSpec.DeclaringClass != tInstr.Object.Type) throw new RpaCompileException("BindInstanceDelegate method spec type doesn't match source"); if (tInstr.MethodSpec.MethodSlotType != MethodSlotType.Virtual) throw new RpaCompileException("BindInstanceDelegate method spec isn't a virtual method"); TypeSpecDelegateTag dgTag = new TypeSpecDelegateTag(destClass, tInstr.MethodSpec); dgTag = (TypeSpecDelegateTag)this.Compiler.TagRepository.InternTypeSpec(dgTag); validationOnly = true; HighSsaRegister dgInstance = new HighSsaRegister(HighValueType.ReferenceValue, dgTag, null); newInstrs.Add(new Instructions.AllocInstanceDelegateInstruction(tInstr.CodeLocation, dgTag, dgInstance, tInstr.Object)); newInstrs.Add(new Instructions.ObjectToObjectInstruction(tInstr.CodeLocation, tInstr.Dest, dgInstance)); this.Compiler.GetRloVTable(dgTag, GenerateMethodInstantiationPath(tInstr.CodeLocation)); } break; case HighInstruction.Opcodes.Catch: { CatchInstruction tInstr = (CatchInstruction)instr; if (tInstr.Dest == null) throw new RpaCompileException("Catch instruction has no destination"); if (tInstr.Dest.ValueType != HighValueType.ReferenceValue) throw new RpaCompileException("Catch instruction destination is invalid"); } break; case HighInstruction.Opcodes.NumberConvert: { validationOnly = false; NumberConvertInstruction tInstr = (NumberConvertInstruction)instr; if (tInstr.Dest == null) throw new RpaCompileException("NumberConvert instruction destination is invalid"); if (tInstr.Dest.ValueType != HighValueType.ValueValue) break; switch (tInstr.Src.ValueType) { case HighValueType.ConstantValue: case HighValueType.ValueValue: break; default: throw new RpaCompileException("NumberConvert source is invalid"); } EmitNumberConversion(tInstr.CodeLocation, tInstr.Dest, tInstr.Src, tInstr.CheckOverflow, newInstrs); } break; case HighInstruction.Opcodes.PassiveConvert: { PassiveConvertInstruction tInstr = (PassiveConvertInstruction)instr; validationOnly = false; if (tInstr.Dest == null) throw new RpaCompileException("PassiveConvert has no destination"); bool srcIsValue; switch (tInstr.Src.ValueType) { case HighValueType.ConstantValue: case HighValueType.ValueValue: srcIsValue = true; break; case HighValueType.BoxedValue: case HighValueType.ConstantString: case HighValueType.Null: case HighValueType.ReferenceValue: srcIsValue = false; break; default: throw new RpaCompileException("PassiveConvert invalid source type"); } bool destIsValue; switch (tInstr.Dest.ValueType) { case HighValueType.BoxedValue: case HighValueType.ReferenceValue: destIsValue = false; break; case HighValueType.ValueValue: destIsValue = true; break; default: throw new RpaCompileException("PassiveConvert invalid dest type"); } if (destIsValue != srcIsValue) throw new RpaCompileException("PassiveConvert ref/value mismatch"); if (srcIsValue) EmitPassiveValueConversion(tInstr.CodeLocation, tInstr.Dest, tInstr.Src, newInstrs); else EmitPassiveRefConversion(tInstr.CodeLocation, tInstr.Dest, tInstr.Src, newInstrs); } break; case HighInstruction.Opcodes.CallConstrainedMethod: { validationOnly = false; CallConstrainedMethodInstruction tInstr = (CallConstrainedMethodInstruction)instr; HighSsaRegister refInstance = tInstr.InstanceSrc; HighSsaRegister[] parameters = tInstr.Parameters; HighSsaRegister dest = tInstr.ReturnDest; MethodSpecTag methodSpec = tInstr.MethodSpec; if (methodSpec.MethodSlotType != MethodSlotType.Instance) throw new RpaCompileException("CallConstrainedMethodInstruction target is not an instance method"); TypeSpecTag constraintType = tInstr.ConstraintType; if (refInstance.ValueType != HighValueType.ManagedPtr) throw new RpaCompileException("CallConstrainedMethodInstruction target is not a managed pointer"); if (refInstance.Type != constraintType) throw new RpaCompileException("CallConstrainedMethodInstruction target type is different from constraint type"); TypeSpecTag instanceType = refInstance.Type; bool isValueType; bool isInterface; switch (instanceType.SubType) { case TypeSpecTag.SubTypeCode.Array: isValueType = false; isInterface = false; break; case TypeSpecTag.SubTypeCode.Class: { TypeSpecClassTag instanceClassTag = (TypeSpecClassTag)instanceType; HighTypeDef instanceTypeDef = this.Compiler.GetTypeDef(instanceClassTag.TypeName); switch (instanceTypeDef.Semantics) { case TypeSemantics.Class: case TypeSemantics.Delegate: isValueType = false; isInterface = false; break; case TypeSemantics.Interface: isValueType = false; isInterface = true; break; case TypeSemantics.Enum: case TypeSemantics.Struct: isValueType = true; isInterface = false; break; default: throw new NotSupportedException(); } } break; default: throw new RpaCompileException("Invalid instance type in CallConstrainedVirtualMethod"); }; if (isValueType) { TypeSpecClassTag instanceClassTag = (TypeSpecClassTag)refInstance.Type; CliClass cls = this.Compiler.GetClosedClass(instanceClassTag); TypeSpecClassTag methodDeclaringClass = methodSpec.DeclaringClass; HighTypeDef methodTypeDef = this.Compiler.GetTypeDef(methodDeclaringClass.TypeName); HighMethod resolvedMethod; uint methodIndex = 0; if (methodTypeDef.Semantics != TypeSemantics.Class) throw new RpaCompileException("CallConstrainedMethod declaring type isn't a class"); CliClass resolvedClass = cls; while (resolvedClass != null) { if (resolvedClass.DeclTagToMethod.TryGetValue(methodSpec.MethodDecl, out methodIndex)) break; resolvedClass = resolvedClass.ParentClass; } if (resolvedClass == null) throw new RpaCompileException("CallConstrainedMethod virtual method was not found"); resolvedMethod = resolvedClass.Methods[methodIndex]; HighSsaRegister boxed = new HighSsaRegister(HighValueType.BoxedValue, instanceType, null); newInstrs.Add(new BoxInstruction(tInstr.CodeLocation, boxed, refInstance)); HighSsaRegister newInstanceSrc = new HighSsaRegister(HighValueType.ReferenceValue, resolvedClass.TypeSpec, null); newInstrs.Add(new Instructions.ObjectToObjectInstruction(tInstr.CodeLocation, newInstanceSrc, boxed)); MethodSpecTag generatedMethodSpec = new MethodSpecTag(MethodSlotType.Instance, methodSpec.GenericParameters, resolvedClass.TypeSpec, resolvedMethod.MethodDeclTag); generatedMethodSpec = this.Compiler.TagRepository.InternMethodSpec(generatedMethodSpec); MethodHandle methodHandle = this.Compiler.InstantiateMethod(new MethodSpecMethodKey(generatedMethodSpec), GenerateMethodInstantiationPath(tInstr.CodeLocation)); CheckMethodCall(generatedMethodSpec, dest, parameters, resolvedMethod.MethodSignature); newInstrs.Add(new Instructions.CallRloInstanceMethodInstruction(tInstr.CodeLocation, methodHandle, dest, newInstanceSrc, parameters)); } else { HighSsaRegister loadedInstance = new HighSsaRegister(HighValueType.ReferenceValue, refInstance.Type, null); newInstrs.Add(new LoadPtrInstruction(tInstr.CodeLocation, loadedInstance, refInstance)); if (methodSpec.GenericParameters.Length != 0) throw new RpaCompileException("Generic method spec on a non-virtual method (???)"); HighSsaRegister instance = new HighSsaRegister(HighValueType.ReferenceValue, constraintType, null); EmitPassiveRefConversion(tInstr.CodeLocation, instance, loadedInstance, newInstrs); if (isInterface) { HighSsaRegister objReg = new HighSsaRegister(HighValueType.ReferenceValue, m_objectType, null); newInstrs.Add(new Instructions.InterfaceToObjectInstruction(tInstr.CodeLocation, objReg, loadedInstance)); if (methodSpec.DeclaringClass != m_objectType) throw new RpaCompileException("Constrained method on an interface isn't System.Object"); uint methodIndex; CliClass objClass = this.Compiler.GetClosedClass(m_objectType); if (!objClass.DeclTagToMethod.TryGetValue(methodSpec.MethodDecl, out methodIndex)) throw new RpaCompileException("Constrained method on System.Object not found"); HighMethod resolvedMethod = objClass.Methods[methodIndex]; MethodSignatureTag methodSignature = resolvedMethod.MethodSignature; CheckMethodCall(methodSpec, dest, parameters, methodSignature); MethodHandle methodHandle = this.Compiler.InstantiateMethod(new MethodSpecMethodKey(methodSpec), GenerateMethodInstantiationPath(tInstr.CodeLocation)); newInstrs.Add(new Instructions.CallRloInstanceMethodInstruction(tInstr.CodeLocation, methodHandle, dest, instance, parameters)); } else { if (constraintType is TypeSpecClassTag || constraintType is TypeSpecArrayTag) { TypeSpecClassTag methodInstanceClass = methodSpec.DeclaringClass; if (this.Compiler.TypeIsValueType(methodInstanceClass)) throw new RpaCompileException("CallConstrainedMethod method spec is from a value type"); HighSsaRegister convertedInstance = new HighSsaRegister(HighValueType.ReferenceValue, methodInstanceClass, null); EmitPassiveRefConversion(tInstr.CodeLocation, convertedInstance, loadedInstance, newInstrs); if (this.Compiler.TypeIsInterface(methodInstanceClass)) throw new RpaCompileException("CallConstrainedMethod target class was an interface"); else { CliClass cliClass = this.Compiler.GetClosedClass(methodInstanceClass); uint methodIndex; if (!cliClass.DeclTagToMethod.TryGetValue(methodSpec.MethodDecl, out methodIndex)) throw new RpaCompileException("CallConstrainedMethod method wasn't found"); HighMethod resolvedMethod = cliClass.Methods[methodIndex]; MethodSignatureTag methodSignature = resolvedMethod.MethodSignature; MethodHandle methodHandle = this.Compiler.InstantiateMethod(new MethodSpecMethodKey(methodSpec), GenerateMethodInstantiationPath(tInstr.CodeLocation)); CheckMethodCall(methodSpec, dest, parameters, methodSignature); newInstrs.Add(new Instructions.CallRloInstanceMethodInstruction(tInstr.CodeLocation, methodHandle, dest, convertedInstance, parameters)); } } else throw new RpaCompileException("Unexpected constraint type"); } } } break; case HighInstruction.Opcodes.Return: case HighInstruction.Opcodes.Branch: case HighInstruction.Opcodes.EnterProtectedBlock: case HighInstruction.Opcodes.LeaveRegion: break; //throw new NotImplementedException(); default: throw new ArgumentException(); } if (validationOnly) newInstrs.Add(instr); }
private List<MethodHandle> GenerateVTableForClass(Compiler compiler, TypeSpecClassTag typeSpec) { List<MethodSpecTag> methodSpecs = GenerateMethodSpecsForClass(compiler, typeSpec); List<MethodHandle> methodHandles = new List<MethodHandle>(); foreach (MethodSpecTag methodSpec in methodSpecs) { if (methodSpec == null) methodHandles.Add(null); else methodHandles.Add(compiler.InstantiateMethod(new MethodSpecMethodKey(methodSpec), m_instantiationPath)); } return methodHandles; }
public bool Create(Compiler compiler) { HighTypeDef typeDef = compiler.GetTypeDef(m_typeName); TypeSpecClassTag parentClassSpec = null; HighClassVtableSlot[] newSlots; HighClassVtableSlot[] replacedSlots; HighInterfaceImplementation[] typeInterfaceImpls; if (typeDef.Semantics == TypeSemantics.Struct || typeDef.Semantics == TypeSemantics.Class) { if (typeDef.Semantics == TypeSemantics.Struct) { m_isStruct = true; TypeNameTag valueTypeName = new TypeNameTag("mscorlib", "System", "ValueType", 0, null); valueTypeName = compiler.TagRepository.InternTypeName(valueTypeName); TypeSpecClassTag vtClassTag = new TypeSpecClassTag(valueTypeName, new TypeSpecTag[0]); vtClassTag = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(vtClassTag); parentClassSpec = vtClassTag; } else if (typeDef.Semantics == TypeSemantics.Class) { m_isStruct = false; parentClassSpec = typeDef.ParentClass; RestrictedExtensionType thisRet = GetRestrictedExtensionType(m_typeName); if (parentClassSpec == null) { if (thisRet != RestrictedExtensionType.Object) throw new Exception("Parentless class is not [mscorlib]System.Object"); } else { if (thisRet == RestrictedExtensionType.Object) throw new Exception("[mscorlib]System.Object has a parent"); RestrictedExtensionType parentRet = GetRestrictedExtensionType(parentClassSpec.TypeName); bool isExtensionOK = false; switch (parentRet) { case RestrictedExtensionType.ValueType: if (thisRet == RestrictedExtensionType.Enum) isExtensionOK = true; break; case RestrictedExtensionType.Delegate: if (thisRet == RestrictedExtensionType.MulticastDelegate) isExtensionOK = true; break; case RestrictedExtensionType.Enum: case RestrictedExtensionType.MulticastDelegate: case RestrictedExtensionType.NullableSZArray: case RestrictedExtensionType.RefSZArray: case RestrictedExtensionType.ValueSZArray: break; case RestrictedExtensionType.Object: case RestrictedExtensionType.None: isExtensionOK = true; break; case RestrictedExtensionType.Array: if (thisRet == RestrictedExtensionType.NullableSZArray || thisRet == RestrictedExtensionType.ValueSZArray || thisRet == RestrictedExtensionType.RefSZArray) isExtensionOK = true; break; default: throw new ArgumentException(); } if (!isExtensionOK) throw new Exception("Invalid extension of a restricted class"); } } m_instanceFields = typeDef.InstanceFields; m_methods = typeDef.Methods; m_staticFields = typeDef.StaticFields; m_isSealed = typeDef.IsSealed; m_isAbstract = typeDef.IsAbstract; replacedSlots = typeDef.ReplacedSlots; newSlots = typeDef.NewSlots; typeInterfaceImpls = typeDef.InterfaceImpls; } else if (typeDef.Semantics == TypeSemantics.Delegate) { m_isStruct = false; TypeNameTag dgTypeName = new TypeNameTag("mscorlib", "System", typeDef.IsMulticastDelegate ? "MulticastDelegate" : "Delegate", 0, null); dgTypeName = compiler.TagRepository.InternTypeName(dgTypeName); TypeSpecClassTag dgClassTag = new TypeSpecClassTag(dgTypeName, new TypeSpecTag[0]); dgClassTag = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(dgClassTag); parentClassSpec = dgClassTag; m_instanceFields = new HighField[0]; m_methods = new HighMethod[0]; m_staticFields = new HighField[0]; m_isSealed = false; m_isAbstract = true; replacedSlots = new HighClassVtableSlot[0]; MethodDeclTag invokeTag = new MethodDeclTag("Invoke", typeDef.DelegateSignature, m_typeName); invokeTag = compiler.TagRepository.InternMethodDeclTag(invokeTag); HighClassVtableSlot invokeSlot = new HighClassVtableSlot(invokeTag, typeDef.DelegateSignature, null, true, false); newSlots = new HighClassVtableSlot[1] { invokeSlot }; typeInterfaceImpls = new HighInterfaceImplementation[0]; } else if (typeDef.Semantics == TypeSemantics.Enum) { m_isStruct = false; TypeNameTag dgTypeName = new TypeNameTag("mscorlib", "System", "Enum", 0, null); dgTypeName = compiler.TagRepository.InternTypeName(dgTypeName); TypeSpecClassTag dgClassTag = new TypeSpecClassTag(dgTypeName, new TypeSpecTag[0]); dgClassTag = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(dgClassTag); parentClassSpec = dgClassTag; string underlyingTypeName; switch (typeDef.UnderlyingType) { case HighTypeDef.EnumUnderlyingType.Int8: underlyingTypeName = "SByte"; break; case HighTypeDef.EnumUnderlyingType.Int16: underlyingTypeName = "Int16"; break; case HighTypeDef.EnumUnderlyingType.Int32: underlyingTypeName = "Int32"; break; case HighTypeDef.EnumUnderlyingType.Int64: underlyingTypeName = "Int64"; break; case HighTypeDef.EnumUnderlyingType.UInt8: underlyingTypeName = "Byte"; break; case HighTypeDef.EnumUnderlyingType.UInt16: underlyingTypeName = "Int16"; break; case HighTypeDef.EnumUnderlyingType.UInt32: underlyingTypeName = "UInt32"; break; case HighTypeDef.EnumUnderlyingType.UInt64: underlyingTypeName = "UInt64"; break; default: throw new Exception(); } TypeNameTag underlyingTypeNameTag = new TypeNameTag("mscorlib", "System", underlyingTypeName); underlyingTypeNameTag = compiler.TagRepository.InternTypeName(underlyingTypeNameTag); TypeSpecClassTag underlyingTypeSpec = new TypeSpecClassTag(underlyingTypeNameTag, new TypeSpecTag[0]); underlyingTypeSpec = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(underlyingTypeSpec); HighField fld = new HighField("value__", underlyingTypeSpec); m_instanceFields = new HighField[1] { fld }; m_methods = new HighMethod[0]; m_staticFields = new HighField[0]; m_isSealed = true; m_isAbstract = false; replacedSlots = new HighClassVtableSlot[0]; newSlots = new HighClassVtableSlot[0]; typeInterfaceImpls = new HighInterfaceImplementation[0]; } else throw new ArgumentException(); if (parentClassSpec != null) { if (compiler.GetTypeDef(parentClassSpec.TypeName).Semantics != TypeSemantics.Class) throw new RpaCompileException("Can't extend class with non-class semantics"); if (!compiler.HaveCliOpenClass(parentClassSpec.TypeName)) return false; CliClass parentClass = compiler.GetClosedClass(parentClassSpec); if (parentClass.m_isSealed) throw new RpaCompileException("Can't extend sealed CLI class"); m_parentClass = parentClass; } m_numGenericParameters = typeDef.NumGenericParameters; // Update vtable { Dictionary<MethodDeclTag, uint> declTagToMethod = new Dictionary<MethodDeclTag, uint>(); uint methodIndex = 0; foreach (HighMethod method in m_methods) { if (declTagToMethod.ContainsKey(method.MethodDeclTag)) throw new Exception("Duplicate method declaration"); declTagToMethod.Add(method.MethodDeclTag, methodIndex++); } m_declTagToMethod = declTagToMethod; } m_declTagToVTableSlot = new Dictionary<MethodDeclTag, uint>(); m_ifcToIfcSlot = new Dictionary<TypeSpecClassTag, uint>(); List<CliVtableSlot> slots = new List<CliVtableSlot>(); if (m_parentClass != null) { foreach (KeyValuePair<MethodDeclTag, uint> dttvs in m_parentClass.m_declTagToVTableSlot) m_declTagToVTableSlot.Add(dttvs.Key, dttvs.Value); foreach (CliVtableSlot parentSlot in m_parentClass.m_vtable) { CliMethodIndex methodIndex = parentSlot.MethodIndex; if (methodIndex == null) slots.Add(parentSlot); else { CliMethodIndex newIndex = new CliMethodIndex(methodIndex.Depth + 1, methodIndex.Index); slots.Add(new CliVtableSlot(newIndex, parentSlot.MethodSignature, parentSlot.IsSealed)); } } } foreach (HighClassVtableSlot slot in replacedSlots) { uint index; if (!m_declTagToVTableSlot.TryGetValue(slot.SlotTag, out index)) throw new Exception("Unmatched vtable slot replacement"); CliVtableSlot existingSlot = slots[(int)index]; if (existingSlot.IsSealed) throw new Exception("Can't replace sealed vtable slot"); if (existingSlot.MethodSignature != slot.Signature) throw new Exception("VTable slot override signature doesn't match"); CliMethodIndex methodIndex = null; if (!slot.IsAbstract) { HighMethod method; methodIndex = this.FindMethod(slot.ImplementingMethodTag, out method); if (method.MethodSignature != slot.Signature) throw new Exception("Signature of method used by vtable slot doesn't match vtable slot's signature"); } slots[(int)index] = new CliVtableSlot(methodIndex, slot.Signature, slot.IsFinal); } foreach (HighClassVtableSlot slot in newSlots) { CliMethodIndex methodIndex = null; if (!slot.IsAbstract) { HighMethod method; methodIndex = this.FindMethod(slot.ImplementingMethodTag, out method); if (method.MethodSignature != slot.Signature) throw new Exception("Signature of method used by vtable slot doesn't match vtable slot's signature"); } m_declTagToVTableSlot.Add(slot.SlotTag, (uint)slots.Count); slots.Add(new CliVtableSlot(methodIndex, slot.Signature, slot.IsFinal)); } m_vtable = slots.ToArray(); if (!m_isAbstract) foreach (CliVtableSlot slot in m_vtable) if (slot.MethodIndex == null) throw new RpaCompileException("Non-abstract class has unoverrided abstract methods"); m_nameToInstanceFieldSlot = new Dictionary<string, uint>(); for (uint i = 0; i < m_instanceFields.Length; i++) { string fldName = m_instanceFields[i].Name; if (m_nameToInstanceFieldSlot.ContainsKey(fldName)) throw new RpaCompileException("Duplicate field name"); m_nameToInstanceFieldSlot.Add(fldName, i); } m_nameToStaticFieldSlot = new Dictionary<string, uint>(); for (uint i = 0; i < m_staticFields.Length; i++) { string fldName = m_staticFields[i].Name; if (m_nameToStaticFieldSlot.ContainsKey(fldName)) throw new RpaCompileException("Duplicate field name"); m_nameToStaticFieldSlot.Add(fldName, i); } HashSet<TypeSpecClassTag> explicitImpls = new HashSet<TypeSpecClassTag>(); List<CliInterfaceImpl> interfaceImpls = new List<CliInterfaceImpl>(); foreach (HighInterfaceImplementation ifcImpl in typeInterfaceImpls) { if (!explicitImpls.Add(ifcImpl.Interface)) throw new Exception("Duplicate interface implementation"); interfaceImpls.Add(ResolveInterfaceImpl(compiler, ifcImpl)); } m_interfaceImpls = interfaceImpls.ToArray(); m_parentClassSpec = parentClassSpec; m_explicitInterfaceSpecs = typeDef.ParentInterfaces; if (m_explicitInterfaceSpecs == null) m_explicitInterfaceSpecs = new TypeSpecClassTag[0]; List<TypeSpecTag> thisGenericParameters = new List<TypeSpecTag>(); for (uint i = 0; i < m_numGenericParameters; i++) { TypeSpecGenericParamTypeTag gptt = new TypeSpecGenericParamTypeTag(TypeSpecGenericParamTypeTag.Values.Var); TypeSpecGenericParamTag gpTag = new TypeSpecGenericParamTag(gptt, i); gpTag = (TypeSpecGenericParamTag)compiler.TagRepository.InternTypeSpec(gpTag); thisGenericParameters.Add(gpTag); } TypeSpecClassTag thisClass = new TypeSpecClassTag(m_typeName, thisGenericParameters.ToArray()); thisClass = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(thisClass); m_typeSpec = thisClass; m_typeDeclarationOrder = new Dictionary<TypeSpecClassTag, uint>(); ResolveTDOForClass(this); m_isCreated = true; return true; }
private List<MethodHandle> GenerateVTableForArray(Compiler compiler, TypeSpecArrayTag typeSpec) { TypeSpecClassTag baseClass; if (typeSpec.IsSZArray) { TypeSpecTag subscriptType = typeSpec.SubscriptType; if (compiler.TypeIsValueType(typeSpec.SubscriptType)) { TypeSpecClassTag subscriptClassTag = (TypeSpecClassTag)subscriptType; TypeNameTag subscriptClassName = subscriptClassTag.TypeName; if (subscriptClassName.FastIs("mscorlib", "System", "Nullable`1", 1, null)) { TypeNameTag baseName = new TypeNameTag("mscorlib", "Clarity", "NullableSZArray`1", 1, null); baseName = compiler.TagRepository.InternTypeName(baseName); baseClass = new TypeSpecClassTag(baseName, subscriptClassTag.ArgTypes); baseClass = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(baseClass); } else { TypeNameTag baseName = new TypeNameTag("mscorlib", "Clarity", "ValueSZArray`1", 1, null); baseName = compiler.TagRepository.InternTypeName(baseName); baseClass = new TypeSpecClassTag(baseName, new TypeSpecTag[] { subscriptClassTag }); baseClass = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(baseClass); } } else { TypeNameTag baseName = new TypeNameTag("mscorlib", "Clarity", "RefSZArray"); baseName = compiler.TagRepository.InternTypeName(baseName); baseClass = new TypeSpecClassTag(baseName, new TypeSpecTag[0]); baseClass = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(baseClass); } } else throw new NotImplementedException("Multidimensional arrays not implemented"); return GenerateVTableForClass(compiler, baseClass); }
private static TypeSpecClassTag GetCachedClass(Compiler compiler, ref TypeSpecClassTag clsTagRef, string typeNamespace, string typeName) { TypeSpecClassTag clsTag = clsTagRef; if (clsTag != null) return clsTag; TypeNameTag name = new TypeNameTag("mscorlib", typeNamespace, typeName); name = compiler.TagRepository.InternTypeName(name); clsTag = new TypeSpecClassTag(name, new TypeSpecTag[0]); clsTag = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(clsTag); clsTagRef = clsTag; return clsTag; }
private TypeSpecClassTag ArrayClassForSubscript(TypeSpecTag subscriptType) { if (m_compiler.TypeIsValueType(subscriptType)) { TypeSpecClassTag subscriptClass = (TypeSpecClassTag)subscriptType; if (subscriptClass.TypeName == m_nullableName) { if (subscriptClass.ArgTypes.Length != 1) throw new RpaCompileException("Malformed Nullable"); TypeSpecClassTag classTag = new TypeSpecClassTag(m_nullableSZArrayName, subscriptClass.ArgTypes); classTag = (TypeSpecClassTag)m_compiler.TagRepository.InternTypeSpec(classTag); return classTag; } else { TypeSpecClassTag classTag = new TypeSpecClassTag(m_valueSZArrayName, new TypeSpecTag[1] { subscriptType }); classTag = (TypeSpecClassTag)m_compiler.TagRepository.InternTypeSpec(classTag); return classTag; } } else { TypeSpecClassTag classTag = new TypeSpecClassTag(m_refSZArrayName, new TypeSpecTag[0]); classTag = (TypeSpecClassTag)m_compiler.TagRepository.InternTypeSpec(classTag); return classTag; } }
private static void AddUniqueInterface(Dictionary<TypeSpecClassTag, int> uniqueDeps, TypeSpecClassTag ifc) { if (uniqueDeps.ContainsKey(ifc)) return; uniqueDeps.Add(ifc, uniqueDeps.Count); }
private TypeSpecClassTag ResolveSimpleType(string typeNamespace, string typeName) { TypeNameTag typeNameTag = new TypeNameTag("mscorlib", typeNamespace, typeName, 0, null); typeNameTag = m_compiler.TagRepository.InternTypeName(typeNameTag); TypeSpecClassTag classTag = new TypeSpecClassTag(typeNameTag, new TypeSpecTag[0]); return (TypeSpecClassTag)m_compiler.TagRepository.InternTypeSpec(classTag); }
public uint DevirtualizeInterfaceMethod(CliClass cls, TypeSpecClassTag ifcSpec, uint ifcSlotIndex) { if (!cls.IsSealed) throw new ArgumentException("Can't devirtualize a non-sealed class"); if (GetTypeDef(ifcSpec.TypeName).Semantics != TypeSemantics.Interface) throw new ArgumentException("Can't devirtualize an implementation of a non-interface"); return RecursiveDevirtualizeInterfaceMethod(cls, ifcSpec, ifcSlotIndex); }