public void AddCompilationRoots(IRootingServiceProvider rootProvider) { foreach (var type in _module.GetAllTypes()) { foreach (var method in type.GetMethods()) { EcmaMethod ecmaMethod = (EcmaMethod)method; if (ecmaMethod.IsRuntimeExport) { string runtimeExportName = ecmaMethod.GetRuntimeExportName(); if (runtimeExportName != null) { rootProvider.AddCompilationRoot(method, "Runtime export", runtimeExportName); } } if (ecmaMethod.IsNativeCallable) { string nativeCallableExportName = ecmaMethod.GetNativeCallableExportName(); if (nativeCallableExportName != null) { rootProvider.AddCompilationRoot(method, "Native callable", nativeCallableExportName); } } } } }
public static void RootType(IRootingServiceProvider rootProvider, TypeDesc type, string reason) { rootProvider.AddCompilationRoot(type, reason); // Instantiate generic types over something that will be useful at runtime if (type.IsGenericDefinition) { Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(type.Instantiation, allowCanon: true); if (inst.IsNull) { return; } type = ((MetadataType)type).MakeInstantiatedType(inst); rootProvider.AddCompilationRoot(type, reason); } // Also root base types. This is so that we make methods on the base types callable. // This helps in cases like "class Foo : Bar<int> { }" where we discover new // generic instantiations. TypeDesc baseType = type.BaseType; while (baseType != null) { baseType = baseType.NormalizeInstantiation(); RootType(rootProvider, baseType, reason); baseType = baseType.BaseType; } if (type.IsDefType) { foreach (var method in type.GetMethods()) { if (method.HasInstantiation) { // Generic methods on generic types could end up as Foo<object>.Bar<__Canon>(), // so for simplicity, we just don't handle them right now to make this more // predictable. if (!method.OwningType.HasInstantiation) { Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(method.Instantiation, allowCanon: false); if (!inst.IsNull) { RootMethod(rootProvider, method.MakeInstantiatedMethod(inst), reason); } } } else { RootMethod(rootProvider, method, reason); } } } }
private void ProcessTypeDirective(IRootingServiceProvider rootProvider, ModuleDesc containingModule, XElement typeElement) { var typeNameAttribute = typeElement.Attribute("Name"); if (typeNameAttribute == null) { throw new Exception(); } var dynamicDegreeAttribute = typeElement.Attribute("Dynamic"); if (dynamicDegreeAttribute != null) { if (dynamicDegreeAttribute.Value != "Required All") { throw new NotSupportedException(); } } string typeName = typeNameAttribute.Value; TypeDesc type = containingModule.GetTypeByCustomAttributeTypeName(typeName); rootProvider.AddCompilationRoot(type, "RD.XML root"); if (type.IsDefType) { foreach (var method in type.GetMethods()) { // We don't know what to instantiate generic methods over if (method.HasInstantiation) { continue; } // Virtual methods should be rooted as if they were called virtually if (method.IsVirtual) { MethodDesc slotMethod = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(method); rootProvider.RootVirtualMethodUse(slotMethod, "RD.XML root"); } // Abstract methods have no entrypoints if (method.IsAbstract) { continue; } rootProvider.AddCompilationRoot(method, "RD.XML root"); } } }
private void RootType(IRootingServiceProvider rootProvider, TypeDesc type) { rootProvider.AddCompilationRoot(type, "RD.XML root"); if (type.IsGenericDefinition) { return; } if (type.IsDefType) { foreach (var method in type.GetMethods()) { // We don't know what to instantiate generic methods over if (method.HasInstantiation) { continue; } try { LibraryRootProvider.CheckCanGenerateMethod(method); // Virtual methods should be rooted as if they were called virtually if (method.IsVirtual) { MethodDesc slotMethod = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(method); rootProvider.RootVirtualMethodForReflection(slotMethod, "RD.XML root"); } if (!method.IsAbstract) { rootProvider.AddCompilationRoot(method, "RD.XML root"); } } catch (TypeSystemException) { // TODO: fail compilation if a switch was passed // Individual methods can fail to load types referenced in their signatures. // Skip them in library mode since they're not going to be callable. continue; // TODO: Log as a warning } } } }
public void AddCompilationRoots(IRootingServiceProvider rootProvider) { foreach (var ecmaMethod in ExportedMethods) { if (ecmaMethod.IsRuntimeExport) { string runtimeExportName = ecmaMethod.GetRuntimeExportName(); rootProvider.AddCompilationRoot((MethodDesc)ecmaMethod, "Runtime export", runtimeExportName); } else if (ecmaMethod.IsUnmanagedCallersOnly) { string unmanagedCallersOnlyExportName = ecmaMethod.GetUnmanagedCallersOnlyExportName(); rootProvider.AddCompilationRoot((MethodDesc)ecmaMethod, "Native callable", unmanagedCallersOnlyExportName); } } }
public void AddCompilationRoots(IRootingServiceProvider rootProvider) { foreach (TypeDesc type in _module.GetAllTypes()) { // Skip delegates (since their Invoke methods have no IL) and uninstantiated generic types if (type.IsDelegate || type.ContainsGenericVariables) { continue; } try { rootProvider.AddCompilationRoot(type, "Library module type"); } catch (TypeSystemException) { // TODO: fail compilation if a switch was passed // Swallow type load exceptions while rooting continue; // TODO: Log as a warning } RootMethods(type, "Library module method", rootProvider); } }
private void RootMethods(TypeDesc type, string reason, IRootingServiceProvider rootProvider) { foreach (MethodDesc method in type.GetMethods()) { // Skip methods with no IL and uninstantiated generic methods if (method.IsIntrinsic || method.IsAbstract || method.HasInstantiation) continue; if (method.IsInternalCall) continue; try { CheckCanGenerateMethod(method); rootProvider.AddCompilationRoot(method, reason); } catch (TypeSystemException) { // TODO: fail compilation if a switch was passed // Individual methods can fail to load types referenced in their signatures. // Skip them in library mode since they're not going to be callable. continue; // TODO: Log as a warning } } }
public void AddCompilationRoots(IRootingServiceProvider rootProvider) { foreach (TypeDesc type in _module.GetAllTypes()) { // Skip delegates (since their Invoke methods have no IL) if (type.IsDelegate) continue; try { rootProvider.AddCompilationRoot(type, "Library module type"); } catch (TypeSystemException) { // TODO: fail compilation if a switch was passed // Swallow type load exceptions while rooting continue; // TODO: Log as a warning } // If this is not a generic definition, root all methods if (!type.HasInstantiation) RootMethods(type, "Library module method", rootProvider); } }
private void RootMethods(TypeDesc type, string reason, IRootingServiceProvider rootProvider) { foreach (MethodDesc method in type.GetAllMethods()) { // Skip methods with no IL and uninstantiated generic methods if (method.IsAbstract || method.HasInstantiation) { continue; } if (method.IsInternalCall) { continue; } try { CheckCanGenerateMethod(method); rootProvider.AddCompilationRoot(method, reason); } catch (TypeSystemException) { // TODO: fail compilation if a switch was passed // Individual methods can fail to load types referenced in their signatures. // Skip them in library mode since they're not going to be callable. continue; // TODO: Log as a warning } } }
private void RootMethod(IRootingServiceProvider rootProvider, MethodDesc method) { try { LibraryRootProvider.CheckCanGenerateMethod(method); // Virtual methods should be rooted as if they were called virtually if (method.IsVirtual) { MethodDesc slotMethod = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(method); rootProvider.RootVirtualMethodForReflection(slotMethod, "RD.XML root"); } if (!method.IsAbstract) { rootProvider.AddCompilationRoot(method, "RD.XML root"); } } catch (TypeSystemException) { // TODO: fail compilation if a switch was passed // Individual methods can fail to load types referenced in their signatures. // Skip them in library mode since they're not going to be callable. return; // TODO: Log as a warning } }
public void AddCompilationRoots(IRootingServiceProvider rootProvider) { foreach (TypeDesc type in _module.GetAllTypes()) { // Skip delegates (since their Invoke methods have no IL) if (type.IsDelegate) { continue; } try { rootProvider.AddCompilationRoot(type, "Library module type"); } catch (TypeSystemException) { // TODO: fail compilation if a switch was passed // Swallow type load exceptions while rooting continue; // TODO: Log as a warning } // If this is not a generic definition, root all methods if (!type.HasInstantiation) { RootMethods(type, "Library module method", rootProvider); } } }
public void AddCompilationRoots(IRootingServiceProvider rootProvider) { if (_context.SupportsUniversalCanon) { rootProvider.AddCompilationRoot(_context.UniversalCanonType.MakeArrayType(), "Universal generic array support"); } }
public void AddCompilationRoots(IRootingServiceProvider rootProvider) { TypeDesc owningType = _module.GetGlobalModuleType(); NativeLibraryStartupMethod nativeLibStartupCode = new NativeLibraryStartupMethod(owningType, _libraryInitializers); rootProvider.AddCompilationRoot(nativeLibStartupCode, "Startup Code Main Method", ManagedEntryPointMethodName); }
public void AddCompilationRoots(IRootingServiceProvider rootProvider) { foreach (TypeDesc type in _module.GetAllTypes()) { try { rootProvider.AddCompilationRoot(type, "Library module type"); } catch (TypeSystemException) { // TODO: fail compilation if a switch was passed // Swallow type load exceptions while rooting continue; // TODO: Log as a warning } // If this is not a generic definition, root all methods if (!type.HasInstantiation) { RootMethods(type, "Library module method", rootProvider); rootProvider.RootStaticBasesForType(type, "Library module type statics"); } } }
private void AddReflectionInitializationCode(IRootingServiceProvider rootProvider) { // System.Private.Reflection.Execution needs to establish a communication channel with System.Private.CoreLib // at process startup. This is done through an eager constructor that calls into CoreLib and passes it // a callback object. // // Since CoreLib cannot reference anything, the type and it's eager constructor won't be added to the compilation // unless we explictly add it. var refExec = _typeSystemContext.GetModuleForSimpleName("System.Private.Reflection.Execution", false); if (refExec != null) { var exec = refExec.GetKnownType("Internal.Reflection.Execution", "ReflectionExecution"); if (ContainsType(exec)) { rootProvider.AddCompilationRoot(exec.GetStaticConstructor(), "Reflection execution"); } } else { // If we can't find Reflection.Execution, we better be compiling a nonstandard thing (managed // portion of the runtime maybe?). Debug.Assert(_typeSystemContext.GetModuleForSimpleName("System.Private.CoreLib", false) == null); } }
void ICompilationRootProvider.AddCompilationRoots(IRootingServiceProvider rootProvider) { MetadataLoadedInfo loadedMetadata = _loadedMetadata.Value; // Add all non-generic reflectable methods as roots. // Virtual methods need special handling (e.g. with dependency tracking) since they can be abstract. foreach (var method in loadedMetadata.MethodMappings.Keys) { if (method.HasInstantiation || method.OwningType.HasInstantiation) { continue; } if (method.IsVirtual) { rootProvider.RootVirtualMethodForReflection(method, "Reflection root"); } else { rootProvider.AddCompilationRoot(method, "Reflection root"); } } // Root all the generic type instantiations from the pre-computed metadata foreach (var type in loadedMetadata.RequiredGenericTypes) { rootProvider.AddCompilationRoot(type, "Required instantiation"); } // Root all the generic methods (either non-generic methods on generic types, or generic methods) from // the pre-computed metadata. // Virtual methods need special handling (e.g. with dependency tracking) since they can be abstract. foreach (var method in loadedMetadata.RequiredGenericMethods) { if (method.IsVirtual) { rootProvider.RootVirtualMethodForReflection(method, "Required instantiation"); } else { rootProvider.AddCompilationRoot(method, "Required instantiation"); } } // TODO: required generic fields. Root containing type, and add field to list in ComputeMetadata() }
public void AddCompilationRoots(IRootingServiceProvider rootProvider) { rootProvider.AddCompilationRoot(_method, #if READYTORUN rootMinimalDependencies: false, #endif reason: "Single method root"); }
private void AddWellKnownTypes(IRootingServiceProvider rootProvider) { var stringType = _typeSystemContext.GetWellKnownType(WellKnownType.String); if (ContainsType(stringType)) { rootProvider.AddCompilationRoot(stringType, "String type is always generated"); } }
public void AddCompilationRoots(IRootingServiceProvider rootProvider) { foreach (var methodProfileInfo in _profileData.GetAllMethodProfileData()) { if (!methodProfileInfo.Flags.HasFlag(MethodProfilingDataFlags.ExcludeHotMethodCode) && !methodProfileInfo.Flags.HasFlag(MethodProfilingDataFlags.ExcludeColdMethodCode)) { try { MethodDesc method = methodProfileInfo.Method; CheckCanGenerateMethod(method); rootProvider.AddCompilationRoot(method, "Profile triggered method"); } catch (TypeSystemException) { // Individual methods can fail to load types referenced in their signatures. // Skip them in library mode since they're not going to be callable. continue; } } } if (!_profileData.PartialNGen) { foreach (TypeDesc type in _module.GetAllTypes()) { try { rootProvider.AddCompilationRoot(type, "Library module type"); } catch (TypeSystemException) { // Swallow type load exceptions while rooting continue; } // If this is not a generic definition, root all methods if (!type.HasInstantiation) { RootMethods(type, "Library module method", rootProvider); } } } }
void ICompilationRootProvider.AddCompilationRoots(IRootingServiceProvider rootProvider) { // We go over all the types and members that need a runtime artifact present in the // compiled executable and root it. const string reason = "Reflection"; foreach (var pair in _reflectableTypes) { if ((pair.Value & MetadataCategory.RuntimeMapping) != 0) { rootProvider.AddCompilationRoot(pair.Key, reason); } } foreach (var pair in _reflectableMethods) { if ((pair.Value & MetadataCategory.RuntimeMapping) != 0) { MethodDesc method = pair.Key; rootProvider.AddReflectionRoot(method, reason); } } foreach (var pair in _reflectableFields) { if ((pair.Value & MetadataCategory.RuntimeMapping) != 0) { FieldDesc field = pair.Key; // We only care about static fields at this point. Instance fields don't need // runtime artifacts generated in the image. if (field.IsStatic && !field.IsLiteral) { if (field.IsThreadStatic) { rootProvider.RootThreadStaticBaseForType(field.OwningType, reason); } else if (field.HasGCStaticBase) { rootProvider.RootGCStaticBaseForType(field.OwningType, reason); } else { rootProvider.RootNonGCStaticBaseForType(field.OwningType, reason); } } } } foreach (var type in _typesWithRootedCctorContext) { rootProvider.RootNonGCStaticBaseForType(type, reason); } }
public void AddCompilationRoots(IRootingServiceProvider rootProvider) { MethodDesc mainMethod = _module.EntryPoint; if (mainMethod == null) { throw new Exception("No managed entrypoint defined for executable module"); } rootProvider.AddCompilationRoot(mainMethod, "Managed Main Method"); }
private void AddCompilationRootsForMultifileLibrary(EcmaModule module, IRootingServiceProvider rootProvider) { foreach (TypeDesc type in module.GetAllTypes()) { // Skip delegates (since their Invoke methods have no IL) and uninstantiated generic types if (type.IsDelegate || type.ContainsGenericVariables) continue; rootProvider.AddCompilationRoot(type, "Library module type"); RootMethods(type, "Library module method", rootProvider); } }
public void AddCompilationRoots(IRootingServiceProvider rootProvider) { foreach (var ecmaMethod in ExportedMethods) { if (ecmaMethod.IsRuntimeExport) { string runtimeExportName = ecmaMethod.GetRuntimeExportName(); if (runtimeExportName != null) { rootProvider.AddCompilationRoot((MethodDesc)ecmaMethod, "Runtime export", runtimeExportName); } } else if (ecmaMethod.IsNativeCallable) { string nativeCallableExportName = ecmaMethod.GetNativeCallableExportName(); if (nativeCallableExportName != null) { rootProvider.AddCompilationRoot((MethodDesc)ecmaMethod, "Native callable", nativeCallableExportName); } } } }
private void ProcessTypeDirective(IRootingServiceProvider rootProvider, ModuleDesc containingModule, XElement typeElement) { var typeNameAttribute = typeElement.Attribute("Name"); if (typeNameAttribute == null) { throw new Exception(); } var dynamicDegreeAttribute = typeElement.Attribute("Dynamic"); if (dynamicDegreeAttribute != null) { if (dynamicDegreeAttribute.Value != "Required All") { throw new NotSupportedException(); } } string typeName = typeNameAttribute.Value; TypeDesc type = containingModule.GetTypeByCustomAttributeTypeName(typeName); rootProvider.AddCompilationRoot(type, "RD.XML root"); if (type.IsDefType) { foreach (var method in type.GetMethods()) { if (method.IsAbstract || method.HasInstantiation) { continue; } rootProvider.AddCompilationRoot(method, "RD.XML root"); } } }
public void AddCompilationRoots(IRootingServiceProvider rootProvider) { MethodDesc mainMethod = _module.EntryPoint; if (mainMethod == null) { throw new Exception("No managed entrypoint defined for executable module"); } TypeDesc owningType = _module.GetGlobalModuleType(); var startupCodeMain = new StartupCodeMainMethod(owningType, mainMethod, _libraryInitializers); rootProvider.AddCompilationRoot(startupCodeMain, "Startup Code Main Method", ManagedEntryPointMethodName); }
private void AddCompilationRootsForMultifileLibrary(EcmaModule module, IRootingServiceProvider rootProvider) { foreach (TypeDesc type in module.GetAllTypes()) { // Skip delegates (since their Invoke methods have no IL) and uninstantiated generic types if (type.IsDelegate || type.ContainsGenericVariables) { continue; } rootProvider.AddCompilationRoot(type, "Library module type"); RootMethods(type, "Library module method", rootProvider); } }
public void AddCompilationRoots(IRootingServiceProvider rootProvider) { foreach (var type in _module.GetAllTypes()) { foreach (var method in type.GetMethods()) { EcmaMethod ecmaMethod = (EcmaMethod)method; if (ecmaMethod.IsRuntimeExport) { string runtimeExportName = ecmaMethod.GetRuntimeExportName(); if (runtimeExportName != null) rootProvider.AddCompilationRoot(method, "Runtime export", runtimeExportName); } if (ecmaMethod.IsNativeCallable) { string nativeCallableExportName = ecmaMethod.GetNativeCallableExportName(); if (nativeCallableExportName != null) rootProvider.AddCompilationRoot(method, "Native callable", nativeCallableExportName); } } } }
public static void RootMethod(IRootingServiceProvider rootProvider, MethodDesc method, string reason) { // Make sure we're not putting something into the graph that will crash later. LibraryRootProvider.CheckCanGenerateMethod(method); // Virtual methods should be rooted as if they were called virtually if (method.IsVirtual) { rootProvider.RootVirtualMethodForReflection(method, reason); } if (!method.IsAbstract) { rootProvider.AddCompilationRoot(method, reason); } }
private void RootMethods(TypeDesc type, string reason, IRootingServiceProvider rootProvider) { foreach (MethodDesc method in type.GetMethods()) { // Skip methods with no IL and uninstantiated generic methods if (method.IsIntrinsic || method.IsAbstract || method.ContainsGenericVariables) { continue; } if (method.IsInternalCall) { continue; } rootProvider.AddCompilationRoot(method, reason); } }
private void RootMethods(TypeDesc type, string reason, IRootingServiceProvider rootProvider) { foreach (MethodDesc method in type.GetAllMethods()) { // Skip methods with no IL if (method.IsAbstract) { continue; } if (method.IsInternalCall) { continue; } MethodDesc methodToRoot = method; if (method.HasInstantiation) { methodToRoot = InstantiateIfPossible(method); if (methodToRoot == null) { continue; } } try { if (!CorInfoImpl.ShouldSkipCompilation(method)) { CheckCanGenerateMethod(methodToRoot); rootProvider.AddCompilationRoot(methodToRoot, reason); } } catch (TypeSystemException) { // Individual methods can fail to load types referenced in their signatures. // Skip them in library mode since they're not going to be callable. continue; } } }
private void AddMainMethodCompilationRoot(EcmaModule module, IRootingServiceProvider rootProvider) { if (StartupCodeMain != null) { throw new Exception("Multiple entrypoint modules"); } MethodDesc mainMethod = module.EntryPoint; if (mainMethod == null) { throw new Exception("No managed entrypoint defined for executable module"); } var owningType = module.GetGlobalModuleType(); StartupCodeMain = new StartupCodeMainMethod(owningType, mainMethod); rootProvider.AddCompilationRoot(StartupCodeMain, "Startup Code Main Method", "__managed__Main"); }
public void AddCompilationRoots(IRootingServiceProvider rootProvider) { foreach (TypeDesc type in _module.GetAllTypes()) { try { rootProvider.AddCompilationRoot(type, "Library module type"); } catch (TypeSystemException) { // Swallow type load exceptions while rooting continue; } // If this is not a generic definition, root all methods if (!type.HasInstantiation) { RootMethods(type, "Library module method", rootProvider); } } }
public static void RootType(IRootingServiceProvider rootProvider, TypeDesc type, string reason) { rootProvider.AddCompilationRoot(type, reason); if (type.IsGenericDefinition) { return; } if (type.IsDefType) { foreach (var method in type.GetMethods()) { if (method.HasInstantiation) { continue; } RootMethod(rootProvider, method, reason); } } }
void ICompilationRootProvider.AddCompilationRoots(IRootingServiceProvider rootProvider) { // We go over all the types and members that need a runtime artifact present in the // compiled executable and root it. const string reason = "Reflection"; foreach (var pair in _reflectableTypes) { if ((pair.Value & MetadataCategory.RuntimeMapping) != 0) { rootProvider.AddCompilationRoot(pair.Key, reason); } } foreach (var pair in _reflectableMethods) { if ((pair.Value & MetadataCategory.RuntimeMapping) != 0) { MethodDesc method = pair.Key; rootProvider.AddReflectionRoot(method, reason); } } foreach (var pair in _reflectableFields) { if ((pair.Value & MetadataCategory.RuntimeMapping) != 0) { FieldDesc field = pair.Key; rootProvider.AddReflectionRoot(field, reason); } } foreach (var type in _typesWithRootedCctorContext) { rootProvider.RootNonGCStaticBaseForType(type, reason); } }
private void RootWellKnownType(WellKnownType wellKnownType, IRootingServiceProvider rootProvider) { var type = _context.GetWellKnownType(wellKnownType); rootProvider.AddCompilationRoot(type, "Enables CPP codegen"); }
public override void AddCompilationRoots(IRootingServiceProvider rootProvider) { rootProvider.AddCompilationRoot(_method, "Single method mode"); }
public void AddCompilationRoots(IRootingServiceProvider rootProvider) { rootProvider.AddCompilationRoot(_method, "Single method root"); }
private void RootMethods(TypeDesc type, string reason, IRootingServiceProvider rootProvider) { foreach (MethodDesc method in type.GetMethods()) { // Skip methods with no IL and uninstantiated generic methods if (method.IsIntrinsic || method.IsAbstract || method.ContainsGenericVariables) continue; if (method.IsInternalCall) continue; rootProvider.AddCompilationRoot(method, reason); } }
private void AddMainMethodCompilationRoot(EcmaModule module, IRootingServiceProvider rootProvider) { if (StartupCodeMain != null) throw new Exception("Multiple entrypoint modules"); MethodDesc mainMethod = module.EntryPoint; if (mainMethod == null) throw new Exception("No managed entrypoint defined for executable module"); var owningType = module.GetGlobalModuleType(); StartupCodeMain = new StartupCodeMainMethod(owningType, mainMethod); rootProvider.AddCompilationRoot(StartupCodeMain, "Startup Code Main Method", "__managed__Main"); }
private void ProcessTypeDirective(IRootingServiceProvider rootProvider, ModuleDesc containingModule, XElement typeElement) { var typeNameAttribute = typeElement.Attribute("Name"); if (typeNameAttribute == null) throw new Exception(); var dynamicDegreeAttribute = typeElement.Attribute("Dynamic"); if (dynamicDegreeAttribute != null) { if (dynamicDegreeAttribute.Value != "Required All") throw new NotSupportedException(); } string typeName = typeNameAttribute.Value; TypeDesc type = containingModule.GetTypeByCustomAttributeTypeName(typeName); rootProvider.AddCompilationRoot(type, "RD.XML root"); if (type.IsDefType) { foreach (var method in type.GetMethods()) { if (method.IsAbstract || method.HasInstantiation) continue; rootProvider.AddCompilationRoot(method, "RD.XML root"); } } }