Merge pull request #3395 from lambdageek/dev/handles-strings
authorAleksey Kliger (λgeek) <akliger@gmail.com>
Wed, 31 Aug 2016 17:23:52 +0000 (13:23 -0400)
committerGitHub <noreply@github.com>
Wed, 31 Aug 2016 17:23:52 +0000 (13:23 -0400)
[runtime] Use coop handles in some String-returning icalls

102 files changed:
docs/sources/mono-api-gc.html
external/cecil
libgc/include/gc.h
mcs/class/Facades/System.Private.CoreLib.InteropServices/AssemblyInfo.cs [deleted file]
mcs/class/Facades/System.Private.CoreLib.InteropServices/Facades_System.Private.CoreLib.InteropServices-net_4_x.csproj [deleted file]
mcs/class/Facades/System.Private.CoreLib.InteropServices/Makefile [deleted file]
mcs/class/Facades/System.Private.CoreLib.InteropServices/System.Private.CoreLib.InteropServices-net_4_x.csproj [deleted file]
mcs/class/Facades/System.Private.CoreLib.InteropServices/System.Private.CoreLib.InteropServices.dll.sources [deleted file]
mcs/class/Facades/System.Private.CoreLib.InteropServices/TypeForwarders.cs [deleted file]
mcs/class/Facades/subdirs.make
mcs/class/System.Core/common_System.Core.dll.sources
mcs/class/System.Core/net_4_x_System.Core.dll.sources
mcs/class/System.ServiceModel/System.ServiceModel.Channels/HttpRequestChannel.cs
mcs/class/System/System.Net/HttpWebRequest.cs
mcs/class/corlib/ReferenceSources/AppContextSwitches.cs
mcs/class/corlib/System.Globalization/CultureInfo.cs
mcs/class/corlib/System.Text/Latin1Encoding.cs
mcs/class/corlib/System.Threading/Thread.cs
mcs/class/corlib/System/Environment.cs
mcs/class/corlib/Test/System.Globalization/CultureInfoTest.cs
mcs/class/corlib/Test/System.Text/ASCIIEncodingTest.cs
mcs/class/corlib/Test/System.Text/Latin1EncodingTest.cs [new file with mode: 0644]
mcs/class/corlib/Test/System.Threading.Tasks/TaskTest.cs
mcs/class/corlib/Test/System/DelegateTest.cs
mcs/class/corlib/corlib_test.dll.sources
mcs/class/referencesource/mscorlib/system/threading/thread.cs
mcs/mcs/anonymous.cs
mcs/mcs/statement.cs
mcs/tests/test-async-89.cs [new file with mode: 0644]
mcs/tests/ver-il-net_4_x.xml
mcs/tools/al/Al.cs
mono/metadata/boehm-gc.c
mono/metadata/domain.c
mono/metadata/gc-internals.h
mono/metadata/gc.c
mono/metadata/icall.c
mono/metadata/jit-info.c
mono/metadata/mono-gc.h
mono/metadata/profiler-private.h
mono/metadata/profiler.c
mono/metadata/profiler.h
mono/metadata/sgen-bridge-internals.h
mono/metadata/sgen-bridge.c
mono/metadata/sgen-bridge.h
mono/metadata/sgen-mono.c
mono/metadata/sgen-new-bridge.c
mono/metadata/sgen-old-bridge.c
mono/metadata/sgen-stw.c
mono/metadata/sgen-tarjan-bridge.c
mono/metadata/threads.c
mono/mini/aot-compiler.c
mono/mini/debugger-agent.c
mono/mini/mini-amd64.c
mono/mini/mini-arm.c
mono/mini/mini-ia64.c
mono/mini/mini-llvm.c
mono/mini/mini-mips.c
mono/mini/mini-ppc.c
mono/mini/mini-s390x.c
mono/mini/mini-sparc.c
mono/mini/mini-x86.c
mono/profiler/decode.c
mono/profiler/proflog.c
mono/profiler/proflog.h
mono/profiler/utils.c
mono/sgen/sgen-marksweep.c
mono/tests/sgen-bridge-pathologies.cs
mono/unit-tests/test-mono-linked-list-set.c
mono/utils/Makefile.am
mono/utils/atomic.h
mono/utils/hazard-pointer.c
mono/utils/hazard-pointer.h
mono/utils/lock-free-alloc.c
mono/utils/lock-free-queue.c
mono/utils/mono-compiler.h
mono/utils/mono-conc-hashtable.c
mono/utils/mono-hwcap-arm.c
mono/utils/mono-hwcap-arm.h [deleted file]
mono/utils/mono-hwcap-arm64.c
mono/utils/mono-hwcap-arm64.h [deleted file]
mono/utils/mono-hwcap-cross.c [new file with mode: 0644]
mono/utils/mono-hwcap-ia64.c
mono/utils/mono-hwcap-ia64.h [deleted file]
mono/utils/mono-hwcap-mips.c
mono/utils/mono-hwcap-mips.h [deleted file]
mono/utils/mono-hwcap-ppc.c
mono/utils/mono-hwcap-ppc.h [deleted file]
mono/utils/mono-hwcap-s390x.c
mono/utils/mono-hwcap-s390x.h [deleted file]
mono/utils/mono-hwcap-sparc.c
mono/utils/mono-hwcap-vars.h [new file with mode: 0644]
mono/utils/mono-hwcap-x86.c
mono/utils/mono-hwcap-x86.h [deleted file]
mono/utils/mono-hwcap.c
mono/utils/mono-hwcap.h
mono/utils/mono-linked-list-set.c
mono/utils/mono-linked-list-set.h
mono/utils/mono-membar.h
mono/utils/mono-threads-posix.c
mono/utils/mono-threads-windows.c
mono/utils/mono-threads.c
mono/utils/mono-threads.h

index 20d6cb9dc9b3566f7408862163ea6c0c98b30666..cddef0364cbfe34fa2f3fff6e0191d55853c9267 100644 (file)
@@ -40,9 +40,8 @@
        <p>The output of the SCC analysis is passed to the
        `cross_references()` callback.  It is expected to set the
        `is_alive` flag on those strongly connected components that it
-       wishes to be kept alive.  Only bridged objects will be
-       reported to the callback, i.e., non-bridged objects are
-       removed from the callback graph.
+       wishes to be kept alive.  The value of `is_alive` will be
+       ignored on any SCCs which lack bridges.
        
        <p>In monodroid each bridged object has a corresponding Java
        mirror object.  In the bridge callback it reifies the Mono
@@ -63,7 +62,7 @@
 
 <div class="mapi-header">
 enum {
-        SGEN_BRIDGE_VERSION = 4
+        SGEN_BRIDGE_VERSION = 5
 };
         
 typedef enum {
index ea18396c86ab3f8ba5d0fcd9ada9e066bd4f9f92..f38c0f5d99b6e44fa906d14e1146fa65a3806cd3 160000 (submodule)
@@ -1 +1 @@
-Subproject commit ea18396c86ab3f8ba5d0fcd9ada9e066bd4f9f92
+Subproject commit f38c0f5d99b6e44fa906d14e1146fa65a3806cd3
index e7929918ad0bb9df8d12b07a7803f660a8a3244f..7b1460a888ae20f5756aa3e8ad71781094541ffd 100644 (file)
@@ -93,6 +93,7 @@ GC_API GC_PTR (*GC_oom_fn) GC_PROTO((size_t bytes_requested));
                        /* pointer to a previously allocated heap       */
                        /* object.                                      */
 
+// Keep somewhat in sync with mono/metadata/profiler.h:enum MonoGCEvent
 typedef enum {
        GC_EVENT_START,
        GC_EVENT_MARK_START,
diff --git a/mcs/class/Facades/System.Private.CoreLib.InteropServices/AssemblyInfo.cs b/mcs/class/Facades/System.Private.CoreLib.InteropServices/AssemblyInfo.cs
deleted file mode 100644 (file)
index 833904b..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-// 
-// Copyright (c) 2015 Xamarin Inc. (http://www.xamarin.com)
-// 
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-// 
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-// 
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-// 
-
-using System;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-
-[assembly: AssemblyTitle ("System.Private.CoreLib.InteropServices.dll")]
-[assembly: AssemblyDescription ("System.Private.CoreLib.InteropServices.dll")]
-[assembly: AssemblyDefaultAlias ("System.Private.CoreLib.InteropServices.dll")]
-[assembly: AssemblyCompany ("Xamarin, Inc.")]
-[assembly: AssemblyProduct ("Mono Common Language Infrastructure")]
-[assembly: AssemblyCopyright ("Copyright (c) 2015 Xamarin Inc. (http://www.xamarin.com)")]
-[assembly: AssemblyVersion ("4.0.0.0")]
-[assembly: AssemblyInformationalVersion ("4.0.0.0")]
-[assembly: AssemblyFileVersion ("4.0.0.0")]
-[assembly: AssemblyDelaySign (true)]
-[assembly: AssemblyKeyFile ("../../msfinal.pub")]
diff --git a/mcs/class/Facades/System.Private.CoreLib.InteropServices/Facades_System.Private.CoreLib.InteropServices-net_4_x.csproj b/mcs/class/Facades/System.Private.CoreLib.InteropServices/Facades_System.Private.CoreLib.InteropServices-net_4_x.csproj
deleted file mode 100644 (file)
index c81a035..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <PropertyGroup>\r
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>\r
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>\r
-    <ProductVersion>9.0.30729</ProductVersion>\r
-    <SchemaVersion>2.0</SchemaVersion>\r
-    <ProjectGuid>{5D05F5E2-7378-4A35-B1A3-76ABEB4A71C3}</ProjectGuid>\r
-    <OutputType>Library</OutputType>\r
-    <NoWarn>1699,1616,1699</NoWarn>\r
-    <OutputPath>./../../../class/lib/net_4_x/Facades</OutputPath>\r
-    <IntermediateOutputPath>obj-Facades</IntermediateOutputPath>\r
-    <GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>\r
-    <NoStdLib>True</NoStdLib>\r
-    \r
-    <NoConfig>True</NoConfig>\r
-    \r
-    <AppDesignerFolder>Properties</AppDesignerFolder>\r
-    <RootNamespace>\r
-    </RootNamespace>\r
-    <AssemblyName>System.Private.CoreLib.InteropServices</AssemblyName>\r
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>\r
-    <FileAlignment>512</FileAlignment>\r
-  </PropertyGroup>\r
-    <PropertyGroup>\r
-    <SignAssembly>true</SignAssembly>\r
-    <DelaySign>true</DelaySign>\r
-  </PropertyGroup>\r
-  <PropertyGroup>\r
-    <AssemblyOriginatorKeyFile>../../msfinal.pub</AssemblyOriginatorKeyFile>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">\r
-    <DebugSymbols>true</DebugSymbols>\r
-    <DebugType>full</DebugType>\r
-    <NoWarn>1699,1616,1699</NoWarn>\r
-    <Optimize>false</Optimize>\r
-    <DefineConstants>TRACE;NET_4_0;NET_4_5;NET_4_6;MONO;DISABLE_CAS_USE</DefineConstants>\r
-    <ErrorReport>prompt</ErrorReport>\r
-    <WarningLevel>4</WarningLevel>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">\r
-    <DebugType>pdbonly</DebugType>\r
-    <NoWarn>1699,1616,1699</NoWarn>\r
-    <Optimize>true</Optimize>\r
-    <DefineConstants>NET_4_0;NET_4_5;NET_4_6;MONO;DISABLE_CAS_USE</DefineConstants>\r
-    <ErrorReport>prompt</ErrorReport>\r
-    <WarningLevel>4</WarningLevel>\r
-  </PropertyGroup>\r
-  <!-- Set AddAdditionalExplicitAssemblyReferences to false, otherwise if targetting .NET4.0, \r
-  Microsoft.NETFramework.props will force a dependency on the assembly System.Core. This\r
-  is a problem to compile the Mono mscorlib.dll -->\r
-  <PropertyGroup>\r
-    <AddAdditionalExplicitAssemblyReferences>false</AddAdditionalExplicitAssemblyReferences>\r
-  </PropertyGroup>\r
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />\r
-  <ItemGroup>\r
-    <Compile Include="AssemblyInfo.cs" />\r
-    <Compile Include="TypeForwarders.cs" />\r  </ItemGroup>\r
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \r
-       Other similar extension points exist, see Microsoft.Common.targets.\r
-  <Target Name="BeforeBuild">\r
-  </Target>\r
-  <Target Name="AfterBuild">\r
-  </Target>\r
-  -->\r
-  <PropertyGroup>\r
-    <PreBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">
-
-    </PreBuildEvent>\r
-    <PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">\r
-\r
-    </PreBuildEvent>\r
-    <PostBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">
-
-    </PostBuildEvent>\r
-    <PostBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">\r
-\r
-    </PostBuildEvent>\r
-  </PropertyGroup>\r
-  <ItemGroup>\r
-    <ProjectReference Include="../../corlib/corlib-net_4_x.csproj">\r
-      <Project>{2CA6026B-2DC8-4C4C-A12C-1E8234049DB7}</Project>\r
-      <Name>corlib-net_4_x</Name>\r
-    </ProjectReference>\r
-    <ProjectReference Include="../../System/System-net_4_x.csproj">\r
-      <Project>{2762E921-91A8-4C87-91E9-BA628013F753}</Project>\r
-      <Name>System-net_4_x</Name>\r
-    </ProjectReference>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <Folder Include="Properties\" />\r
-  </ItemGroup>\r
-</Project>\r
-
diff --git a/mcs/class/Facades/System.Private.CoreLib.InteropServices/Makefile b/mcs/class/Facades/System.Private.CoreLib.InteropServices/Makefile
deleted file mode 100644 (file)
index 7b03ca8..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-MCS_BUILD_DIR = ../../../build
-
-thisdir = class/Facades/System.Private.CoreLib.InteropServices
-SUBDIRS = 
-include $(MCS_BUILD_DIR)/rules.make
-
-LIBRARY_SUBDIR = Facades
-LIBRARY_INSTALL_DIR = $(mono_libdir)/mono/$(FRAMEWORK_VERSION)/Facades
-
-LIBRARY = System.Private.CoreLib.InteropServices.dll
-
-KEY_FILE = ../../msfinal.pub
-SIGN_FLAGS = /delaysign /keyfile:$(KEY_FILE) /nowarn:1616,1699
-LIB_REFS = System
-LIB_MCS_FLAGS = $(SIGN_FLAGS) 
-
-PLATFORM_DEBUG_FLAGS =
-
-NO_TEST = yes
-
-include $(MCS_BUILD_DIR)/library.make
-
-
diff --git a/mcs/class/Facades/System.Private.CoreLib.InteropServices/System.Private.CoreLib.InteropServices-net_4_x.csproj b/mcs/class/Facades/System.Private.CoreLib.InteropServices/System.Private.CoreLib.InteropServices-net_4_x.csproj
deleted file mode 100644 (file)
index 4813330..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <PropertyGroup>\r
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>\r
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>\r
-    <ProductVersion>9.0.30729</ProductVersion>\r
-    <SchemaVersion>2.0</SchemaVersion>\r
-    <ProjectGuid>{BE4A05DF-5630-4E80-9521-7B4216229A60}</ProjectGuid>\r
-    <OutputType>Library</OutputType>\r
-    <NoWarn>1699,1616,1699</NoWarn>\r
-    <OutputPath>./../../../class/lib/net_4_x/Facades</OutputPath>\r
-    <NoStdLib>True</NoStdLib>\r
-    <NoConfig>True</NoConfig>\r
-    \r
-    <AppDesignerFolder>Properties</AppDesignerFolder>\r
-    <RootNamespace>\r
-    </RootNamespace>\r
-    <AssemblyName>System.Private.CoreLib.InteropServices</AssemblyName>\r
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>\r
-    <FileAlignment>512</FileAlignment>\r
-  </PropertyGroup>\r
-    <PropertyGroup>\r
-    <SignAssembly>true</SignAssembly>\r
-    <DelaySign>true</DelaySign>\r
-  </PropertyGroup>\r
-  <PropertyGroup>\r
-    <AssemblyOriginatorKeyFile>../../msfinal.pub</AssemblyOriginatorKeyFile>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">\r
-    <DebugSymbols>true</DebugSymbols>\r
-    <DebugType>full</DebugType>\r
-    <NoWarn>1699,1616,1699</NoWarn>\r
-    <Optimize>false</Optimize>\r
-    <DefineConstants>DEBUG;TRACE;NET_4_0;NET_4_5;NET_4_6;MONO;DISABLE_CAS_USE</DefineConstants>\r
-    <ErrorReport>prompt</ErrorReport>\r
-    <WarningLevel>4</WarningLevel>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">\r
-    <DebugType>pdbonly</DebugType>\r
-    <NoWarn>1699,1616,1699</NoWarn>\r
-    <Optimize>true</Optimize>\r
-    <DefineConstants>NET_4_0;NET_4_5;NET_4_6;MONO;DISABLE_CAS_USE</DefineConstants>\r
-    <ErrorReport>prompt</ErrorReport>\r
-    <WarningLevel>4</WarningLevel>\r
-  </PropertyGroup>\r
-  <!-- Set AddAdditionalExplicitAssemblyReferences to false, otherwise if targetting .NET4.0, \r
-  Microsoft.NETFramework.props will force a dependency on the assembly System.Core. This\r
-  is a problem to compile the Mono mscorlib.dll -->\r
-  <PropertyGroup>\r
-    <AddAdditionalExplicitAssemblyReferences>false</AddAdditionalExplicitAssemblyReferences>\r
-  </PropertyGroup>\r
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />\r
-  <ItemGroup>\r
-    <Compile Include="AssemblyInfo.cs" />\r
-    <Compile Include="TypeForwarders.cs" />\r  </ItemGroup>\r
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \r
-       Other similar extension points exist, see Microsoft.Common.targets.\r
-  <Target Name="BeforeBuild">\r
-  </Target>\r
-  <Target Name="AfterBuild">\r
-  </Target>\r
-  -->\r
-  <PropertyGroup>\r
-    <PreBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">\r
-\r
-    </PreBuildEvent>\r
-    <PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">\r
-\r
-    </PreBuildEvent>\r
-\r
-    <PostBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">\r
-\r
-    </PostBuildEvent>\r
-    <PostBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">\r
-\r
-    </PostBuildEvent>\r
-  </PropertyGroup>\r
-  <ItemGroup>\r
-    <ProjectReference Include="../../corlib/corlib-net_4_x.csproj">\r
-      <Project>{2CA6026B-2DC8-4C4C-A12C-1E8234049DB7}</Project>\r
-      <Name>corlib-net_4_x</Name>\r
-    </ProjectReference>\r
-    <ProjectReference Include="../../corlib/corlib-net_4_x.csproj">\r
-      <Project>{2CA6026B-2DC8-4C4C-A12C-1E8234049DB7}</Project>\r
-      <Name>corlib-net_4_x</Name>\r
-    </ProjectReference>\r
-    <ProjectReference Include="../../System/System-net_4_x.csproj">\r
-      <Project>{2762E921-91A8-4C87-91E9-BA628013F753}</Project>\r
-      <Name>System-net_4_x</Name>\r
-    </ProjectReference>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <Folder Include="Properties\" />\r
-  </ItemGroup>\r
-</Project>\r
-
diff --git a/mcs/class/Facades/System.Private.CoreLib.InteropServices/System.Private.CoreLib.InteropServices.dll.sources b/mcs/class/Facades/System.Private.CoreLib.InteropServices/System.Private.CoreLib.InteropServices.dll.sources
deleted file mode 100644 (file)
index 8e33d4d..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-TypeForwarders.cs
-AssemblyInfo.cs
-
diff --git a/mcs/class/Facades/System.Private.CoreLib.InteropServices/TypeForwarders.cs b/mcs/class/Facades/System.Private.CoreLib.InteropServices/TypeForwarders.cs
deleted file mode 100644 (file)
index 7a1269d..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-// 
-// Copyright (c) 2015 Xamarin Inc. (http://www.xamarin.com)
-// 
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-// 
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-// 
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-// 
-
-[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.InteropServices.CallingConvention))]
-[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.InteropServices.DllImportAttribute))]
-[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.InteropServices.GCHandle))]
-[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.InteropServices.GCHandleType))]
-[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.InteropServices.SafeHandle))]
-
-//Missing: [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(Internal.Reflection.Execution.PayForPlayExperience.MissingMetadataExceptionCreator))]
-//Missing: [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.CompilerServices.DependencyReductionTypeRemoved))]
-//Missing: [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.CompilerServices.PreInitializedAttribute))]
-//Missing: [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.InteropServices.InteropExtensions))]
-//Missing: [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.InteropServices.NativeCallableAttributes))]
-//Missing: [assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(System.Runtime.RuntimeImportAttribute))]
index df1dd020404535839b69b35be715b25cdb7a9275..c980d70840d4d7c2def8ece1b62f4ce110d13c8c 100644 (file)
@@ -24,7 +24,7 @@ System.Security.Cryptography.Encryption.Aes System.Security.Cryptography.Encrypt
 System.Security.Cryptography.Hashing.Algorithms System.Security.Cryptography.RSA System.Security.Cryptography.RandomNumberGenerator \
 System.Security.Principal.Windows System.Threading.Thread System.Threading.ThreadPool \
 System.Xml.XPath System.Xml.XmlDocument System.Xml.Xsl.Primitives Microsoft.Win32.Registry.AccessControl System.Diagnostics.StackTrace System.Globalization.Extensions \
-System.IO.FileSystem.AccessControl System.Private.CoreLib.InteropServices System.Reflection.TypeExtensions \
+System.IO.FileSystem.AccessControl System.Reflection.TypeExtensions \
 System.Security.SecureString System.Threading.AccessControl System.Threading.Overlapped System.Xml.XPath.XDocument \
 System.Security.Cryptography.Primitives System.Text.Encoding.CodePages System.IO.FileSystem.Watcher \
 System.Security.Cryptography.ProtectedData System.ServiceProcess.ServiceController System.IO.Pipes
index f6a3f9b546078bc94ddbe43598ca8cdb33f58b3e..6e36c961e353774dd0f024fb71287f0911d7f8aa 100644 (file)
@@ -21,10 +21,15 @@ System.IO.Pipes/AnonymousPipeClientStream.cs
 System.IO.Pipes/AnonymousPipeServerStream.cs
 System.IO.Pipes/NamedPipeClientStream.cs
 System.IO.Pipes/NamedPipeServerStream.cs
+System.IO.Pipes/PipeAccessRights.cs
+System.IO.Pipes/PipeAccessRule.cs
+System.IO.Pipes/PipeAuditRule.cs
 System.IO.Pipes/PipeDirection.cs
 System.IO.Pipes/PipeInterfaces.cs
 System.IO.Pipes/PipeOptions.cs
+System.IO.Pipes/PipeSecurity.cs
 System.IO.Pipes/PipeStream.cs
+System.IO.Pipes/PipeStreamImpersonationWorker.cs
 System.IO.Pipes/PipeTransmissionMode.cs
 
 ReferenceSources/SR.cs
index f367efd60c7562e4d1253707eed5828ace4a90e5..72d78659215f4a1661166b8791c9a345beb43182 100644 (file)
@@ -1,11 +1,6 @@
 #include common_System.Core.dll.sources
 #include dynamic_System.Core.dll.sources
 
-System.IO.Pipes/PipeAccessRights.cs
-System.IO.Pipes/PipeAccessRule.cs
-System.IO.Pipes/PipeAuditRule.cs
-System.IO.Pipes/PipeSecurity.cs
-System.IO.Pipes/PipeStreamImpersonationWorker.cs
 System.IO.Pipes/PipeUnix.cs
 System.IO.Pipes/PipeWin32.cs
 
index 77995b55137a7127af793c38a406ebe1bb7fe3d3..4e4d73f9fb186fe974c15de0cfd45fdfa692f4eb 100644 (file)
@@ -126,6 +126,7 @@ namespace System.ServiceModel.Channels
                        }
 
                        web_request.Timeout = (int) timeout.TotalMilliseconds;
+                       web_request.KeepAlive = httpbe.KeepAliveEnabled;
 
                        // There is no SOAP Action/To header when AddressingVersion is None.
                        if (message.Version.Envelope.Equals (EnvelopeVersion.Soap11) ||
index 25a5d2877fdc4e4d6409f3c4d8a14b26469593e6..9f94783258dfa6a4067bebd666584507334cfd6c 100644 (file)
@@ -450,7 +450,7 @@ namespace System.Net
                                        newWebHeaders.Add(headerName,webHeaders[headerName]);
                                }
 
-                               webHeaders = newWebHeaders;
+                               this.webHeaders = newWebHeaders;
                        }
                }
                
index 55d45d833e3f6a5c74d371e8e118d0e5861f7edd..8874423d8492c49421debe9a2795fd721964f6a8 100644 (file)
@@ -2,5 +2,6 @@ namespace System {
        static class AppContextSwitches {
                public static readonly bool ThrowExceptionIfDisposedCancellationTokenSource = true;
                public static readonly bool SetActorAsReferenceWhenCopyingClaimsIdentity = false;
+               public static readonly bool NoAsyncCurrentCulture = false;
        }
 }
\ No newline at end of file
index 66914166bc3d20efc61cc573ff314535515711b2..e6741d4d3caf2c0cf6467e382e9821c4281646eb 100644 (file)
@@ -116,6 +116,9 @@ namespace System.Globalization
                const int CalendarTypeBits = 8;
 
                const string MSG_READONLY = "This instance is read only";
+
+               static volatile CultureInfo s_DefaultThreadCurrentUICulture;
+               static volatile CultureInfo s_DefaultThreadCurrentCulture;
                
                public static CultureInfo InvariantCulture {
                        get {
@@ -128,7 +131,7 @@ namespace System.Globalization
                                return Thread.CurrentThread.CurrentCulture;
                        }
                        set {
-                               throw new NotImplementedException ();
+                               Thread.CurrentThread.CurrentCulture = value;
                        }
                }
 
@@ -137,7 +140,7 @@ namespace System.Globalization
                                return Thread.CurrentThread.CurrentUICulture;
                        }
                        set {
-                               throw new NotImplementedException ();
+                               Thread.CurrentThread.CurrentUICulture = value;
                        }
                }
 
@@ -511,7 +514,7 @@ namespace System.Globalization
                        }
                }
 
-               internal void CheckNeutral ()
+               void CheckNeutral ()
                {
                }
 
@@ -1070,19 +1073,19 @@ namespace System.Globalization
                
                public static CultureInfo DefaultThreadCurrentCulture {
                        get {
-                               return Thread.default_culture;
+                               return s_DefaultThreadCurrentCulture;
                        }
                        set {
-                               Thread.default_culture = value;
+                               s_DefaultThreadCurrentCulture = value;
                        }
                }
                
                public static CultureInfo DefaultThreadCurrentUICulture {
                        get {
-                               return Thread.default_ui_culture;
+                               return s_DefaultThreadCurrentUICulture;
                        }
                        set {
-                               Thread.default_ui_culture = value;
+                               s_DefaultThreadCurrentUICulture = value;
                        }
                }
 
@@ -1092,6 +1095,19 @@ namespace System.Globalization
                        }
                }
 
+               internal static CultureInfo UserDefaultUICulture {
+                       get {
+                               return ConstructCurrentUICulture ();
+                       }
+               }
+
+               internal static CultureInfo UserDefaultCulture {
+                       get {
+                               return ConstructCurrentCulture ();
+                       }
+               }
+
+
 #region reference sources
                // TODO:
                internal static readonly bool IsTaiwanSku;
@@ -1144,6 +1160,19 @@ namespace System.Globalization
             return true;
         }
 
+        internal static bool VerifyCultureName(CultureInfo culture, bool throwException) {
+            Contract.Assert(culture!=null, "[CultureInfo.VerifyCultureName]culture!=null");
+
+            //If we have an instance of one of our CultureInfos, the user can't have changed the
+            //name and we know that all names are valid in files.
+            if (!culture.m_isInherited) {
+                return true;
+            }
+
+            return VerifyCultureName(culture.Name, throwException);
+
+        }
+
 #endregion
        }
 }
index f64237aaf6a7ef85e98ee51b2fd4a52174c3039c..0d87d5624e976237fd27f47acfba26b4c8a591d2 100644 (file)
@@ -157,7 +157,11 @@ internal class Latin1Encoding : Encoding
                                        buffer = EncoderFallback.CreateFallbackBuffer ();
                                if (Char.IsSurrogate (ch) && count > 1 &&
                                    Char.IsSurrogate (chars [charIndex]))
-                                       buffer.Fallback (ch, chars [charIndex], charIndex++ - 1);
+                               {
+                                       buffer.Fallback (ch, chars [charIndex], charIndex - 1);
+                                       charIndex++;
+                                       count--;
+                               }
                                else
                                        buffer.Fallback (ch, charIndex - 1);
                                if (fallback_chars == null || fallback_chars.Length < buffer.Remaining)
index 7527667be3f9394a2a95fc7a949e38b774fac6ef..f1924b22e07ef7e603d8d2446de8ff0a85ff1e7a 100644 (file)
@@ -122,10 +122,6 @@ namespace System.Threading {
 
                IPrincipal principal;
                int principal_version;
-               bool current_culture_set;
-               bool current_ui_culture_set;
-               CultureInfo current_culture;
-               CultureInfo current_ui_culture;
 
                // the name of current_thread is
                // important because they are used by the runtime.
@@ -133,9 +129,6 @@ namespace System.Threading {
                [ThreadStatic]
                static Thread current_thread;
 
-               static internal CultureInfo default_culture;
-               static internal CultureInfo default_ui_culture;
-
                // can be both a ThreadStart and a ParameterizedThreadStart
                private MulticastDelegate m_Delegate;
 
@@ -340,54 +333,6 @@ namespace System.Threading {
                        }
                }
 
-               //[MethodImplAttribute (MethodImplOptions.InternalCall)]
-               //private static extern int current_lcid ();
-
-               public CultureInfo CurrentCulture {
-                       get {
-                               CultureInfo culture = current_culture;
-                               if (current_culture_set && culture != null)
-                                       return culture;
-
-                               if (default_culture != null)
-                                       return default_culture;
-
-                               current_culture = culture = CultureInfo.ConstructCurrentCulture ();
-                               return culture;
-                       }
-                       
-                       [SecurityPermission (SecurityAction.Demand, ControlThread=true)]
-                       set {
-                               if (value == null)
-                                       throw new ArgumentNullException ("value");
-
-                               value.CheckNeutral ();
-                               current_culture = value;
-                               current_culture_set = true;
-                       }
-               }
-
-               public CultureInfo CurrentUICulture {
-                       get {
-                               CultureInfo culture = current_ui_culture;
-                               if (current_ui_culture_set && culture != null)
-                                       return culture;
-
-                               if (default_ui_culture != null)
-                                       return default_ui_culture;
-
-                               current_ui_culture = culture = CultureInfo.ConstructCurrentUICulture ();
-                               return culture;
-                       }
-                       
-                       set {
-                               if (value == null)
-                                       throw new ArgumentNullException ("value");
-                               current_ui_culture = value;
-                               current_ui_culture_set = true;
-                       }
-               }
-
                public bool IsThreadPoolThread {
                        get {
                                return IsThreadPoolThreadInternal;
@@ -723,11 +668,6 @@ namespace System.Threading {
                        return ManagedThreadId;
                }
 
-               internal CultureInfo GetCurrentUICultureNoAppX ()
-               {
-                       return CultureInfo.CurrentUICulture;
-               }
-
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                internal static extern void GetStackTraces (out Thread[] threads, out object[] stack_frames);
 
index 87096678d30b76a4e4a9632e3446e7e1b42ca0ac..36ae8687aae76a3cf40e67ae5f76c4dc32993fed 100644 (file)
@@ -870,6 +870,22 @@ namespace System {
                        }
                }
 #else
+               public static string GetEnvironmentVariable (string variable, EnvironmentVariableTarget target)
+               {
+                       if (target == EnvironmentVariableTarget.Process)
+                               return GetEnvironmentVariable (variable);
+
+                       return null;
+               }
+
+               public static IDictionary GetEnvironmentVariables (EnvironmentVariableTarget target)
+               {
+                       if (target == EnvironmentVariableTarget.Process)
+                               return GetEnvironmentVariables ();
+
+                       return (IDictionary)new Hashtable ();
+               }
+
                public static void SetEnvironmentVariable (string variable, string value)
                {
                        if (variable == null)
@@ -883,6 +899,14 @@ namespace System {
 
                        InternalSetEnvironmentVariable (variable, value);
                }
+
+               public static void SetEnvironmentVariable (string variable, string value, EnvironmentVariableTarget target)
+               {
+                       if (target == EnvironmentVariableTarget.Process)
+                               SetEnvironmentVariable (variable, value);
+
+                       // other targets ignored
+               }
 #endif
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                internal static extern void InternalSetEnvironmentVariable (string variable, string value);
index 231b829c50947d22adcf4ea2a171ce85648ae8f3..124aacd130248c037dac8a37f8ced82b6e8962a4 100644 (file)
@@ -12,6 +12,7 @@ using System.Globalization;
 using System.IO;
 using System.Runtime.Serialization.Formatters.Binary;
 using System.Threading;
+using System.Threading.Tasks;
 
 using NUnit.Framework;
 
@@ -727,20 +728,37 @@ namespace MonoTests.System.Globalization
                }
 
                [Test]
-               public void DefaultThreadCurrentCultureAndNumberFormaters () {
+               public void DefaultThreadCurrentCultureIsIgnoredWhenCultureFlowsToThread ()
+               {
                        string us_str = null;
                        string br_str = null;
+
                        var thread = new Thread (() => {
                                CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
                                us_str = 100000.ToString ("C");
                                CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("pt-BR");
                                br_str = 100000.ToString ("C");
                        });
+
+                       var expected = 100000.ToString ("C");
+
                        thread.Start ();
                        thread.Join ();
                        CultureInfo.DefaultThreadCurrentCulture = null;
-                       Assert.AreEqual ("$100,000.00", us_str, "#1");
-                       Assert.AreEqual ("R$ 100.000,00", br_str, "#2");
+                       Assert.AreEqual (expected, us_str, "#1");
+                       Assert.AreEqual (expected, br_str, "#2");
+               }
+
+               [Test]
+               public void FlowCultureInfoFromParentThreadSinceNet46 ()
+               {
+                       Func<Task> f = async () => {
+                               Thread.CurrentThread.CurrentUICulture = new CultureInfo ("pt-BR");
+                               await Task.Yield ();
+                               Assert.AreEqual ("pt-BR", Thread.CurrentThread.CurrentUICulture.Name);
+                       };
+
+                       f ().Wait ();
                }
        }
 }
index 16fca588d1e4a395222bdd3c7e335fba2b898143..f35a9d3883062cb04a0eaeeeff65f3ef43dc9116 100644 (file)
@@ -119,6 +119,40 @@ namespace MonoTests.System.Text
                                Assert.AreEqual (testchars [i], (char) bytes [i]);
                }
 
+               [Test] // Test GetBytes(string)
+               public void TestGetBytes7 ()
+               {
+                       var latin1_encoding = Encoding.GetEncoding ("latin1");
+
+                       var expected = new byte [] { 0x3F, 0x20, 0x3F, 0x20, 0x3F };
+                       var actual = latin1_encoding.GetBytes("\u24c8 \u2075 \u221e"); // normal replacement
+                       Assert.AreEqual (expected, actual, "#1");
+
+                       expected = new byte [] { 0x3F, 0x3F };
+                       actual = latin1_encoding.GetBytes("\ud83d\ude0a"); // surrogate pair replacement
+                       Assert.AreEqual (expected, actual, "#2");
+
+                       expected = new byte [] { 0x3F, 0x3F, 0x20 };
+                       actual = latin1_encoding.GetBytes("\ud83d\ude0a "); // surrogate pair replacement
+                       Assert.AreEqual (expected, actual, "#3");
+
+                       expected = new byte [] { 0x20, 0x20, 0x3F, 0x3F, 0x20, 0x20 };
+                       actual = latin1_encoding.GetBytes("  \ud83d\ude0a  "); // surrogate pair replacement
+                       Assert.AreEqual (expected, actual, "#4");
+
+                       expected = new byte [] { 0x20, 0x20, 0x3F, 0x3F, 0x20, 0x20 };
+                       actual = latin1_encoding.GetBytes("  \ud834\udd1e  "); // surrogate pair replacement
+                       Assert.AreEqual (expected, actual, "#5");
+
+                       expected = new byte [] { 0x41, 0x42, 0x43, 0x00, 0x41, 0x42, 0x43 };
+                       actual = latin1_encoding.GetBytes("ABC\0ABC"); // embedded zero byte not replaced
+                       Assert.AreEqual (expected, actual, "#6");
+
+                       expected = new byte [] { 0x20, 0x20, 0x3F, 0x20, 0x20 };
+                       actual = latin1_encoding.GetBytes("  \ud834  "); // invalid surrogate pair replacement
+                       Assert.AreEqual (expected, actual, "#7");
+               }
+
                [Test] // Test GetChars(byte[])
                public void TestGetChars1 () 
                {
@@ -212,6 +246,15 @@ namespace MonoTests.System.Text
                        Assert.AreEqual (string.Empty, encoding.GetString (new byte [0], 0, 0), "#2");
                }
 
+               [Test]
+               [ExpectedException (typeof (EncoderFallbackException))]
+               public void EncoderFallback ()
+               {
+                       Encoding e = Encoding.ASCII.Clone () as Encoding;
+                       e.EncoderFallback = new EncoderExceptionFallback ();
+                       e.GetBytes ("\u24c8");
+               }
+
                [Test]
                [ExpectedException (typeof (DecoderFallbackException))]
                public void DecoderFallback ()
diff --git a/mcs/class/corlib/Test/System.Text/Latin1EncodingTest.cs b/mcs/class/corlib/Test/System.Text/Latin1EncodingTest.cs
new file mode 100644 (file)
index 0000000..0195967
--- /dev/null
@@ -0,0 +1,350 @@
+//
+// Latin1EncodingTest.cs
+//
+// Author:
+//     Alexander Köplinger (alexander.koeplinger@xamarin.com)
+//
+// Copyright (C) 2016 Xamarin, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Text;
+
+using NUnit.Framework;
+using NUnit.Framework.Constraints;
+
+#if !MOBILE
+using NUnit.Framework.SyntaxHelpers;
+#endif
+
+namespace MonoTests.System.Text
+{
+       [TestFixture]
+       public class Latin1EncodingTest
+       {
+               private char[] testchars;
+               private byte[] testbytes;
+
+               [SetUp]
+               public void SetUp ()
+               {
+                       testchars = new char[4];
+                       testchars[0] = 'T';
+                       testchars[1] = 'e';
+                       testchars[2] = 's';
+                       testchars[3] = 't';
+                       testbytes = new byte[4];
+                       testbytes[0] = (byte) 'T';
+                       testbytes[1] = (byte) 'e';
+                       testbytes[2] = (byte) 's';
+                       testbytes[3] = (byte) 't';
+               }
+
+               [Test]
+               public void IsBrowserDisplay ()
+               {
+                       Assert.IsTrue (Encoding.GetEncoding ("latin1").IsBrowserDisplay);
+               }
+
+               [Test]
+               public void IsBrowserSave ()
+               {
+                       Assert.IsTrue (Encoding.GetEncoding ("latin1").IsBrowserSave);
+               }
+
+               [Test]
+               public void IsMailNewsDisplay ()
+               {
+                       Assert.IsTrue (Encoding.GetEncoding ("latin1").IsMailNewsDisplay);
+               }
+
+               [Test]
+               public void IsMailNewsSave ()
+               {
+                       Assert.IsTrue (Encoding.GetEncoding ("latin1").IsMailNewsSave);
+               }
+
+               [Test] // Test GetBytes(char[])
+               public void TestGetBytes1 () 
+               {
+                       Encoding latin1_encoding = Encoding.GetEncoding ("latin1");
+                       byte[] bytes = latin1_encoding.GetBytes(testchars);
+                       for (int i = 0; i < testchars.Length; i++)
+                               Assert.AreEqual (testchars[i], (char) bytes[i]);
+               }
+
+               [Test] // Test GetBytes(char[], int, int)
+               public void TestGetBytes2 () 
+               {
+                       Encoding latin1_encoding = Encoding.GetEncoding ("latin1");
+                       byte[] bytes = latin1_encoding.GetBytes(testchars, 1, 1);
+                       Assert.AreEqual (1, bytes.Length, "#1");
+                       Assert.AreEqual (testchars [1], (char) bytes [0], "#2");
+               }
+
+               [Test] // Test non-Latin1 char in char[]
+               public void TestGetBytes3 () 
+               {
+                       Encoding latin1_encoding = Encoding.GetEncoding ("latin1");
+                       testchars[2] = (char) 0x100;
+                       byte[] bytes = latin1_encoding.GetBytes(testchars);
+                       Assert.AreEqual ('T', (char) bytes [0], "#1");
+                       Assert.AreEqual ('e', (char) bytes [1], "#2");
+                       Assert.AreEqual ('?', (char) bytes [2], "#3");
+                       Assert.AreEqual ('t', (char) bytes [3], "#4");
+               }
+
+               [Test] // Test GetBytes(char[], int, int, byte[], int)
+               public void TestGetBytes4 () 
+               {
+                       Encoding latin1_encoding = Encoding.GetEncoding ("latin1");
+                       byte[] bytes = new Byte[1];
+                       int cnt = latin1_encoding.GetBytes(testchars, 1, 1, bytes, 0);
+                       Assert.AreEqual (1, cnt, "#1");
+                       Assert.AreEqual (testchars [1], (char) bytes [0], "#2");
+               }
+
+               [Test] // Test GetBytes(string, int, int, byte[], int)
+               public void TestGetBytes5 () 
+               {
+                       Encoding latin1_encoding = Encoding.GetEncoding ("latin1");
+                       byte[] bytes = new Byte[1];
+                       int cnt = latin1_encoding.GetBytes("Test", 1, 1, bytes, 0);
+                       Assert.AreEqual ('e', (char) bytes [0], "#1");
+               }
+
+               [Test] // Test GetBytes(string)
+               public void TestGetBytes6 () 
+               {
+                       Encoding latin1_encoding = Encoding.GetEncoding ("latin1");
+                       byte[] bytes = latin1_encoding.GetBytes("Test");
+                       for (int i = 0; i < testchars.Length; i++)
+                               Assert.AreEqual (testchars [i], (char) bytes [i]);
+               }
+
+               [Test] // Test GetBytes(string)
+               public void TestGetBytes7 ()
+               {
+                       var latin1_encoding = Encoding.GetEncoding ("latin1");
+
+                       var expected = new byte [] { 0x3F, 0x20, 0x3F, 0x20, 0x3F };
+                       var actual = latin1_encoding.GetBytes("\u24c8 \u2075 \u221e"); // normal replacement
+                       Assert.AreEqual (expected, actual, "#1");
+
+                       expected = new byte [] { 0x3F, 0x3F };
+                       actual = latin1_encoding.GetBytes("\ud83d\ude0a"); // surrogate pair replacement
+                       Assert.AreEqual (expected, actual, "#2");
+
+                       expected = new byte [] { 0x3F, 0x3F, 0x20 };
+                       actual = latin1_encoding.GetBytes("\ud83d\ude0a "); // surrogate pair replacement
+                       Assert.AreEqual (expected, actual, "#3");
+
+                       expected = new byte [] { 0x20, 0x20, 0x3F, 0x3F, 0x20, 0x20 };
+                       actual = latin1_encoding.GetBytes("  \ud83d\ude0a  "); // surrogate pair replacement
+                       Assert.AreEqual (expected, actual, "#4");
+
+                       expected = new byte [] { 0x20, 0x20, 0x3F, 0x3F, 0x20, 0x20 };
+                       actual = latin1_encoding.GetBytes("  \ud834\udd1e  "); // surrogate pair replacement
+                       Assert.AreEqual (expected, actual, "#5");
+
+                       expected = new byte [] { 0x41, 0x42, 0x43, 0x00, 0x41, 0x42, 0x43 };
+                       actual = latin1_encoding.GetBytes("ABC\0ABC"); // embedded zero byte not replaced
+                       Assert.AreEqual (expected, actual, "#6");
+
+                       expected = new byte [] { 0x20, 0x20, 0x3F, 0x20, 0x20 };
+                       actual = latin1_encoding.GetBytes("  \ud834  "); // invalid surrogate pair replacement
+                       Assert.AreEqual (expected, actual, "#7");
+               }
+
+               [Test] // Test GetChars(byte[])
+               public void TestGetChars1 () 
+               {
+                       Encoding latin1_encoding = Encoding.GetEncoding ("latin1");
+                       char[] chars = latin1_encoding.GetChars(testbytes);
+                       for (int i = 0; i < testbytes.Length; i++)
+                               Assert.AreEqual (testbytes[i], (byte) chars[i]);
+               }
+
+               [Test] // Test GetChars(byte[], int, int)
+               public void TestGetChars2 () 
+               {
+                       Encoding latin1_encoding = Encoding.GetEncoding ("latin1");
+                       char[] chars = latin1_encoding.GetChars(testbytes, 1, 1);
+                       Assert.AreEqual (1, chars.Length, "#1");
+                       Assert.AreEqual (testbytes [1], (byte) chars [0], "#2");
+               }
+
+               [Test] // Test GetChars(byte[], int, int, char[], int)
+               public void TestGetChars4 () 
+               {
+                       Encoding latin1_encoding = Encoding.GetEncoding ("latin1");
+                       char[] chars = new char[1];
+                       int cnt = latin1_encoding.GetChars(testbytes, 1, 1, chars, 0);
+                       Assert.AreEqual (1, cnt, "#1");
+                       Assert.AreEqual (testbytes [1], (byte) chars [0], "#2");
+               }
+
+               [Test] // Test GetString(char[])
+               public void TestGetString1 () 
+               {
+                       Encoding latin1_encoding = Encoding.GetEncoding ("latin1");
+                       string str = latin1_encoding.GetString(testbytes);
+                       Assert.AreEqual ("Test", str);
+               }
+
+               [Test] // Test GetString(char[], int, int)
+               public void TestGetString2 () 
+               {
+                       Encoding latin1_encoding = Encoding.GetEncoding ("latin1");
+                       string str = latin1_encoding.GetString(testbytes, 1, 2);
+                       Assert.AreEqual ("es", str);
+               }
+
+               [Test] // Test Decoder
+               public void TestDecoder ()
+               {
+                       Encoding latin1_encoding = Encoding.GetEncoding ("latin1");
+                       char[] chars = new char[1];
+                       int cnt = latin1_encoding.GetDecoder().GetChars(testbytes, 1, 1, chars, 0);
+                       Assert.AreEqual (1, cnt, "#1");
+                       Assert.AreEqual (testbytes [1], (byte) chars [0], "#2");
+               }
+
+               [Test] // Test Decoder
+               public void TestEncoder ()
+               {
+                       Encoding latin1_encoding = Encoding.GetEncoding ("latin1");
+                       byte[] bytes = new Byte[1];
+                       int cnt = latin1_encoding.GetEncoder().GetBytes(testchars, 1, 1, bytes, 0, false);
+                       Assert.AreEqual (1, cnt, "#1");
+                       Assert.AreEqual (testchars [1], (char) bytes [0], "#2");
+               }
+
+               [Test]
+               public void TestZero ()
+               {
+                       Encoding encoding = Encoding.GetEncoding ("latin1");
+                       Assert.AreEqual (string.Empty, encoding.GetString (new byte [0]), "#1");
+                       Assert.AreEqual (string.Empty, encoding.GetString (new byte [0], 0, 0), "#2");
+               }
+
+               [Test]
+               [ExpectedException (typeof (EncoderFallbackException))]
+               public void EncoderFallback ()
+               {
+                       Encoding e = Encoding.GetEncoding ("latin1").Clone () as Encoding;
+                       e.EncoderFallback = new EncoderExceptionFallback ();
+                       e.GetBytes ("\u24c8");
+               }
+
+               [Test]
+       //      [ExpectedException (typeof (ArgumentException))]
+               public void DecoderFallback2 ()
+               {
+                       var bytes = new byte[] {
+                               0x30, 0xa0, 0x31, 0xa8
+                       };
+                       var enc = (Encoding)Encoding.GetEncoding ("latin1").Clone ();
+                       enc.DecoderFallback = new TestFallbackDecoder ();
+                       
+                       var chars = new char [7];
+                       var ret = enc.GetChars (bytes, 0, bytes.Length, chars, 0);
+                       Console.WriteLine (ret);
+                       
+                       for (int i = 0; i < chars.Length; i++) {
+                               Console.Write ("{0:x2} ", (int)chars [i]);
+                       }
+                       Console.WriteLine ();
+               }
+               
+               [Test]
+               public void DecoderFallback3 ()
+               {
+                       var bytes = new byte[] {
+                               0x30, 0xa0, 0x31, 0xa8
+                       };
+                       var enc = (Encoding)Encoding.GetEncoding ("latin1").Clone ();
+                       enc.DecoderFallback = new TestFallbackDecoder ();
+                       
+                       var chars = new char[] { '9', '8', '7', '6', '5' };
+                       var ret = enc.GetChars (bytes, 0, bytes.Length, chars, 0);
+                       
+                       Assert.That (ret, Is.EqualTo (4), "ret");
+                       Assert.That (chars [0], Is.EqualTo ('0'), "chars[0]");
+                       Assert.That (chars [1], Is.EqualTo ((char)0xA0), "chars[1]");
+                       Assert.That (chars [2], Is.EqualTo ('1'), "chars[2]");
+                       Assert.That (chars [3], Is.EqualTo ((char)0xA8), "chars[3]");
+                       Assert.That (chars [4], Is.EqualTo ('5'), "chars[4]");
+               }
+               
+               class TestFallbackDecoder : DecoderFallback {
+                       const int count = 2;
+                       
+                       public override int MaxCharCount {
+                               get { return count; }
+                       }
+                       
+                       public override DecoderFallbackBuffer CreateFallbackBuffer ()
+                       {
+                               return new Buffer ();
+                       }
+                       
+                       class Buffer : DecoderFallbackBuffer {
+                               char[] queue;
+                               int index;
+                               
+                               public override int Remaining {
+                                       get {
+                                               return queue.Length - index;
+                                       }
+                               }
+                               
+                               public override char GetNextChar ()
+                               {
+                                       return index < queue.Length ? queue [index++] : '\0';
+                               }
+                               
+                               public override bool Fallback (byte[] bytes, int unused)
+                               {
+                                       queue = new char[bytes.Length * count];
+                                       index = 0;
+                                       for (int i = 0; i < bytes.Length; i++) {
+                                               for (int j = 0; j < count; j++)
+                                                       queue [index++] = (char)(bytes [i]+j);
+                                       }
+                                       return true;
+                               }
+                               
+                               public override bool MovePrevious ()
+                               {
+                                       throw new NotImplementedException ();
+                               }
+                               
+                               public override void Reset ()
+                               {
+                                       base.Reset ();
+                               }
+                       }
+               }
+
+       }
+}
index e406357204f2a99d07bae57065d386b59cede021..f4e8a9705f78e0beeacafc11313de8475cea8a30 100644 (file)
@@ -1055,24 +1055,21 @@ namespace MonoTests.System.Threading.Tasks
                        var token = source.Token;
                        var evt = new ManualResetEventSlim ();
                        bool result = false;
-                       bool thrown = false;
 
-                       var task = Task.Factory.StartNew (() => evt.Wait (100));
+                       var task = Task.Factory.StartNew (() => { Assert.IsTrue (evt.Wait (2000), "#1"); });
                        var cont = task.ContinueWith (t => result = true, token, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
 
                        source.Cancel();
                        evt.Set ();
-                       task.Wait (100);
+                       Assert.IsTrue (task.Wait (2000), "#2");
                        try {
-                               cont.Wait (100);
-                       } catch (Exception ex) {
-                               thrown = true;
+                               Assert.IsFalse (cont.Wait (4000), "#3");
+                       } catch (AggregateException ex) {
                        }
 
-                       Assert.IsTrue (task.IsCompleted);
-                       Assert.IsTrue (cont.IsCanceled);
-                       Assert.IsFalse (result);
-                       Assert.IsTrue (thrown);
+                       Assert.IsTrue (task.IsCompleted, "#4");
+                       Assert.IsTrue (cont.IsCanceled, "#5");
+                       Assert.IsFalse (result, "#6");
                }
 
                [Test]
index e1d95dc93f00f563a4a7415708b3714d5a107a4f..ba664353ab9e0056492a1ae525057969609af25e 100644 (file)
@@ -1445,6 +1445,18 @@ namespace MonoTests.System
                        var del = Delegate.Remove (del1, del2);
                }
 
+               [Test]
+               [ExpectedException (typeof (ArgumentException))]
+               public void CreateDelegateThrowsAnArgumentExceptionWhenCalledWithAnOpenGeneric()
+               {
+                       var m = GetType().GetMethod("AnyGenericMethod");
+                       Delegate.CreateDelegate(typeof(Action), this, m);
+               }
+
+               public void AnyGenericMethod<T>()
+               {
+               }
+
                static bool Int32D2 (int x, int y)
                {
                        return (x & y) == y; 
index cfd6b74ae03874680cbda5a79f32ae2f9999953c..bfa344cf598ae671dca5b6e25920aebe05be733e 100644 (file)
@@ -405,6 +405,7 @@ System.Text/EncoderTest.cs
 System.Text/EncodingTest.cs
 System.Text/EncodingTester.cs
 System.Text/EncodingInfoTest.cs
+System.Text/Latin1EncodingTest.cs
 System.Text/StringBuilderTest.cs
 System.Text/TestEncoding.cs
 System.Text/UnicodeEncodingTest.cs
index b477f7bb686d3aa8758503ff45f1bce268e22855..d85cf9fb97643751787b80da2b208e0e89641c5c 100644 (file)
@@ -1081,7 +1081,6 @@ namespace System.Threading {
 
             dls.Store.SetData(slot, data);
         }
-#if !MONO
 
         // #threadCultureInfo
         //
@@ -1337,12 +1336,23 @@ namespace System.Threading {
         }
 
 #if! FEATURE_LEAK_CULTURE_INFO
+
+#if MONO
+        static void nativeInitCultureAccessors()
+        {
+            m_CurrentCulture = CultureInfo.ConstructCurrentCulture ();
+            m_CurrentUICulture = CultureInfo.ConstructCurrentUICulture ();
+        }
+#else
         [System.Security.SecurityCritical]  // auto-generated
         [ResourceExposure(ResourceScope.None)]
         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
         [SuppressUnmanagedCodeSecurity]
         private static extern void nativeInitCultureAccessors();
 #endif
+#endif
+
+#if !MONO
 
         /*=============================================================*/
 
index 80481ed2091f6ba2cf1deb7c25e4c5514ce9e529..d27fe806048797af33538b202c262e0e040dff4e 100644 (file)
@@ -1595,6 +1595,15 @@ namespace Mono.CSharp {
                        if (res && errors != ec.Report.Errors)
                                return null;
 
+                       if (block.IsAsync && block.Original.ParametersBlock.HasCapturedThis && ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.block.IsAsync) {
+                               //
+                               // We'll do ldftn to load the fabricated m_X method but
+                               // because we are inside struct the method can be hoisted
+                               // anywhere in the parent scope
+                               //
+                               ec.CurrentBlock.ParametersBlock.HasReferenceToStoreyForInstanceLambdas = true;
+                       }
+
                        return res ? this : null;
                }
 
@@ -1798,6 +1807,8 @@ namespace Mono.CSharp {
                                                        parent = storey = sm;
                                                }
                                        }
+                               } else if (src_block.ParametersBlock.HasReferenceToStoreyForInstanceLambdas) {
+                                       src_block.ParametersBlock.StateMachine.AddParentStoreyReference (ec, storey);
                                }
 
                                modifiers = storey != null ? Modifiers.INTERNAL : Modifiers.PRIVATE;
index d7105592ebb29cdcff8b38039e88696def303f62..7f54b33eeb599c16146c7adfcc0c2e12b3d5beaf 100644 (file)
@@ -2657,6 +2657,7 @@ namespace Mono.CSharp {
                        AwaitBlock = 1 << 13,
                        FinallyBlock = 1 << 14,
                        CatchBlock = 1 << 15,
+                       HasReferenceToStoreyForInstanceLambdas = 1 << 16,
                        Iterator = 1 << 20,
                        NoFlowAnalysis = 1 << 21,
                        InitializationEmitted = 1 << 22
@@ -3281,7 +3282,7 @@ namespace Mono.CSharp {
                                                        break;
                                        }
                                }
-                               
+
                                //
                                // We are the first storey on path and 'this' has to be hoisted
                                //
@@ -3349,7 +3350,7 @@ namespace Mono.CSharp {
 
                                                                //
                                                                // If we are state machine with no parent. We can hook into parent without additional
-                                                               // reference and capture this directly
+                                                               // reference and capture this directly
                                                                //
                                                                ExplicitBlock parent_storey_block = pb;
                                                                while (parent_storey_block.Parent != null) {
@@ -3666,6 +3667,15 @@ namespace Mono.CSharp {
 
                #region Properties
 
+               public bool HasReferenceToStoreyForInstanceLambdas {
+                       get {
+                               return (flags & Flags.HasReferenceToStoreyForInstanceLambdas) != 0;
+                       }
+                       set {
+                               flags = value ? flags | Flags.HasReferenceToStoreyForInstanceLambdas : flags & ~Flags.HasReferenceToStoreyForInstanceLambdas;
+                       }
+               }
+
                public bool IsAsync {
                        get {
                                return (flags & Flags.HasAsyncModifier) != 0;
diff --git a/mcs/tests/test-async-89.cs b/mcs/tests/test-async-89.cs
new file mode 100644 (file)
index 0000000..5a69685
--- /dev/null
@@ -0,0 +1,51 @@
+using System;
+using System.Threading.Tasks;
+
+class X
+{
+       public static void Main ()
+       {
+               new X ().Test ();
+       }
+
+       void Test ()
+       {
+               object v1 = null;
+
+               Action a = () =>
+               {
+                       if (v1 == null)
+                       {
+                               object v2 = null;
+
+                               Action a2 = () =>
+                               {
+                                       Console.WriteLine (v2);
+                               };
+                               
+                               Action a3 = async () =>
+                               {
+                                       // This scope needs to access to Scope which can do ldftn on instance method
+                                       {
+                                       Func<Task> a4 = async () =>
+                                       {
+                                               await Foo ();
+                                       };
+                                       }
+
+                                       await Task.Yield ();
+                               };
+
+                               a3 ();
+                       }
+               };
+
+               a ();
+       }
+
+       async Task Foo ()
+       {
+               await Task.FromResult (1);
+       }
+
+}
\ No newline at end of file
index 270fe53c92fdf6c81740a9b9d4f6d632b8673bd4..cde4e9e70d68ea66bba24d1169045aa8b6be1057 100644 (file)
       </method>
     </type>
   </test>
+  <test name="test-async-89.cs">
+    <type name="X">
+      <method name="Void Main()" attrs="150">
+        <size>12</size>
+      </method>
+      <method name="Void Test()" attrs="129">
+        <size>41</size>
+      </method>
+      <method name="System.Threading.Tasks.Task Foo()" attrs="129">
+        <size>33</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+    <type name="X+&lt;Test&gt;c__AnonStorey1">
+      <method name="Void &lt;&gt;m__0()" attrs="131">
+        <size>67</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+    <type name="X+&lt;Foo&gt;c__async0">
+      <method name="Void MoveNext()" attrs="486">
+        <size>158</size>
+      </method>
+      <method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
+        <size>13</size>
+      </method>
+    </type>
+    <type name="X+&lt;Test&gt;c__AnonStorey1+&lt;Test&gt;c__AnonStorey2">
+      <method name="Void &lt;&gt;m__0()" attrs="131">
+        <size>13</size>
+      </method>
+      <method name="Void &lt;&gt;m__1()" attrs="131">
+        <size>48</size>
+      </method>
+      <method name="System.Threading.Tasks.Task &lt;&gt;m__2()" attrs="131">
+        <size>46</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+    <type name="X+&lt;Test&gt;c__AnonStorey1+&lt;Test&gt;c__AnonStorey2+&lt;Test&gt;c__async3">
+      <method name="Void MoveNext()" attrs="486">
+        <size>179</size>
+      </method>
+      <method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
+        <size>13</size>
+      </method>
+    </type>
+    <type name="X+&lt;Test&gt;c__AnonStorey1+&lt;Test&gt;c__AnonStorey2+&lt;Test&gt;c__async4">
+      <method name="Void MoveNext()" attrs="486">
+        <size>167</size>
+      </method>
+      <method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
+        <size>13</size>
+      </method>
+    </type>
+  </test>
   <test name="test-cls-00.cs">
     <type name="CLSCLass_6">
       <method name="Void add_Disposed(Delegate)" attrs="2182">
index bdc741144ea595cb7d7bcbeb8b509e5a3e225148..3670d2f2eb94c6562db2a34b84eb5653165e4c07 100644 (file)
@@ -13,14 +13,13 @@ using System.Globalization;
 using System.IO;
 using System.Collections;
 using System.Collections.Generic;
-using System.Reflection;
-using System.Reflection.Emit;
 using System.Security.Cryptography;
 using System.Text;
 using System.Configuration.Assemblies;
 
+using IKVM.Reflection;
+using IKVM.Reflection.Emit;
 using Mono.Security.Cryptography;
-using IKR = IKVM.Reflection;
 
 namespace Mono.AssemblyLinker
 {
@@ -49,6 +48,15 @@ namespace Mono.AssemblyLinker
                No
        }
 
+       public enum Platform {
+               AnyCPU,
+               AnyCPU32Preferred,
+               Arm,
+               X86,
+               X64,
+               IA64
+       }
+
        public class AssemblyLinker {
 
                ArrayList inputFiles = new ArrayList ();
@@ -59,24 +67,35 @@ namespace Mono.AssemblyLinker
                string entryPoint;
                string win32IconFile;
                string win32ResFile;
+               string title;
+               string description;
+               string company;
+               string product;
+               string copyright;
+               string trademark;
                string templateFile;
                bool isTemplateFile = false;
                Target target = Target.Dll;
+               Platform platform = Platform.AnyCPU;
                DelaySign delaysign = DelaySign.NotSet;
                string keyfile;
                string keyname;
                string culture;
+               Universe universe;
 
                public static int Main (String[] args) {
                        return new AssemblyLinker ().DynMain (args);
                }
 
                private int DynMain (String[] args) {
-                       ParseArgs (args);
+                       using (universe = new Universe (UniverseOptions.MetadataOnly)) {
+                               universe.LoadFile (typeof (object).Assembly.Location);
+                               ParseArgs (args);
 
-                       DoIt ();
+                               DoIt ();
 
-                       return 0;
+                               return 0;
+                       }
                }
 
                private void ParseArgs (string[] args) 
@@ -211,7 +230,7 @@ namespace Mono.AssemblyLinker
                                        if (realArg.StartsWith ("0x"))
                                                realArg = realArg.Substring (2);
                                        uint val = Convert.ToUInt32 (realArg, 16);
-                                       AddCattr (typeof (AssemblyAlgorithmIdAttribute), typeof (uint), val);
+                                       AddCattr (typeof (System.Reflection.AssemblyAlgorithmIdAttribute), typeof (uint), val);
                                } catch (Exception) {
                                        ReportInvalidArgument (opt, arg);
                                }
@@ -233,21 +252,21 @@ namespace Mono.AssemblyLinker
                        case "company":
                                if (arg == null)
                                        ReportMissingText (opt);
-                               AddCattr (typeof (AssemblyCompanyAttribute), arg);
+                               company = arg;
                                return true;
 
                        case "config":
                        case "configuration":
                                if (arg == null)
                                        ReportMissingText (opt);
-                               AddCattr (typeof (AssemblyConfigurationAttribute), arg);
+                               AddCattr (typeof (System.Reflection.AssemblyConfigurationAttribute), arg);
                                return true;
 
                        case "copy":
                        case "copyright":
                                if (arg == null)
                                        ReportMissingText (opt);
-                               AddCattr (typeof (AssemblyCopyrightAttribute), arg);
+                               copyright = arg;
                                return true;
 
                        case "c":
@@ -273,7 +292,7 @@ namespace Mono.AssemblyLinker
                        case "description":
                                if (arg == null)
                                        ReportMissingText (opt);
-                               AddCattr (typeof (AssemblyDescriptionAttribute), arg);
+                               description = arg;
                                return true;
 
                        case "e":
@@ -292,7 +311,7 @@ namespace Mono.AssemblyLinker
                                if (arg == null)
                                        ReportMissingText (opt);
 
-                               AddCattr (typeof (AssemblyFileVersionAttribute), arg);
+                               AddCattr (typeof (System.Reflection.AssemblyFileVersionAttribute), arg);
                                return true;
 
                        case "flags":
@@ -303,7 +322,7 @@ namespace Mono.AssemblyLinker
                                        if (realArg.StartsWith ("0x"))
                                                realArg = realArg.Substring (2);
                                        uint val = Convert.ToUInt32 (realArg, 16);
-                                       AddCattr (typeof (AssemblyFlagsAttribute), typeof (uint), val);
+                                       AddCattr (typeof (System.Reflection.AssemblyFlagsAttribute), typeof (uint), val);
                                } catch (Exception) {
                                        ReportInvalidArgument (opt, arg);
                                }
@@ -342,18 +361,46 @@ namespace Mono.AssemblyLinker
                                outFile = arg;
                                return true;
 
+               case "platform":
+                       if (arg == null)
+                               ReportMissingText (opt);
+                       switch (arg.ToLowerInvariant ()) {
+                               case "arm":
+                                       platform = Platform.Arm;
+                                       break;
+                               case "anycpu":
+                                       platform = Platform.AnyCPU;
+                                       break;
+                               case "x86":
+                                       platform = Platform.X86;
+                                       break;
+                               case "x64":
+                                       platform = Platform.X64;
+                                       break;
+                               case "itanium":
+                                       platform = Platform.IA64;
+                                       break;
+                               case "anycpu32bitpreferred":
+                                       platform = Platform.AnyCPU32Preferred;
+                                       break;
+                               default:
+                                       ReportInvalidArgument (opt, arg);
+                                       break;
+                               }
+                               return true;
+
                        case "prod":
                        case "product":
                                if (arg == null)
                                        ReportMissingText (opt);
-                               AddCattr (typeof (AssemblyProductAttribute), arg);
+                               product = arg;
                                return true;
 
                        case "productv":
                        case "productversion":
                                if (arg == null)
                                        ReportMissingText (opt);
-                               AddCattr (typeof (AssemblyInformationalVersionAttribute), arg);
+                               AddCattr (typeof (System.Reflection.AssemblyInformationalVersionAttribute), arg);
                                return true;
 
                        case "t":
@@ -388,14 +435,14 @@ namespace Mono.AssemblyLinker
                        case "title":
                                if (arg == null)
                                        ReportMissingText (opt);
-                               AddCattr (typeof (AssemblyTitleAttribute), arg);
+                               title = arg;
                                return true;
 
                        case "trade":
                        case "trademark":
                                if (arg == null)
                                        ReportMissingText (opt);
-                               AddCattr (typeof (AssemblyTrademarkAttribute), arg);
+                               trademark = arg;
                                return true;
 
                        case "v":
@@ -405,7 +452,7 @@ namespace Mono.AssemblyLinker
                                        Version ();
                                        break;
                                }
-                               AddCattr (typeof (AssemblyVersionAttribute), arg);
+                               AddCattr (typeof (System.Reflection.AssemblyVersionAttribute), arg);
                                return true;
 
                        case "win32icon":
@@ -461,11 +508,14 @@ namespace Mono.AssemblyLinker
                        return command.ToLower ();
                }
 
-               private void AddCattr (Type attrType, Type arg, object value) {
-                       cattrs.Add (new CustomAttributeBuilder (attrType.GetConstructor (new Type [] { arg }), new object [] { value }));
+               private void AddCattr (System.Type attrType, System.Type arg, object value) {
+                       var importedAttrType = universe.Import(attrType);
+                       var importedArg = universe.Import(arg);
+
+                       cattrs.Add (new CustomAttributeBuilder (importedAttrType.GetConstructor (new [] { importedArg }), new [] { value }));
                }
 
-               private void AddCattr (Type attrType, object value) {
+               private void AddCattr (System.Type attrType, object value) {
                        AddCattr (attrType, typeof (string), value);
                }
 
@@ -596,12 +646,25 @@ namespace Mono.AssemblyLinker
                        if (isTemplateFile)
                                aname = ReadCustomAttributesFromTemplateFile (templateFile, aname);
 
+                       if (!String.IsNullOrEmpty (title))
+                               AddCattr (typeof (System.Reflection.AssemblyTitleAttribute), title);
+                       if (!String.IsNullOrEmpty (description))
+                               AddCattr (typeof (System.Reflection.AssemblyDescriptionAttribute), description);
+                       if (!String.IsNullOrEmpty (company))
+                               AddCattr (typeof (System.Reflection.AssemblyCompanyAttribute), company);
+                       if (!String.IsNullOrEmpty (product))
+                               AddCattr (typeof (System.Reflection.AssemblyProductAttribute), product);
+                       if (!String.IsNullOrEmpty (copyright))
+                               AddCattr (typeof (System.Reflection.AssemblyCopyrightAttribute), copyright);
+                       if (!String.IsNullOrEmpty (trademark))
+                               AddCattr (typeof (System.Reflection.AssemblyTrademarkAttribute), trademark);
+
                        SetKeyPair (aname);
 
                        if (fileName != outFile)
-                               ab = AppDomain.CurrentDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.Save, Path.GetDirectoryName (outFile));
+                               ab = universe.DefineDynamicAssembly (aname, AssemblyBuilderAccess.Save, Path.GetDirectoryName (outFile));
                        else
-                               ab = AppDomain.CurrentDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.Save);
+                               ab = universe.DefineDynamicAssembly (aname, AssemblyBuilderAccess.Save);
 
                        foreach (CustomAttributeBuilder cb in cattrs)
                                ab.SetCustomAttribute (cb);
@@ -611,10 +674,6 @@ namespace Mono.AssemblyLinker
                         */
 
                        foreach (ModuleInfo mod in inputFiles) {
-                               MethodInfo mi = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
-                               if (mi == null)
-                                       Report (0, "Cannot add modules on this runtime: try the Mono runtime instead.");
-
                                if (mod.target != null) {
                                        File.Copy (mod.fileName, mod.target, true);
                                        mod.fileName = mod.target;
@@ -631,7 +690,7 @@ namespace Mono.AssemblyLinker
                                if (isAssembly)
                                        ReportWarning (1020, "Ignoring included assembly '" + mod.fileName + "'");
                                else
-                                       mi.Invoke (ab, new object [] { mod.fileName });
+                               ab.__AddModule (universe.OpenRawModule(mod.fileName));
                        }
 
                        /*
@@ -645,7 +704,7 @@ namespace Mono.AssemblyLinker
                                MethodInfo mainMethodInfo = null;
 
                                try {
-                                       Type mainType = ab.GetType (mainClass);
+                                       IKVM.Reflection.Type mainType = ab.GetType (mainClass);
                                        if (mainType != null)
                                                mainMethodInfo = mainType.GetMethod (mainMethod);
                                }
@@ -666,10 +725,7 @@ namespace Mono.AssemblyLinker
 
                        if (win32IconFile != null) {
                                try {
-                                       MethodInfo mi = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
-                                       if (mi == null)
-                                               Report (0, "Cannot embed win32 icons on this runtime: try the Mono runtime instead.");
-                                       mi.Invoke (ab, new object [] {  win32IconFile });
+                                       ab.__DefineIconResource (File.ReadAllBytes (win32IconFile));
                                }
                                catch (Exception ex) {
                                        Report (1031, "Error reading icon '" + win32IconFile + "' --" + ex);
@@ -685,6 +741,8 @@ namespace Mono.AssemblyLinker
                                }
                        }
 
+                       ModuleBuilder mainModule = null;
+
                        foreach (ResourceInfo res in resources) {
                                if (res.name == null)
                                        res.name = Path.GetFileName (res.fileName);
@@ -694,11 +752,13 @@ namespace Mono.AssemblyLinker
                                                Report (1046, String.Format ("Resource identifier '{0}' has already been used in this assembly", res.name));
 
                                if (res.isEmbedded) {
-                                       MethodInfo mi = typeof (AssemblyBuilder).GetMethod ("EmbedResourceFile", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
-                                               null, CallingConventions.Any, new Type [] { typeof (string), typeof (string) }, null);
-                                       if (mi == null)
-                                               Report (0, "Cannot embed resources on this runtime: try the Mono runtime instead.");
-                                       mi.Invoke (ab, new object [] { res.name, res.fileName });
+                                       if (mainModule == null) {
+                                               mainModule = ab.DefineDynamicModule (fileName, fileName, false);
+                                       }
+
+                                       Stream stream = new MemoryStream (File.ReadAllBytes (res.fileName));
+
+                                       mainModule.DefineManifestResource (res.name, stream, res.isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public);
                                }
                                else {
                                        if (res.target != null) {
@@ -721,8 +781,36 @@ namespace Mono.AssemblyLinker
                                }
                        }
 
+                       PortableExecutableKinds pekind = PortableExecutableKinds.ILOnly;
+                       ImageFileMachine machine;
+
+                       switch (platform) {
+                       case Platform.X86:
+                               pekind |= PortableExecutableKinds.Required32Bit;
+                               machine = ImageFileMachine.I386;
+                               break;
+                       case Platform.X64:
+                               pekind |= PortableExecutableKinds.PE32Plus;
+                               machine = ImageFileMachine.AMD64;
+                               break;
+                       case Platform.IA64:
+                               machine = ImageFileMachine.IA64;
+                               break;
+                       case Platform.AnyCPU32Preferred:
+                               pekind |= PortableExecutableKinds.Preferred32Bit;
+                               machine = ImageFileMachine.I386;
+                               break;
+                       case Platform.Arm:
+                               machine = ImageFileMachine.ARM;
+                               break;
+                       case Platform.AnyCPU:
+                       default:
+                               machine = ImageFileMachine.I386;
+                               break;
+                       }
+
                        try {
-                               ab.Save (fileName);
+                               ab.Save (fileName, pekind, machine);
                        }
                        catch (Exception ex) {
                                Report (1019, "Metadata failure creating assembly -- " + ex);
@@ -733,17 +821,14 @@ namespace Mono.AssemblyLinker
                {
                        // LAMESPEC: according to MSDN, the template assembly must have a
                        // strong name but this is not enforced
-                       const IKR.UniverseOptions options = IKR.UniverseOptions.MetadataOnly;
-
-                       var universe = new IKR.Universe (options);
                        var asm = universe.LoadFile (templateFile);
 
                        // Create missing assemblies, we don't want to load them!
                        // Code taken from ikdasm
                        var names = new HashSet<string> ();
-                       IKR.AssemblyName[] assembly_refs = asm.ManifestModule.__GetReferencedAssemblies ();
+                       AssemblyName[] assembly_refs = asm.ManifestModule.__GetReferencedAssemblies ();
 
-                       var resolved_assemblies = new IKR.Assembly [assembly_refs.Length];
+                       var resolved_assemblies = new Assembly [assembly_refs.Length];
                        for (int i = 0; i < resolved_assemblies.Length; i++) {
                                string name = assembly_refs [i].Name;
 
@@ -798,6 +883,85 @@ namespace Mono.AssemblyLinker
                                                        keyname = key_name_value;
                                        }
                                        break;
+
+                                       case "System.Reflection.AssemblyTitleAttribute": {
+                                               if (title != null)
+                                                       // ignore if specified on command line
+                                                       continue;
+
+                                               // AssemblyTitleAttribute .ctor(string title)
+                                               string title_value = (string) attr_data.ConstructorArguments [0].Value;
+
+                                               if (!String.IsNullOrEmpty (title_value))
+                                                       title = title_value;
+                                       }
+                                       break;
+
+                                       case "System.Reflection.AssemblyDescriptionAttribute": {
+                                               if (description != null)
+                                                       // ignore if specified on command line
+                                                       continue;
+
+                                               // AssemblyDescriptionAttribute .ctor(string description)
+                                               string description_value = (string) attr_data.ConstructorArguments [0].Value;
+
+                                               if (!String.IsNullOrEmpty (description_value))
+                                                       description = description_value;
+                                       }
+                                       break;
+
+                                       case "System.Reflection.AssemblyProductAttribute": {
+                                               if (product != null)
+                                                       // ignore if specified on command line
+                                                       continue;
+
+                                               // AssemblyProductAttribute .ctor(string product)
+                                               string product_value = (string) attr_data.ConstructorArguments [0].Value;
+
+                                               if (!String.IsNullOrEmpty (product_value))
+                                                       product = product_value;
+                                       }
+                                       break;
+
+                                       case "System.Reflection.AssemblyCompanyAttribute": {
+                                               if (company != null)
+                                                       // ignore if specified on command line
+                                                       continue;
+
+                                               // AssemblyCompanyAttribute .ctor(string company)
+                                               string company_value = (string) attr_data.ConstructorArguments [0].Value;
+
+                                               if (!String.IsNullOrEmpty (company_value))
+                                                       company = company_value;
+
+                                       }
+                                       break;
+
+                                       case "System.Reflection.AssemblyCopyrightAttribute": {
+                                               if (copyright != null)
+                                                       // ignore if specified on command line
+                                                       continue;
+
+                                               // AssemblyCopyrightAttribute .ctor(string copyright)
+                                               string copyright_value = (string) attr_data.ConstructorArguments [0].Value;
+
+                                               if (!String.IsNullOrEmpty (copyright_value))
+                                                       copyright = copyright_value;
+                                       }
+                                       break;
+
+                                       case "System.Reflection.AssemblyTrademarkAttribute": {
+                                               if (trademark != null)
+                                                       // ignore if specified on command line
+                                                       continue;
+
+                                               // AssemblyTrademarkAttribute .ctor(string trademark)
+                                               string trademark_value = (string) attr_data.ConstructorArguments [0].Value;
+
+                                               if (!String.IsNullOrEmpty (trademark_value))
+                                                       trademark = trademark_value;
+                                       }
+                                       break;
                                }
                        }
 
@@ -877,6 +1041,9 @@ namespace Mono.AssemblyLinker
                        "  /main:<method>            Specifies the method name of the entry point",
                        "  /nologo                   Suppress the startup banner and copyright message",
                        "  /out:<filename>           Output file name for the assembly manifest",
+                       "  /platform:<text>          Limit which platforms this code can run on; must be",
+                       "                            one of x86, Itanium, x64, arm, anycpu32bitpreferred,",
+                       "                            or anycpu (the default)",
                        "  /prod[uct]:<text>         Product name",
                        "  /productv[ersion]:<text>  Product version",
                        "  /t[arget]:lib[rary]       Create a library",
index 846e34757b04076f355b7369a47b7ffcf274a34d..d3153d29967deb995f5d80da007197e6f7575475 100644 (file)
@@ -428,7 +428,6 @@ on_gc_notification (GC_EventType event)
        switch (e) {
        case MONO_GC_EVENT_PRE_STOP_WORLD:
                MONO_GC_WORLD_STOP_BEGIN ();
-               mono_thread_info_suspend_lock ();
                break;
 
        case MONO_GC_EVENT_POST_STOP_WORLD:
@@ -441,7 +440,6 @@ on_gc_notification (GC_EventType event)
 
        case MONO_GC_EVENT_POST_START_WORLD:
                MONO_GC_WORLD_RESTART_END (1);
-               mono_thread_info_suspend_unlock ();
                break;
 
        case MONO_GC_EVENT_START:
@@ -481,7 +479,21 @@ on_gc_notification (GC_EventType event)
        }
 
        mono_profiler_gc_event (e, 0);
+
+       switch (e) {
+       case MONO_GC_EVENT_PRE_STOP_WORLD:
+               mono_thread_info_suspend_lock ();
+               mono_profiler_gc_event (MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED, 0);
+               break;
+       case MONO_GC_EVENT_POST_START_WORLD:
+               mono_thread_info_suspend_unlock ();
+               mono_profiler_gc_event (MONO_GC_EVENT_POST_START_WORLD_UNLOCKED, 0);
+               break;
+       default:
+               break;
+       }
 }
+
  
 static void
 on_gc_heap_resize (size_t new_size)
@@ -773,7 +785,7 @@ mono_gc_invoke_finalizers (void)
        return 0;
 }
 
-gboolean
+MonoBoolean
 mono_gc_pending_finalizers (void)
 {
        return GC_should_invoke_finalizers ();
index 0ceac2d500a98698255e82d3f9cff616c21dc88e..54e4115771d8a8d52a48e752fec201f173d2aefd 100644 (file)
@@ -525,6 +525,7 @@ mono_init_internal (const char *filename, const char *exe_filename, const char *
 #endif
 
 #ifndef HOST_WIN32
+       mono_w32handle_init ();
        wapi_init ();
 #endif
 
index b5a19af282f4aa6e588dc7f1f28aef511acd9a7e..cd9408df98bbd073b054eeff706deb64b7a9765f 100644 (file)
@@ -145,10 +145,6 @@ void     mono_gchandle_free_domain  (MonoDomain *domain);
 
 typedef void (*FinalizerThreadCallback) (gpointer user_data);
 
-/* if there are finalizers to run, run them. Returns the number of finalizers run */
-gboolean mono_gc_pending_finalizers (void);
-void     mono_gc_finalize_notify    (void);
-
 void* mono_gc_alloc_pinned_obj (MonoVTable *vtable, size_t size);
 void* mono_gc_alloc_obj (MonoVTable *vtable, size_t size);
 void* mono_gc_alloc_vector (MonoVTable *vtable, size_t size, uintptr_t max_length);
index fab34a56b8bc34ad104d3bfba90792e804c494cb..46eaf5e224af7ad3bd1ac05a365d4415ad0d910b 100644 (file)
@@ -326,8 +326,12 @@ mono_gc_run_finalize (void *obj, void *data)
        if (log_finalizers)
                g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Calling finalizer.", o->vtable->klass->name, o);
 
+       mono_profiler_gc_finalize_object_begin (o);
+
        runtime_invoke (o, NULL, &exc, NULL);
 
+       mono_profiler_gc_finalize_object_end (o);
+
        if (log_finalizers)
                g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Returned from finalizer.", o->vtable->klass->name, o);
 
@@ -914,11 +918,15 @@ finalizer_thread (gpointer unused)
 
                finalize_domain_objects ();
 
+               mono_profiler_gc_finalize_begin ();
+
                /* If finished == TRUE, mono_gc_cleanup has been called (from mono_runtime_cleanup),
                 * before the domain is unloaded.
                 */
                mono_gc_invoke_finalizers ();
 
+               mono_profiler_gc_finalize_end ();
+
                mono_threads_join_threads ();
 
                reference_queue_proccess_all ();
index 8c9eecc2f0379b551fdbdcc79ada4bb3082e7a16..b331969129c56a55224645737b08f9170aabb97f 100644 (file)
@@ -6213,6 +6213,7 @@ ves_icall_System_Delegate_CreateDelegate_internal (MonoReflectionType *type, Mon
        MonoObject *delegate;
        gpointer func;
        MonoMethod *method = info->method;
+       MonoMethodSignature *sig = mono_method_signature(method);
 
        mono_class_init_checked (delegate_class, &error);
        if (mono_error_set_pending_exception (&error))
@@ -6237,6 +6238,13 @@ ves_icall_System_Delegate_CreateDelegate_internal (MonoReflectionType *type, Mon
                }
        }
 
+       if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
+               if (!method->is_inflated) {
+                       mono_set_pending_exception(mono_get_exception_argument("method", " Cannot bind to the target method because its signature differs from that of the delegate type"));
+                       return NULL;
+               }
+       }
+
        delegate = mono_object_new_checked (mono_object_domain (type), delegate_class, &error);
        if (mono_error_set_pending_exception (&error))
                return NULL;
index e94b73d590cfe85fd055d00b341fc8d84198c924..6ffff1a6b7328511743975d2b247935fe7aa9d6d 100644 (file)
@@ -195,7 +195,7 @@ jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointe
 
        while (left < right) {
                int pos = (left + right) / 2;
-               MonoJitInfo *ji = (MonoJitInfo *)get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
+               MonoJitInfo *ji = (MonoJitInfo *)mono_get_hazardous_pointer((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
                gint8 *code_end = (gint8*)ji->code_start + ji->code_size;
 
                if (addr < code_end)
@@ -228,7 +228,7 @@ jit_info_table_find (MonoJitInfoTable *table, MonoThreadHazardPointers *hp, gint
                MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
 
                while (pos < chunk->num_elements) {
-                       ji = (MonoJitInfo *)get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
+                       ji = (MonoJitInfo *)mono_get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
 
                        ++pos;
 
@@ -286,7 +286,7 @@ mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_
           table by a hazard pointer and make sure that the pointer is
           still there after we've made it hazardous, we don't have to
           worry about the writer freeing the table. */
-       table = (MonoJitInfoTable *)get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
+       table = (MonoJitInfoTable *)mono_get_hazardous_pointer ((gpointer volatile*)&domain->jit_info_table, hp, JIT_INFO_TABLE_HAZARD_INDEX);
 
        ji = jit_info_table_find (table, hp, (gint8*)addr);
        if (hp)
@@ -298,7 +298,7 @@ mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_
 
        /* Maybe its an AOT module */
        if (try_aot && mono_get_root_domain () && mono_get_root_domain ()->aot_modules) {
-               table = (MonoJitInfoTable *)get_hazardous_pointer ((gpointer volatile*)&mono_get_root_domain ()->aot_modules, hp, JIT_INFO_TABLE_HAZARD_INDEX);
+               table = (MonoJitInfoTable *)mono_get_hazardous_pointer ((gpointer volatile*)&mono_get_root_domain ()->aot_modules, hp, JIT_INFO_TABLE_HAZARD_INDEX);
                module_ji = jit_info_table_find (table, hp, (gint8*)addr);
                if (module_ji)
                        ji = jit_info_find_in_aot_func (domain, module_ji->d.image, addr);
index e1455148696b130e5e21dffd5c0d4eaa56ad9815..c5c65b66947c8a8f83e1c8dd53f3aee795ddf1a1 100644 (file)
@@ -50,6 +50,8 @@ MONO_API int    mono_gc_get_generation  (MonoObject *object);
 MONO_API int    mono_gc_collection_count (int generation);
 MONO_API int64_t mono_gc_get_used_size   (void);
 MONO_API int64_t mono_gc_get_heap_size   (void);
+MONO_API MonoBoolean mono_gc_pending_finalizers (void);
+MONO_API void     mono_gc_finalize_notify    (void);
 MONO_API int    mono_gc_invoke_finalizers (void);
 /* heap walking is only valid in the pre-stop-world event callback */
 MONO_API int    mono_gc_walk_heap        (int flags, MonoGCReferences callback, void *data);
index 5888b90fca925bdcfd35082990fa52a0fa83fb4d..1bf80e2c867a41e775e7b2ebb3ba1da5794d2f5f 100644 (file)
@@ -75,6 +75,11 @@ void mono_profiler_gc_moves       (void **objects, int num);
 void mono_profiler_gc_handle      (int op, int type, uintptr_t handle, MonoObject *obj);
 void mono_profiler_gc_roots       (int num, void **objects, int *root_types, uintptr_t *extra_info);
 
+void mono_profiler_gc_finalize_begin (void);
+void mono_profiler_gc_finalize_object_begin (MonoObject *obj);
+void mono_profiler_gc_finalize_object_end (MonoObject *obj);
+void mono_profiler_gc_finalize_end (void);
+
 void mono_profiler_code_chunk_new (gpointer chunk, int size);
 void mono_profiler_code_chunk_destroy (gpointer chunk);
 void mono_profiler_code_buffer_new (gpointer buffer, int size, MonoProfilerCodeBufferType type, gconstpointer data);
index 4920694b731f928265424c78bfa730b5238bd7aa..fb4cdeca08b8632bf1f746c8ea5bda5b26a1517a 100644 (file)
@@ -102,6 +102,11 @@ struct _ProfilerDesc {
        MonoProfileGCHandleFunc  gc_handle;
        MonoProfileGCRootFunc    gc_roots;
 
+       MonoProfileGCFinalizeFunc gc_finalize_begin;
+       MonoProfileGCFinalizeObjectFunc gc_finalize_object_begin;
+       MonoProfileGCFinalizeObjectFunc gc_finalize_object_end;
+       MonoProfileGCFinalizeFunc gc_finalize_end;
+
        MonoProfileFunc          runtime_initialized_event;
 
        MonoProfilerCodeChunkNew code_chunk_new;
@@ -925,6 +930,50 @@ mono_profiler_install_gc_roots (MonoProfileGCHandleFunc handle_callback, MonoPro
        prof_list->gc_roots = roots_callback;
 }
 
+void
+mono_profiler_gc_finalize_begin (void)
+{
+       for (ProfilerDesc *prof = prof_list; prof; prof = prof->next)
+               if ((prof->events & MONO_PROFILE_GC_FINALIZATION) && prof->gc_finalize_begin)
+                       prof->gc_finalize_begin (prof->profiler);
+}
+
+void
+mono_profiler_gc_finalize_object_begin (MonoObject *obj)
+{
+       for (ProfilerDesc *prof = prof_list; prof; prof = prof->next)
+               if ((prof->events & MONO_PROFILE_GC_FINALIZATION) && prof->gc_finalize_object_begin)
+                       prof->gc_finalize_object_begin (prof->profiler, obj);
+}
+
+void
+mono_profiler_gc_finalize_object_end (MonoObject *obj)
+{
+       for (ProfilerDesc *prof = prof_list; prof; prof = prof->next)
+               if ((prof->events & MONO_PROFILE_GC_FINALIZATION) && prof->gc_finalize_object_end)
+                       prof->gc_finalize_object_end (prof->profiler, obj);
+}
+
+void
+mono_profiler_gc_finalize_end (void)
+{
+       for (ProfilerDesc *prof = prof_list; prof; prof = prof->next)
+               if ((prof->events & MONO_PROFILE_GC_FINALIZATION) && prof->gc_finalize_end)
+                       prof->gc_finalize_end (prof->profiler);
+}
+
+void
+mono_profiler_install_gc_finalize (MonoProfileGCFinalizeFunc begin, MonoProfileGCFinalizeObjectFunc begin_obj, MonoProfileGCFinalizeObjectFunc end_obj, MonoProfileGCFinalizeFunc end)
+{
+       if (!prof_list)
+               return;
+
+       prof_list->gc_finalize_begin = begin;
+       prof_list->gc_finalize_object_begin = begin_obj;
+       prof_list->gc_finalize_object_begin = end_obj;
+       prof_list->gc_finalize_end = end;
+}
+
 void
 mono_profiler_install_runtime_initialized (MonoProfileFunc runtime_initialized_callback)
 {
index b793548ef8fbd98782f7975b1b08ffd0d0a3634d..84dc1bb83b1bca0dbdf7309649757483a5fbe593 100644 (file)
@@ -31,7 +31,8 @@ typedef enum {
        MONO_PROFILE_IOMAP_EVENTS     = 1 << 18, /* this should likely be removed, too */
        MONO_PROFILE_GC_MOVES         = 1 << 19,
        MONO_PROFILE_GC_ROOTS         = 1 << 20,
-       MONO_PROFILE_CONTEXT_EVENTS   = 1 << 21
+       MONO_PROFILE_CONTEXT_EVENTS   = 1 << 21,
+       MONO_PROFILE_GC_FINALIZATION  = 1 << 22
 } MonoProfileFlags;
 
 typedef enum {
@@ -39,6 +40,7 @@ typedef enum {
        MONO_PROFILE_FAILED
 } MonoProfileResult;
 
+// Keep somewhat in sync with libgc/include/gc.h:enum GC_EventType
 typedef enum {
        MONO_GC_EVENT_START,
        MONO_GC_EVENT_MARK_START,
@@ -46,10 +48,26 @@ typedef enum {
        MONO_GC_EVENT_RECLAIM_START,
        MONO_GC_EVENT_RECLAIM_END,
        MONO_GC_EVENT_END,
+       /*
+        * This is the actual arrival order of the following events:
+        *
+        * MONO_GC_EVENT_PRE_STOP_WORLD
+        * MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED
+        * MONO_GC_EVENT_POST_STOP_WORLD
+        * MONO_GC_EVENT_PRE_START_WORLD
+        * MONO_GC_EVENT_POST_START_WORLD_UNLOCKED
+        * MONO_GC_EVENT_POST_START_WORLD
+        *
+        * The LOCKED and UNLOCKED events guarantee that, by the time they arrive,
+        * the GC and suspend locks will both have been acquired and released,
+        * respectively.
+        */
        MONO_GC_EVENT_PRE_STOP_WORLD,
        MONO_GC_EVENT_POST_STOP_WORLD,
        MONO_GC_EVENT_PRE_START_WORLD,
-       MONO_GC_EVENT_POST_START_WORLD
+       MONO_GC_EVENT_POST_START_WORLD,
+       MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED,
+       MONO_GC_EVENT_POST_START_WORLD_UNLOCKED
 } MonoGCEvent;
 
 /* coverage info */
@@ -150,6 +168,9 @@ typedef void (*MonoProfileGCResizeFunc)   (MonoProfiler *prof, int64_t new_size)
 typedef void (*MonoProfileGCHandleFunc)   (MonoProfiler *prof, int op, int type, uintptr_t handle, MonoObject *obj);
 typedef void (*MonoProfileGCRootFunc)     (MonoProfiler *prof, int num_roots, void **objects, int *root_types, uintptr_t *extra_info);
 
+typedef void (*MonoProfileGCFinalizeFunc)  (MonoProfiler *prof);
+typedef void (*MonoProfileGCFinalizeObjectFunc) (MonoProfiler *prof, MonoObject *obj);
+
 typedef void (*MonoProfileIomapFunc) (MonoProfiler *prof, const char *report, const char *pathname, const char *new_pathname);
 
 typedef mono_bool (*MonoProfileCoverageFilterFunc)   (MonoProfiler *prof, MonoMethod *method);
@@ -197,6 +218,7 @@ MONO_API void mono_profiler_coverage_get  (MonoProfiler *prof, MonoMethod *metho
 MONO_API void mono_profiler_install_gc    (MonoProfileGCFunc callback, MonoProfileGCResizeFunc heap_resize_callback);
 MONO_API void mono_profiler_install_gc_moves    (MonoProfileGCMoveFunc callback);
 MONO_API void mono_profiler_install_gc_roots    (MonoProfileGCHandleFunc handle_callback, MonoProfileGCRootFunc roots_callback);
+MONO_API void mono_profiler_install_gc_finalize (MonoProfileGCFinalizeFunc begin, MonoProfileGCFinalizeObjectFunc begin_obj, MonoProfileGCFinalizeObjectFunc end_obj, MonoProfileGCFinalizeFunc end);
 MONO_API void mono_profiler_install_runtime_initialized (MonoProfileFunc runtime_initialized_callback);
 
 MONO_API void mono_profiler_install_code_chunk_new (MonoProfilerCodeChunkNew callback);
index 0597bdd7882fdd994391eadbe65c84ca58c0c181..09224b2f15be171f37d2107b293af76b76c47d38 100644 (file)
@@ -33,9 +33,16 @@ void sgen_bridge_describe_pointer (GCObject *object);
 gboolean sgen_is_bridge_object (GCObject *obj);
 void sgen_mark_bridge_object (GCObject *obj);
 
+gboolean sgen_bridge_handle_gc_param (const char *opt);
 gboolean sgen_bridge_handle_gc_debug (const char *opt);
 void sgen_bridge_print_gc_debug_usage (void);
 
+typedef struct {
+       char *dump_prefix;
+       gboolean accounting;
+       gboolean scc_precise_merge; // Used by Tarjan
+} SgenBridgeProcessorConfig;
+
 typedef struct {
        void (*reset_data) (void);
        void (*processing_stw_step) (void);
@@ -44,10 +51,9 @@ typedef struct {
        MonoGCBridgeObjectKind (*class_kind) (MonoClass *klass);
        void (*register_finalized_object) (GCObject *object);
        void (*describe_pointer) (GCObject *object);
-       void (*enable_accounting) (void);
 
-       // Optional-- used for debugging
-       void (*set_dump_prefix) (const char *prefix);
+       /* Should be called once, immediately after init */
+       void (*set_config) (const SgenBridgeProcessorConfig *);
 
        /*
         * These are set by processing_build_callback_data().
index 006e68c50121f32e9de1a776a9f164ead82907dd..7ec2d4386dfb5f4934169182128e402931b4f397 100644 (file)
@@ -33,6 +33,8 @@ typedef enum {
 static BridgeProcessorSelection bridge_processor_selection = BRIDGE_PROCESSOR_DEFAULT;
 // Most recently requested callbacks
 static MonoGCBridgeCallbacks pending_bridge_callbacks;
+// Configuration to be passed to bridge processor after init
+static SgenBridgeProcessorConfig bridge_processor_config;
 // Currently-in-use callbacks
 MonoGCBridgeCallbacks bridge_callbacks;
 
@@ -84,6 +86,12 @@ bridge_processor_name (const char *name)
        }
 }
 
+static gboolean
+bridge_processor_started ()
+{
+       return bridge_processor.reset_data != NULL;
+}
+
 // Initialize a single bridge processor
 static void
 init_bridge_processor (SgenBridgeProcessor *processor, BridgeProcessorSelection selection)
@@ -133,9 +141,17 @@ sgen_init_bridge ()
                bridge_callbacks = pending_bridge_callbacks;
 
                // If a bridge was registered but there is no bridge processor yet
-               if (bridge_callbacks.cross_references && !bridge_processor.reset_data)
+               if (bridge_callbacks.cross_references && !bridge_processor_started ()) {
                        init_bridge_processor (&bridge_processor, bridge_processor_selection);
 
+                       if (bridge_processor.set_config)
+                               bridge_processor.set_config (&bridge_processor_config);
+
+                       // Config is no longer needed so free its memory
+                       free (bridge_processor_config.dump_prefix);
+                       bridge_processor_config.dump_prefix = NULL;
+               }
+
                sgen_gc_unlock ();
        }
 }
@@ -147,7 +163,7 @@ sgen_set_bridge_implementation (const char *name)
 
        if (selection == BRIDGE_PROCESSOR_INVALID)
                g_warning ("Invalid value for bridge processor implementation, valid values are: 'new', 'old' and 'tarjan'.");
-       else if (bridge_processor.reset_data)
+       else if (bridge_processor_started ())
                g_warning ("Cannot set bridge processor implementation once bridge has already started");
        else
                bridge_processor_selection = selection;
@@ -480,12 +496,9 @@ sgen_bridge_describe_pointer (GCObject *obj)
 static void
 set_dump_prefix (const char *prefix)
 {
-       if (!bridge_processor.set_dump_prefix) {
-               fprintf (stderr, "Warning: Bridge implementation does not support dumping - ignoring.\n");
-               return;
-       }
-
-       bridge_processor.set_dump_prefix (prefix);
+       if (bridge_processor_config.dump_prefix)
+               free (bridge_processor_config.dump_prefix);
+       bridge_processor_config.dump_prefix = strdup (prefix);
 }
 
 /* Test support code */
@@ -652,22 +665,39 @@ register_test_bridge_callbacks (const char *bridge_class_name)
        mono_gc_register_bridge_callbacks (&callbacks);
 }
 
+gboolean
+sgen_bridge_handle_gc_param (const char *opt)
+{
+       g_assert (!bridge_processor_started ());
+
+       if (!strcmp (opt, "bridge-require-precise-merge")) {
+               bridge_processor_config.scc_precise_merge = TRUE;
+       } else {
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
 gboolean
 sgen_bridge_handle_gc_debug (const char *opt)
 {
+       g_assert (!bridge_processor_started ());
+
        if (g_str_has_prefix (opt, "bridge=")) {
                opt = strchr (opt, '=') + 1;
                register_test_bridge_callbacks (g_strdup (opt));
        } else if (!strcmp (opt, "enable-bridge-accounting")) {
-               bridge_processor.enable_accounting ();
+               bridge_processor_config.accounting = TRUE;
        } else if (g_str_has_prefix (opt, "bridge-dump=")) {
                char *prefix = strchr (opt, '=') + 1;
-               set_dump_prefix (prefix);
+               set_dump_prefix(prefix);
        } else if (g_str_has_prefix (opt, "bridge-compare-to=")) {
                const char *name = strchr (opt, '=') + 1;
                BridgeProcessorSelection selection = bridge_processor_name (name);
 
                if (selection != BRIDGE_PROCESSOR_INVALID) {
+                       // Compare processor doesn't get config
                        init_bridge_processor (&compare_to_bridge_processor, selection);
                } else {
                        g_warning ("Invalid bridge implementation to compare against - ignoring.");
index b11df8a17b5e39d83ef82e05e98ca52c5125cf87..a03b0a81bfd508c93bcc82afa65aa3ff6e4ae3da 100644 (file)
@@ -17,8 +17,8 @@
  * When SGen is done marking, it puts together a list of all dead bridged
  * objects.  This is passed to the bridge processor, which does an analysis to
  * simplify the graph: It replaces strongly-connected components with single
- * nodes, and then removes any nodes corresponding to components which do not
- * contain bridged objects.
+ * nodes, and may remove nodes corresponding to components which do not contain
+ * bridged objects.
  *
  * The output of the SCC analysis is passed to the client's `cross_references()`
  * callback.  This consists of 2 arrays, an array of SCCs (MonoGCBridgeSCC),
@@ -54,7 +54,7 @@
 MONO_BEGIN_DECLS
 
 enum {
-       SGEN_BRIDGE_VERSION = 4
+       SGEN_BRIDGE_VERSION = 5
 };
        
 typedef enum {
index 19265f57ef4bf84d41c97a2542253251a0cf2265..05a0cda0685db40f836eb9ac30cfefc78f0195cd 100644 (file)
@@ -491,7 +491,7 @@ mono_gc_invoke_finalizers (void)
        return sgen_gc_invoke_finalizers ();
 }
 
-gboolean
+MonoBoolean
 mono_gc_pending_finalizers (void)
 {
        return sgen_have_pending_finalizers ();
@@ -2896,7 +2896,7 @@ sgen_client_handle_gc_param (const char *opt)
        } else if (g_str_has_prefix (opt, "toggleref-test")) {
                /* FIXME: This should probably in MONO_GC_DEBUG */
                sgen_register_test_toggleref_callback ();
-       } else {
+       } else if (!sgen_bridge_handle_gc_param (opt)) {
                return FALSE;
        }
        return TRUE;
index 4631c0c5430f2ec946931fee01fee5ae079a6ad7..501ceb76d5b8c5a987d26b28891e01ca701cdb53 100644 (file)
@@ -101,6 +101,8 @@ typedef struct _SCC {
 #endif
 } SCC;
 
+static char *dump_prefix = NULL;
+
 // Maps managed objects to corresponding HashEntry stricts
 static SgenHashTable hash_table = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_HASH_TABLE, INTERNAL_MEM_BRIDGE_HASH_TABLE_ENTRY, sizeof (HashEntry), mono_aligned_addr_hash, NULL);
 
@@ -161,11 +163,16 @@ dyn_array_int_contains (DynIntArray *da, int x)
 #endif
 
 static void
-enable_accounting (void)
+set_config (const SgenBridgeProcessorConfig *config)
 {
-       SgenHashTable table = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_HASH_TABLE, INTERNAL_MEM_BRIDGE_HASH_TABLE_ENTRY, sizeof (HashEntryWithAccounting), mono_aligned_addr_hash, NULL);
-       bridge_accounting_enabled = TRUE;
-       hash_table = table;
+       if (config->accounting) {
+               SgenHashTable table = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_HASH_TABLE, INTERNAL_MEM_BRIDGE_HASH_TABLE_ENTRY, sizeof (HashEntryWithAccounting), mono_aligned_addr_hash, NULL);
+               bridge_accounting_enabled = TRUE;
+               hash_table = table;
+       }
+       if (config->dump_prefix) {
+               dump_prefix = strdup (config->dump_prefix);
+       }
 }
 
 static MonoGCBridgeObjectKind
@@ -604,8 +611,6 @@ reset_flags (SCC *scc)
 }
 #endif
 
-static char *dump_prefix = NULL;
-
 static void
 dump_graph (void)
 {
@@ -657,12 +662,6 @@ dump_graph (void)
        fclose (file);
 }
 
-static void
-set_dump_prefix (const char *prefix)
-{
-       dump_prefix = strdup (prefix);
-}
-
 static int
 compare_hash_entries (const HashEntry *e1, const HashEntry *e2)
 {
@@ -1087,8 +1086,7 @@ sgen_new_bridge_init (SgenBridgeProcessor *collector)
        collector->class_kind = class_kind;
        collector->register_finalized_object = register_finalized_object;
        collector->describe_pointer = describe_pointer;
-       collector->enable_accounting = enable_accounting;
-       collector->set_dump_prefix = set_dump_prefix;
+       collector->set_config = set_config;
 
        bridge_processor = collector;
 }
index d33d5d86815d795db6168cf97b9e0f24b9c3f1ff..346e4b0aeb50a1aff3d8ada64bf8b2042898dd17 100644 (file)
@@ -372,11 +372,13 @@ dyn_array_int_merge_one (DynIntArray *array, int value)
 
 
 static void
-enable_accounting (void)
+set_config (const SgenBridgeProcessorConfig *config)
 {
-       SgenHashTable table = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_HASH_TABLE, INTERNAL_MEM_BRIDGE_HASH_TABLE_ENTRY, sizeof (HashEntryWithAccounting), mono_aligned_addr_hash, NULL);
-       bridge_accounting_enabled = TRUE;
-       hash_table = table;
+       if (config->accounting) {
+               SgenHashTable table = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_HASH_TABLE, INTERNAL_MEM_BRIDGE_HASH_TABLE_ENTRY, sizeof (HashEntryWithAccounting), mono_aligned_addr_hash, NULL);
+               bridge_accounting_enabled = TRUE;
+               hash_table = table;
+       }
 }
 
 static MonoGCBridgeObjectKind
@@ -922,7 +924,7 @@ sgen_old_bridge_init (SgenBridgeProcessor *collector)
        collector->class_kind = class_kind;
        collector->register_finalized_object = register_finalized_object;
        collector->describe_pointer = describe_pointer;
-       collector->enable_accounting = enable_accounting;
+       collector->set_config = set_config;
 
        bridge_processor = collector;
 }
index ea14448ccfbfaeb7b376fbf06abd59135cf6b680..60e5933450fba844a1888577df232f4255102127 100644 (file)
@@ -209,6 +209,8 @@ sgen_client_stop_world (int generation)
 
        acquire_gc_locks ();
 
+       mono_profiler_gc_event (MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED, generation);
+
        /* We start to scan after locks are taking, this ensures we won't be interrupted. */
        sgen_process_togglerefs ();
 
@@ -283,6 +285,8 @@ sgen_client_restart_world (int generation, gint64 *stw_time)
         */
        release_gc_locks ();
 
+       mono_profiler_gc_event (MONO_GC_EVENT_POST_START_WORLD_UNLOCKED, generation);
+
        *stw_time = usec;
 }
 
index 76c5ac64a90d1380e68f88e5e0f1b44f83a7481c..daa983e64ac61ce1a29d534c4f2785d872e5e3ce 100644 (file)
@@ -19,8 +19,6 @@
 
 #include "sgen/sgen-gc.h"
 #include "sgen-bridge-internals.h"
-#include "sgen/sgen-hash-table.h"
-#include "sgen/sgen-qsort.h"
 #include "tabledefs.h"
 #include "utils/mono-logger-internals.h"
 
  *     which colors. The color graph then becomes the reduced SCC graph.
  */
 
-static void
-enable_accounting (void)
-{
-       // bridge_accounting_enabled = TRUE;
-       // hash_table = (SgenHashTable)SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_HASH_TABLE, INTERNAL_MEM_BRIDGE_HASH_TABLE_ENTRY, sizeof (HashEntryWithAccounting), mono_aligned_addr_hash, NULL);
-}
-
 // Is this class bridged or not, and should its dependencies be scanned or not?
 // The result of this callback will be cached for use by is_opaque_object later.
 static MonoGCBridgeObjectKind
@@ -83,6 +74,36 @@ class_kind (MonoClass *klass)
 //enable usage logging
 // #define DUMP_GRAPH 1
 
+/* Used in bridgeless_color_is_heavy:
+ * The idea here is as long as the reference fanin and fanout on a node are both 2 or greater, then
+ * removing that node will result in a net increase in edge count. So the question is which node
+ * removals are counterproductive (i.e., how many edges saved balances out one node added).
+ * The number of edges saved by preserving a node is (fanin*fanout - fanin - fanout).
+ *
+ * With all that in mind:
+ *
+ * - HEAVY_REFS_MIN is the number that *both* fanin and fanout must meet to preserve the node.
+ * - HEAVY_COMBINED_REFS_MIN is the number (fanin*fanout) must meet to preserve the node.
+ *
+ * Note HEAVY_COMBINED_REFS_MIN must be <= 2*INCOMING_COLORS_MAX, or we won't know the true fanin.
+ */
+
+#define HEAVY_REFS_MIN 2
+#define HEAVY_COMBINED_REFS_MIN 60
+
+/* Used in ColorData:
+ * The higher INCOMING_COLORS_BITS is the higher HEAVY_COMBINED_REFS_MIN can be (see above).
+ * However, API_INDEX_BITS + INCOMING_COLORS_BITS must be equal to 31, and if API_INDEX_BITS is too
+ * low then terrible things will happen if too many colors are generated. (The number of colors we
+ * will ever attempt to generate is currently naturally limited by the JNI GREF limit.)
+ */
+
+#define API_INDEX_BITS        26
+#define INCOMING_COLORS_BITS  5
+
+#define API_INDEX_MAX         ((1<<API_INDEX_BITS)-1)
+#define INCOMING_COLORS_MAX   ((1<<INCOMING_COLORS_BITS)-1)
+
 // ScanData state
 enum {
        INITIAL,
@@ -94,13 +115,17 @@ enum {
 /*
 Optimizations:
        We can split this data structure in two, those with bridges and those without
+       (and only bridgeless need to record incoming_colors)
 */
 typedef struct {
-    // Colors (ColorDatas) linked to by objects with this color
+       // Colors (ColorDatas) linked to by objects with this color
        DynPtrArray other_colors;
-    // Bridge objects (GCObjects) held by objects with this color
+       // Bridge objects (GCObjects) held by objects with this color
        DynPtrArray bridges;
-       int api_index    : 31;
+       // Index of this color's MonoGCBridgeSCC in the array passed to the client (or -1 for none)
+       signed api_index         : API_INDEX_BITS;
+       // Count of colors that list this color in their other_colors
+       unsigned incoming_colors : INCOMING_COLORS_BITS;
        unsigned visited : 1;
 } ColorData;
 
@@ -115,7 +140,7 @@ typedef struct _ScanData {
        // Tarjan algorithm index (order visited)
        int index;
        // Tarjan index of lowest-index object known reachable from here
-       int low_index : 27;
+       signed low_index : 27;
 
        // See "ScanData state" enum above
        unsigned state : 2;
@@ -124,7 +149,22 @@ typedef struct _ScanData {
        unsigned obj_state : 2;
 } ScanData;
 
+/* Should color be made visible to client even though it has no bridges?
+ * True if we predict the number of reduced edges to be enough to justify the extra node.
+ */
+static inline gboolean
+bridgeless_color_is_heavy (ColorData *data) {
+       int fanin = data->incoming_colors;
+       int fanout = dyn_array_ptr_size (&data->other_colors);
+       return fanin > HEAVY_REFS_MIN && fanout > HEAVY_REFS_MIN
+               && fanin*fanout >= HEAVY_COMBINED_REFS_MIN;
+}
 
+// Should color be made visible to client?
+static inline gboolean
+color_visible_to_client (ColorData *data) {
+       return dyn_array_ptr_size (&data->bridges) || bridgeless_color_is_heavy (data);
+}
 
 // Stacks of ScanData objects used for tarjan algorithm.
 // The Tarjan algorithm is normally defined recursively; here scan_stack simulates the call stack of a recursive algorithm,
@@ -134,12 +174,21 @@ static DynPtrArray scan_stack, loop_stack;
 // GCObjects on which register_finalized_object has been called
 static DynPtrArray registered_bridges;
 
-// ColorData objects
+// As we traverse the graph, which ColorData objects are accessible from our current position?
 static DynPtrArray color_merge_array;
+// Running hash of the contents of the color_merge_array.
+static unsigned int color_merge_array_hash;
+
+static void color_merge_array_empty ()
+{
+       dyn_array_ptr_empty (&color_merge_array);
+       color_merge_array_hash = 0;
+}
 
 static int ignored_objects;
 static int object_index;
 static int num_colors_with_bridges;
+static int num_sccs;
 static int xref_count;
 
 static size_t setup_time, tarjan_time, scc_setup_time, gather_xref_time, xref_setup_time, cleanup_time;
@@ -161,6 +210,7 @@ static ObjectBucket *root_object_bucket;
 static ObjectBucket *cur_object_bucket;
 static int object_data_count;
 
+// Arenas to allocate ScanData from
 static ObjectBucket*
 new_object_bucket (void)
 {
@@ -213,7 +263,7 @@ free_object_buckets (void)
 //ColorData buckets
 #define NUM_COLOR_ENTRIES ((BUCKET_SIZE - SIZEOF_VOID_P * 2) / sizeof (ColorData))
 
-// Same as ObjectBucket except NUM_COLOR_ENTRIES and NUM_SCAN_ENTRIES differ
+// Arenas for ColorDatas, same as ObjectBucket except items-per-bucket differs
 typedef struct _ColorBucket ColorBucket;
 struct _ColorBucket {
        ColorBucket *next;
@@ -356,11 +406,13 @@ find_or_create_data (GCObject *obj)
 //----------
 typedef struct {
        ColorData *color;
-       int hash;
+       unsigned int hash;
 } HashEntry;
 
 /*
-We tried 2/32, 2/128, 4/32, 4/128, 6/128 and 8/128.
+The merge cache maps an ordered list of ColorDatas [the color_merge_array] to a single ColorData.
+
+About cache bucket tuning: We tried 2/32, 2/128, 4/32, 4/128, 6/128 and 8/128.
 
 The performance cost between 4/128 and 8/128 is so small since cache movement happens completely in the same cacheline,
 making the extra space pretty much free.
@@ -373,17 +425,39 @@ Memory wise, 4/32 takes 512 and 8/128 takes 8k, so it's quite reasonable.
 #define ELEMENTS_PER_BUCKET 8
 #define COLOR_CACHE_SIZE 128
 static HashEntry merge_cache [COLOR_CACHE_SIZE][ELEMENTS_PER_BUCKET];
+static unsigned int hash_perturb;
+
+// If true, disable an optimization where sometimes SCC nodes are merged without a perfect check
+static gboolean scc_precise_merge;
 
-static int
-mix_hash (size_t hash)
+static unsigned int
+mix_hash (uintptr_t source)
 {
-       return (int)(((hash * 215497) >> 16) ^ ((hash * 1823231) + hash));
+       unsigned int hash = source;
+
+       // The full hash determines whether two colors can be merged-- sometimes exclusively.
+       // This value changes every GC, so XORing it in before performing the hash will make the
+       // chance that two different colors will produce the same hash on successive GCs very low.
+       hash = hash ^ hash_perturb;
+
+       // Actual hash
+       hash = (((hash * 215497) >> 16) ^ ((hash * 1823231) + hash));
+
+       // Mix in highest bits on 64-bit systems only
+       if (sizeof (source) > 4)
+               hash = hash ^ (source >> 32);
+
+       return hash;
 }
 
 static void
 reset_cache (void)
 {
        memset (merge_cache, 0, sizeof (merge_cache));
+
+       // When using the precise merge debug option, we do not want the inconsistency caused by hash_perturb.
+       if (!scc_precise_merge)
+               ++hash_perturb;
 }
 
 
@@ -397,6 +471,13 @@ dyn_array_ptr_contains (DynPtrArray *da, void *x)
        return FALSE;
 }
 
+static gboolean
+match_colors_estimate (DynPtrArray *a, DynPtrArray *b)
+{
+       return dyn_array_ptr_size (a) == dyn_array_ptr_size (b);
+}
+
+
 static gboolean
 match_colors (DynPtrArray *a, DynPtrArray *b)
 {
@@ -411,23 +492,36 @@ match_colors (DynPtrArray *a, DynPtrArray *b)
        return TRUE;
 }
 
-static int cache_hits, cache_misses;
+// If scc_precise_merge, "semihits" refers to find_in_cache calls aborted because the merge array was too large.
+// Otherwise "semihits" refers to cache hits where the match was only estimated.
+static int cache_hits, cache_semihits, cache_misses;
 
+// The cache contains only non-bridged colors.
 static ColorData*
 find_in_cache (int *insert_index)
 {
        HashEntry *bucket;
-       int i, hash, size, index;
+       int i, size, index;
 
        size = dyn_array_ptr_size (&color_merge_array);
-       /* Cache checking is very ineficient with a lot of elements*/
-       if (size > 3)
+
+       /* Color equality checking is very expensive with a lot of elements, so when there are many
+        * elements we switch to a cheap comparison method which allows false positives. When false
+        * positives occur the worst that can happen is two items will be inappropriately merged
+        * and memory will be retained longer than it should be. We assume that will correct itself
+        * on the next GC (the hash_perturb mechanism increases the probability of this).
+        *
+        * Because this has *some* potential to create problems, if the user set the debug option
+        * 'enable-tarjan-precise-merge' we bail out early (and never merge SCCs with >3 colors).
+        */
+       gboolean color_merge_array_large = size > 3;
+       if (scc_precise_merge && color_merge_array_large) {
+               ++cache_semihits;
                return NULL;
+       }
 
-       hash = 0;
-       for (i = 0 ; i < size; ++i)
-               hash += mix_hash ((size_t)dyn_array_ptr_get (&color_merge_array, i));
-       if (!hash)
+       unsigned int hash = color_merge_array_hash;
+       if (!hash) // 0 is used to indicate an empty bucket entry
                hash = 1;
 
        index = hash & (COLOR_CACHE_SIZE - 1);
@@ -435,9 +529,17 @@ find_in_cache (int *insert_index)
        for (i = 0; i < ELEMENTS_PER_BUCKET; ++i) {
                if (bucket [i].hash != hash)
                        continue;
-               if (match_colors (&bucket [i].color->other_colors, &color_merge_array)) {
-                       ++cache_hits;
-                       return bucket [i].color;
+
+               if (color_merge_array_large) {
+                       if (match_colors_estimate (&bucket [i].color->other_colors, &color_merge_array)) {
+                               ++cache_semihits;
+                               return bucket [i].color;
+                       }
+               } else {
+                       if (match_colors (&bucket [i].color->other_colors, &color_merge_array)) {
+                               ++cache_hits;
+                               return bucket [i].color;
+                       }
                }
        }
 
@@ -450,14 +552,16 @@ find_in_cache (int *insert_index)
        return NULL;
 }
 
+// A color is needed for an SCC. If the SCC has bridges, the color MUST be newly allocated.
+// If the SCC lacks bridges, the allocator MAY use the cache to merge it with an existing one.
 static ColorData*
-new_color (gboolean force_new)
+new_color (gboolean has_bridges)
 {
-       int i = -1;
+       int cacheSlot = -1;
        ColorData *cd;
        /* XXX Try to find an equal one and return it */
-       if (!force_new) {
-               cd = find_in_cache (&i);
+       if (!has_bridges) {
+               cd = find_in_cache (&cacheSlot);
                if (cd)
                        return cd;
        }
@@ -465,9 +569,16 @@ new_color (gboolean force_new)
        cd = alloc_color_data ();
        cd->api_index = -1;
        dyn_array_ptr_set_all (&cd->other_colors, &color_merge_array);
-       /* if i >= 0, it means we prepared a given slot to receive the new color */
-       if (i >= 0)
-               merge_cache [i][0].color = cd;
+
+       // Inform targets
+       for (int i = 0; i < dyn_array_ptr_size (&color_merge_array); ++i) {
+               ColorData *points_to = (ColorData *)dyn_array_ptr_get (&color_merge_array, i);
+               points_to->incoming_colors = MIN (points_to->incoming_colors + 1, INCOMING_COLORS_MAX);
+       }
+
+       /* if cacheSlot >= 0, it means we prepared a given slot to receive the new color */
+       if (cacheSlot >= 0)
+               merge_cache [cacheSlot][0].color = cd;
 
        return cd;
 }
@@ -587,6 +698,7 @@ compute_low_index (ScanData *data, GCObject *obj)
 
        cd = other->color;
        if (!cd->visited) {
+               color_merge_array_hash += mix_hash ((uintptr_t) other->color);
                dyn_array_ptr_add (&color_merge_array, other->color);
                cd->visited = TRUE;
        }
@@ -608,16 +720,24 @@ compute_low (ScanData *data)
        #include "sgen/sgen-scan-object.h"
 }
 
+// A non-bridged object needs a single color describing the current merge array.
 static ColorData*
 reduce_color (void)
 {
        ColorData *color = NULL;
        int size = dyn_array_ptr_size (&color_merge_array);
 
+       // Merge array is empty-- this SCC points to no bridged colors.
+       // This SCC can be ignored completely.
        if (size == 0)
                color = NULL;
+
+       // Merge array has one item-- this SCC points to a single bridged color.
+       // This SCC can be forwarded to the pointed-to color.
        else if (size == 1) {
                color = (ColorData *)dyn_array_ptr_get (&color_merge_array, 0);
+
+       // This SCC gets to talk to the color allocator.
        } else
                color = new_color (FALSE);
 
@@ -694,7 +814,7 @@ create_scc (ScanData *data)
                g_assert (cd->visited);
                cd->visited = FALSE;
        }
-       dyn_array_ptr_empty (&color_merge_array);
+       color_merge_array_empty ();
        found_bridge = FALSE;
 }
 
@@ -704,7 +824,7 @@ dfs (void)
        g_assert (dyn_array_ptr_size (&scan_stack) == 1);
        g_assert (dyn_array_ptr_size (&loop_stack) == 0);
 
-       dyn_array_ptr_empty (&color_merge_array);
+       color_merge_array_empty ();
 
        while (dyn_array_ptr_size (&scan_stack) > 0) {
                ScanData *data = (ScanData *)dyn_array_ptr_pop (&scan_stack);
@@ -891,7 +1011,7 @@ gather_xrefs (ColorData *color)
                if (src->visited)
                        continue;
                src->visited = TRUE;
-               if (dyn_array_ptr_size (&src->bridges))
+               if (color_visible_to_client (src))
                        dyn_array_ptr_add (&color_merge_array, src);
                else
                        gather_xrefs (src);
@@ -907,7 +1027,7 @@ reset_xrefs (ColorData *color)
                if (!src->visited)
                        continue;
                src->visited = FALSE;
-               if (!dyn_array_ptr_size (&src->bridges))
+               if (!color_visible_to_client (src))
                        reset_xrefs (src);
        }
 }
@@ -915,9 +1035,7 @@ reset_xrefs (ColorData *color)
 static void
 processing_build_callback_data (int generation)
 {
-       int j, api_index;
-       MonoGCBridgeSCC **api_sccs;
-       MonoGCBridgeXRef *api_xrefs;
+       int j;
        gint64 curtime;
        ColorBucket *cur;
 
@@ -936,15 +1054,27 @@ processing_build_callback_data (int generation)
        printf ("number of SCCs %d\n", num_colors_with_bridges);
 #endif
 
+       // Count the number of SCCs visible to the client
+       num_sccs = 0;
+       for (cur = root_color_bucket; cur; cur = cur->next) {
+               ColorData *cd;
+               for (cd = &cur->data [0]; cd < cur->next_data; ++cd) {
+                       if (color_visible_to_client (cd))
+                               num_sccs++;
+               }
+       }
+
        /* This is a straightforward translation from colors to the bridge callback format. */
-       api_sccs = (MonoGCBridgeSCC **)sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC*) * num_colors_with_bridges, INTERNAL_MEM_BRIDGE_DATA, TRUE);
-       api_index = xref_count = 0;
+       MonoGCBridgeSCC **api_sccs = (MonoGCBridgeSCC **)sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC*) * num_sccs, INTERNAL_MEM_BRIDGE_DATA, TRUE);
+       int api_index = 0;
+       xref_count = 0;
 
+       // Convert visible SCCs, along with their bridged object list, to MonoGCBridgeSCCs in the client's SCC list
        for (cur = root_color_bucket; cur; cur = cur->next) {
                ColorData *cd;
                for (cd = &cur->data [0]; cd < cur->next_data; ++cd) {
                        int bridges = dyn_array_ptr_size (&cd->bridges);
-                       if (!bridges)
+                       if (!(bridges || bridgeless_color_is_heavy (cd)))
                                continue;
 
                        api_sccs [api_index] = (MonoGCBridgeSCC *)sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC) + sizeof (MonoObject*) * bridges, INTERNAL_MEM_BRIDGE_DATA, TRUE);
@@ -955,20 +1085,22 @@ processing_build_callback_data (int generation)
 
                        for (j = 0; j < bridges; ++j)
                                api_sccs [api_index]->objs [j] = (MonoObject *)dyn_array_ptr_get (&cd->bridges, j);
+
+                       g_assert(api_index < API_INDEX_MAX);
                        api_index++;
                }
        }
 
        scc_setup_time = step_timer (&curtime);
 
+       // Eliminate non-visible SCCs from the SCC list and redistribute xrefs
        for (cur = root_color_bucket; cur; cur = cur->next) {
                ColorData *cd;
                for (cd = &cur->data [0]; cd < cur->next_data; ++cd) {
-                       int bridges = dyn_array_ptr_size (&cd->bridges);
-                       if (!bridges)
+                       if (!color_visible_to_client (cd))
                                continue;
 
-                       dyn_array_ptr_empty (&color_merge_array);
+                       color_merge_array_empty ();
                        gather_xrefs (cd);
                        reset_xrefs (cd);
                        dyn_array_ptr_set_all (&cd->other_colors, &color_merge_array);
@@ -983,27 +1115,28 @@ processing_build_callback_data (int generation)
        dump_color_table (" after xref pass", TRUE);
 #endif
 
-       api_xrefs = (MonoGCBridgeXRef *)sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeXRef) * xref_count, INTERNAL_MEM_BRIDGE_DATA, TRUE);
-       api_index = 0;
+       // Write out xrefs array
+       MonoGCBridgeXRef *api_xrefs = (MonoGCBridgeXRef *)sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeXRef) * xref_count, INTERNAL_MEM_BRIDGE_DATA, TRUE);
+       int xref_index = 0;
        for (cur = root_color_bucket; cur; cur = cur->next) {
                ColorData *src;
                for (src = &cur->data [0]; src < cur->next_data; ++src) {
-                       int bridges = dyn_array_ptr_size (&src->bridges);
-                       if (!bridges)
+                       if (!color_visible_to_client (src))
                                continue;
 
                        for (j = 0; j < dyn_array_ptr_size (&src->other_colors); ++j) {
                                ColorData *dest = (ColorData *)dyn_array_ptr_get (&src->other_colors, j);
-                               g_assert (dyn_array_ptr_size (&dest->bridges)); /* We flattened the color graph, so this must never happen. */
+                               g_assert (color_visible_to_client (dest)); /* Supposedly we already eliminated all xrefs to non-visible objects. */
+
+                               api_xrefs [xref_index].src_scc_index = src->api_index;
+                               api_xrefs [xref_index].dst_scc_index = dest->api_index;
 
-                               api_xrefs [api_index].src_scc_index = src->api_index;
-                               api_xrefs [api_index].dst_scc_index = dest->api_index;
-                               ++api_index;
+                               ++xref_index;
                        }
                }
        }
 
-       g_assert (xref_count == api_index);
+       g_assert (xref_count == xref_index);
        xref_setup_time = step_timer (&curtime);
 
 #if defined (DUMP_GRAPH)
@@ -1013,7 +1146,7 @@ processing_build_callback_data (int generation)
 #endif
 
        //FIXME move half of the cleanup to before the bridge callback?
-       bridge_processor->num_sccs = num_colors_with_bridges;
+       bridge_processor->num_sccs = num_sccs;
        bridge_processor->api_sccs = api_sccs;
        bridge_processor->num_xrefs = xref_count;
        bridge_processor->api_xrefs = api_xrefs;
@@ -1026,7 +1159,7 @@ processing_after_callback (int generation)
        int bridge_count = dyn_array_ptr_size (&registered_bridges);
        int object_count = object_data_count;
        int color_count = color_data_count;
-       int scc_count = num_colors_with_bridges;
+       int colors_with_bridges_count = num_colors_with_bridges;
 
        SGEN_TV_GETTIME (curtime);
 
@@ -1035,10 +1168,10 @@ processing_after_callback (int generation)
 
        cleanup_time = step_timer (&curtime);
 
-       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "GC_TAR_BRIDGE bridges %d objects %d colors %d ignored %d sccs %d xref %d cache %d/%d setup %.2fms tarjan %.2fms scc-setup %.2fms gather-xref %.2fms xref-setup %.2fms cleanup %.2fms",
-               bridge_count, object_count, color_count,
-               ignored_objects, scc_count, xref_count,
-               cache_hits, cache_misses,
+       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "GC_TAR_BRIDGE bridges %d objects %d opaque %d colors %d colors-bridged %d colors-visible %d xref %d cache-hit %d cache-%s %d cache-miss %d setup %.2fms tarjan %.2fms scc-setup %.2fms gather-xref %.2fms xref-setup %.2fms cleanup %.2fms",
+               bridge_count, object_count, ignored_objects,
+               color_count, colors_with_bridges_count, num_sccs, xref_count,
+               cache_hits, (scc_precise_merge ? "abstain" : "semihit"), cache_semihits, cache_misses,
                setup_time / 10000.0f,
                tarjan_time / 10000.0f,
                scc_setup_time / 10000.0f,
@@ -1046,7 +1179,7 @@ processing_after_callback (int generation)
                xref_setup_time / 10000.0f,
                cleanup_time / 10000.0f);
 
-       cache_hits = cache_misses = 0;
+       cache_hits = cache_semihits = cache_misses = 0;
        ignored_objects = 0;
 }
 
@@ -1072,6 +1205,15 @@ describe_pointer (GCObject *obj)
        // printf ("  is visited: %d\n", (int)entry->is_visited);
 }
 
+static void
+set_config (const SgenBridgeProcessorConfig *config)
+{
+       if (config->scc_precise_merge) {
+               hash_perturb = 0;
+               scc_precise_merge = TRUE;
+       }
+}
+
 void
 sgen_tarjan_bridge_init (SgenBridgeProcessor *collector)
 {
@@ -1082,12 +1224,12 @@ sgen_tarjan_bridge_init (SgenBridgeProcessor *collector)
        collector->class_kind = class_kind;
        collector->register_finalized_object = register_finalized_object;
        collector->describe_pointer = describe_pointer;
-       collector->enable_accounting = enable_accounting;
-       // collector->set_dump_prefix = set_dump_prefix;
+       collector->set_config = set_config;
 
        sgen_register_fixed_internal_mem_type (INTERNAL_MEM_TARJAN_OBJ_BUCKET, BUCKET_SIZE);
        g_assert (sizeof (ObjectBucket) <= BUCKET_SIZE);
        g_assert (sizeof (ColorBucket) <= BUCKET_SIZE);
+       g_assert (API_INDEX_BITS + INCOMING_COLORS_BITS <= 31);
        bridge_processor = collector;
 }
 
index 6870f431e8b802c73647b150c39fdee3a1083416..43dd5a430bcc4082614c473c1cbe4cb2fe25338e 100644 (file)
@@ -5056,17 +5056,16 @@ mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread
 void
 mono_thread_internal_unhandled_exception (MonoObject* exc)
 {
-       if (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
-               MonoClass *klass = exc->vtable->klass;
-               if (is_threadabort_exception (klass)) {
-                       mono_thread_internal_reset_abort (mono_thread_internal_current ());
-               } else if (!is_appdomainunloaded_exception (klass)) {
-                       mono_unhandled_exception (exc);
-                       if (mono_environment_exitcode_get () == 1) {
-                               mono_environment_exitcode_set (255);
-                               mono_invoke_unhandled_exception_hook (exc);
-                               g_assert_not_reached ();
-                       }
+       MonoClass *klass = exc->vtable->klass;
+       if (is_threadabort_exception (klass)) {
+               mono_thread_internal_reset_abort (mono_thread_internal_current ());
+       } else if (!is_appdomainunloaded_exception (klass)
+               && mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
+               mono_unhandled_exception (exc);
+               if (mono_environment_exitcode_get () == 1) {
+                       mono_environment_exitcode_set (255);
+                       mono_invoke_unhandled_exception_hook (exc);
+                       g_assert_not_reached ();
                }
        }
 }
index dba952c9ff1763d8926082130c5f10e4827e0a0e..33189c06e10e24d7e95b6d9683a60dbcf91362b1 100644 (file)
@@ -9964,7 +9964,7 @@ compile_asm (MonoAotCompile *acfg)
                wrap_path (g_strdup_printf ("%s.o", acfg->tmpfname)), ld_flags);
 #else
        // Default (linux)
-       char *args = g_strdup_printf ("%s %s -shared -o %s %s %s %s", tool_prefix, LD_OPTIONS,
+       char *args = g_strdup_printf ("%s -shared -o %s %s %s %s", LD_OPTIONS,
                wrap_path (tmp_outfile_name), wrap_path (llvm_ofile),
                wrap_path (g_strdup_printf ("%s.o", acfg->tmpfname)), ld_flags);
 
index ed3bee869a155630c8b1f6256d273db39a8487ff..22f063c59640e9253d58be382839db3c838575e7 100644 (file)
@@ -9833,16 +9833,17 @@ debugger_thread (void *arg)
        thread->internal_thread->state |= ThreadState_Background;
        thread->internal_thread->flags |= MONO_THREAD_FLAG_DONT_MANAGE;
 
-       mono_set_is_debugger_attached (TRUE);
-       
        if (agent_config.defer) {
                if (!wait_for_attach ()) {
                        DEBUG_PRINTF (1, "[dbg] Can't attach, aborting debugger thread.\n");
                        attach_failed = TRUE; // Don't abort process when we can't listen
                } else {
+                       mono_set_is_debugger_attached (TRUE);
                        /* Send start event to client */
                        process_profiler_event (EVENT_KIND_VM_START, mono_thread_get_main ());
                }
+       } else {
+               mono_set_is_debugger_attached (TRUE);
        }
        
        while (!attach_failed) {
index 5a662802771d12efd3ba67f4087f63585654f876..f9a0d5adc8bdfa90c778cbc613c58ecf6d0f4fc0 100644 (file)
@@ -33,7 +33,7 @@
 #include <mono/utils/mono-mmap.h>
 #include <mono/utils/mono-memory-model.h>
 #include <mono/utils/mono-tls.h>
-#include <mono/utils/mono-hwcap-x86.h>
+#include <mono/utils/mono-hwcap.h>
 #include <mono/utils/mono-threads.h>
 
 #include "trace.h"
index 6983398027a5b2bb2e37143c455dceb3db0635cc..7b2e1fa7b48e2438c7e85deeb87108be375a6936 100644 (file)
@@ -18,7 +18,7 @@
 #include <mono/metadata/profiler-private.h>
 #include <mono/metadata/debug-helpers.h>
 #include <mono/utils/mono-mmap.h>
-#include <mono/utils/mono-hwcap-arm.h>
+#include <mono/utils/mono-hwcap.h>
 #include <mono/utils/mono-memory-model.h>
 #include <mono/utils/mono-threads-coop.h>
 
index d88a6c99a8f362bb690424ace4462d58f3d913d9..357e260799833ed8d4a1bf415c148853bf610e39 100644 (file)
@@ -21,7 +21,7 @@
 #include <mono/metadata/threads.h>
 #include <mono/metadata/profiler-private.h>
 #include <mono/utils/mono-math.h>
-#include <mono/utils/mono-hwcap-ia64.h>
+#include <mono/utils/mono-hwcap.h>
 
 #include "trace.h"
 #include "mini-ia64.h"
index d2ae0a74c372d5d486ade5b7f780bb903374dd4b..3ca1bca04c16a83087b5b01bf5c6eba63f020576 100644 (file)
@@ -5375,6 +5375,17 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        values [ins->dreg] = LLVMBuildSelect (builder, v, lhs, rhs, dname);
                        break;
                }
+
+/*
+ * See the ARM64 comment in mono/utils/atomic.h for an explanation of why this
+ * hack is necessary (for now).
+ */
+#ifdef TARGET_ARM64
+#define ARM64_ATOMIC_FENCE_FIX mono_llvm_build_fence (builder, LLVM_BARRIER_SEQ)
+#else
+#define ARM64_ATOMIC_FENCE_FIX
+#endif
+
                case OP_ATOMIC_EXCHANGE_I4:
                case OP_ATOMIC_EXCHANGE_I8: {
                        LLVMValueRef args [2];
@@ -5390,7 +5401,9 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        args [0] = convert (ctx, lhs, LLVMPointerType (t, 0));
                        args [1] = convert (ctx, rhs, t);
 
+                       ARM64_ATOMIC_FENCE_FIX;
                        values [ins->dreg] = mono_llvm_build_atomic_rmw (builder, LLVM_ATOMICRMW_OP_XCHG, args [0], args [1]);
+                       ARM64_ATOMIC_FENCE_FIX;
                        break;
                }
                case OP_ATOMIC_ADD_I4:
@@ -5407,7 +5420,9 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
 
                        args [0] = convert (ctx, lhs, LLVMPointerType (t, 0));
                        args [1] = convert (ctx, rhs, t);
+                       ARM64_ATOMIC_FENCE_FIX;
                        values [ins->dreg] = LLVMBuildAdd (builder, mono_llvm_build_atomic_rmw (builder, LLVM_ATOMICRMW_OP_ADD, args [0], args [1]), args [1], dname);
+                       ARM64_ATOMIC_FENCE_FIX;
                        break;
                }
                case OP_ATOMIC_CAS_I4:
@@ -5425,7 +5440,9 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        args [1] = convert (ctx, values [ins->sreg3], t);
                        /* new value */
                        args [2] = convert (ctx, values [ins->sreg2], t);
+                       ARM64_ATOMIC_FENCE_FIX;
                        val = mono_llvm_build_cmpxchg (builder, args [0], args [1], args [2]);
+                       ARM64_ATOMIC_FENCE_FIX;
                        /* cmpxchg returns a pair */
                        values [ins->dreg] = LLVMBuildExtractValue (builder, val, 0, "");
                        break;
@@ -5466,7 +5483,9 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
 
                        addr = convert (ctx, addr, LLVMPointerType (t, 0));
 
+                       ARM64_ATOMIC_FENCE_FIX;
                        values [ins->dreg] = emit_load_general (ctx, bb, &builder, size, addr, lhs, dname, is_volatile, barrier);
+                       ARM64_ATOMIC_FENCE_FIX;
 
                        if (sext)
                                values [ins->dreg] = LLVMBuildSExt (builder, values [ins->dreg], LLVMInt32Type (), dname);
@@ -5514,7 +5533,9 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        addr = LLVMBuildGEP (builder, convert (ctx, base, LLVMPointerType (t, 0)), &index, 1, "");
                        value = convert (ctx, values [ins->sreg1], t);
 
+                       ARM64_ATOMIC_FENCE_FIX;
                        emit_store_general (ctx, bb, &builder, size, value, addr, base, is_volatile, barrier);
+                       ARM64_ATOMIC_FENCE_FIX;
                        break;
                }
                case OP_RELAXED_NOP: {
index 5d6ebc7b6bc126975df54bdc38c29d247d5ca8d0..783896f15681743acb6001dad302705db271bee9 100644 (file)
@@ -19,7 +19,7 @@
 #include <mono/metadata/appdomain.h>
 #include <mono/metadata/debug-helpers.h>
 #include <mono/utils/mono-mmap.h>
-#include <mono/utils/mono-hwcap-mips.h>
+#include <mono/utils/mono-hwcap.h>
 
 #include <mono/arch/mips/mips-codegen.h>
 
index 3089a8546b1d3a4d605535a775c1f57d27eb793f..7d2c0d8b8cfda73cacd3b6847b37f7c5dd523da4 100644 (file)
@@ -17,7 +17,7 @@
 #include <mono/metadata/debug-helpers.h>
 #include <mono/utils/mono-proclib.h>
 #include <mono/utils/mono-mmap.h>
-#include <mono/utils/mono-hwcap-ppc.h>
+#include <mono/utils/mono-hwcap.h>
 
 #include "mini-ppc.h"
 #ifdef TARGET_POWERPC64
index 3fe40d2cfc28fdd8a055b003ad58785d5cbd3427..a1094afa173fbe0baeb75c2ff221e0e9b73ae7e9 100644 (file)
@@ -268,7 +268,7 @@ if (ins->inst_target_bb->native_offset) {                                   \
 #include <mono/utils/mono-error-internals.h>
 #include <mono/utils/mono-math.h>
 #include <mono/utils/mono-mmap.h>
-#include <mono/utils/mono-hwcap-s390x.h>
+#include <mono/utils/mono-hwcap.h>
 #include <mono/utils/mono-threads.h>
 
 #include "mini-s390x.h"
@@ -399,8 +399,6 @@ pthread_key_t lmf_addr_key;
 
 gboolean lmf_addr_key_inited = FALSE; 
 
-facilityList_t facs;
-
 /*
  * The code generated for sequence points reads from this location, 
  * which is made read-only when single stepping is enabled.
@@ -4370,7 +4368,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                }
                        break;
                case OP_ICONV_TO_R_UN: {
-                       if (facs.fpe) {
+                       if (mono_hwcap_s390x_has_fpe) {
                                s390_cdlfbr (code, ins->dreg, 5, ins->sreg1, 0);
                        } else {
                                s390_llgfr (code, s390_r0, ins->sreg1);
@@ -4379,7 +4377,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                }
                        break;
                case OP_LCONV_TO_R_UN: {
-                       if (facs.fpe) {
+                       if (mono_hwcap_s390x_has_fpe) {
                                s390_cdlgbr (code, ins->dreg, 5, ins->sreg1, 0);
                        } else {
                                short int *jump;
@@ -4416,7 +4414,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        s390_ngr   (code, ins->dreg, s390_r0);
                        break;
                case OP_FCONV_TO_U1:
-                       if (facs.fpe) {
+                       if (mono_hwcap_s390x_has_fpe) {
                                s390_clgdbr (code, ins->dreg, 5, ins->sreg1, 0);
                                s390_lghi  (code, s390_r0, 0xff);
                                s390_ngr   (code, ins->dreg, s390_r0);
@@ -4433,7 +4431,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        s390_ngr   (code, ins->dreg, s390_r0);
                        break;
                case OP_FCONV_TO_U2:
-                       if (facs.fpe) {
+                       if (mono_hwcap_s390x_has_fpe) {
                                s390_clgdbr (code, ins->dreg, 5, ins->sreg1, 0);
                                s390_llill  (code, s390_r0, 0xffff);
                                s390_ngr    (code, ins->dreg, s390_r0);
@@ -4447,7 +4445,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        break;
                case OP_FCONV_TO_U4:
                case OP_FCONV_TO_U:
-                       if (facs.fpe) {
+                       if (mono_hwcap_s390x_has_fpe) {
                                s390_clfdbr (code, ins->dreg, 5, ins->sreg1, 0);
                        } else {
                                code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
@@ -4457,7 +4455,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        s390_cgdbr (code, ins->dreg, 5, ins->sreg1);
                        break;
                case OP_FCONV_TO_U8:
-                       if (facs.fpe) {
+                       if (mono_hwcap_s390x_has_fpe) {
                                s390_clgdbr (code, ins->dreg, 5, ins->sreg1, 0);
                        } else {
                                code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
@@ -7077,7 +7075,7 @@ mono_arch_cpu_enumerate_simd_versions (void)
 {
        guint32 sseOpts = 0;
 
-       if (facs.vec != 0) 
+       if (mono_hwcap_s390x_has_vec)
                sseOpts = (SIMD_VERSION_SSE1  | SIMD_VERSION_SSE2 |
                           SIMD_VERSION_SSE3  | SIMD_VERSION_SSSE3 |
                           SIMD_VERSION_SSE41 | SIMD_VERSION_SSE42 |
index 022f8a5e790b8ea9334d4fa61bb7f92c99229c9f..5003bfe025403fa2d02c9709b18d04fa2e26b491 100644 (file)
@@ -28,7 +28,7 @@
 #include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/tokentype.h>
 #include <mono/utils/mono-math.h>
-#include <mono/utils/mono-hwcap-sparc.h>
+#include <mono/utils/mono-hwcap.h>
 
 #include "mini-sparc.h"
 #include "trace.h"
index 9e1702be17c8e32286f5233e2423a4740d2b59ec..288af652434bf9ffc25e4ad0893d5087409de286 100644 (file)
@@ -29,7 +29,7 @@
 #include <mono/utils/mono-counters.h>
 #include <mono/utils/mono-mmap.h>
 #include <mono/utils/mono-memory-model.h>
-#include <mono/utils/mono-hwcap-x86.h>
+#include <mono/utils/mono-hwcap.h>
 #include <mono/utils/mono-threads.h>
 
 #include "trace.h"
index e8d53afea686ed76588370c99fe74beac2c0718b..355e4c95388770496902b501920f4d9b0fd8e959 100644 (file)
@@ -1862,9 +1862,23 @@ gc_event_name (int ev)
        case MONO_GC_EVENT_RECLAIM_END: return "reclaim end";
        case MONO_GC_EVENT_END: return "end";
        case MONO_GC_EVENT_PRE_STOP_WORLD: return "pre stop";
+       case MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED: return "pre stop lock";
        case MONO_GC_EVENT_POST_STOP_WORLD: return "post stop";
        case MONO_GC_EVENT_PRE_START_WORLD: return "pre start";
        case MONO_GC_EVENT_POST_START_WORLD: return "post start";
+       case MONO_GC_EVENT_POST_START_WORLD_UNLOCKED: return "post start unlock";
+       default:
+               return "unknown";
+       }
+}
+
+static const char*
+sync_point_name (int type)
+{
+       switch (type) {
+       case SYNC_POINT_PERIODIC: return "periodic";
+       case SYNC_POINT_WORLD_STOP: return "world stop";
+       case SYNC_POINT_WORLD_START: return "world start";
        default:
                return "unknown";
        }
@@ -1956,21 +1970,25 @@ get_root_name (int rtype)
 }
 
 static MethodDesc**
-decode_bt (MethodDesc** sframes, int *size, unsigned char *p, unsigned char **endp, intptr_t ptr_base)
+decode_bt (ProfContext *ctx, MethodDesc** sframes, int *size, unsigned char *p, unsigned char **endp, intptr_t ptr_base, intptr_t *method_base)
 {
        MethodDesc **frames;
        int i;
-       int flags = decode_uleb128 (p, &p);
+       if (ctx->data_version < 13)
+               decode_uleb128 (p, &p); /* flags */
        int count = decode_uleb128 (p, &p);
-       if (flags != 0)
-               return NULL;
        if (count > *size)
                frames = (MethodDesc **)malloc (count * sizeof (void*));
        else
                frames = sframes;
        for (i = 0; i < count; ++i) {
                intptr_t ptrdiff = decode_sleb128 (p, &p);
-               frames [i] = lookup_method (ptr_base + ptrdiff);
+               if (ctx->data_version > 12) {
+                       *method_base += ptrdiff;
+                       frames [i] = lookup_method (*method_base);
+               } else {
+                       frames [i] = lookup_method (ptr_base + ptrdiff);
+               }
        }
        *size = count;
        *endp = p;
@@ -2279,8 +2297,16 @@ decode_buffer (ProfContext *ctx)
                                if (new_size > max_heap_size)
                                        max_heap_size = new_size;
                        } else if (subtype == TYPE_GC_EVENT) {
-                               uint64_t ev = decode_uleb128 (p, &p);
-                               int gen = decode_uleb128 (p, &p);
+                               uint64_t ev;
+                               if (ctx->data_version > 12)
+                                       ev = *p++;
+                               else
+                                       ev = decode_uleb128 (p, &p);
+                               int gen;
+                               if (ctx->data_version > 12)
+                                       gen = *p++;
+                               else
+                                       gen = decode_uleb128 (p, &p);
                                if (debug)
                                        fprintf (outfile, "gc event for gen%d: %s at %llu (thread: 0x%zx)\n", gen, gc_event_name (ev), (unsigned long long) time_base, thread->thread_id);
                                if (gen > 2) {
@@ -2318,7 +2344,7 @@ decode_buffer (ProfContext *ctx)
                                intptr_t objdiff = decode_sleb128 (p, &p);
                                if (has_bt) {
                                        num_bt = 8;
-                                       frames = decode_bt (sframes, &num_bt, p, &p, ptr_base);
+                                       frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
                                        if (!frames) {
                                                fprintf (outfile, "Cannot load backtrace\n");
                                                return 0;
@@ -2352,7 +2378,7 @@ decode_buffer (ProfContext *ctx)
                                uint32_t handle = decode_uleb128 (p, &p);
                                if (has_bt) {
                                        num_bt = 8;
-                                       frames = decode_bt (sframes, &num_bt, p, &p, ptr_base);
+                                       frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
                                        if (!frames) {
                                                fprintf (outfile, "Cannot load backtrace\n");
                                                return 0;
@@ -2374,6 +2400,21 @@ decode_buffer (ProfContext *ctx)
                                        fprintf (outfile, "handle (%s) %u destroyed\n", get_handle_name (htype), handle);
                                if (frames != sframes)
                                        free (frames);
+                       } else if (subtype == TYPE_GC_FINALIZE_START) {
+                               // TODO: Generate a finalizer report based on these events.
+                               if (debug)
+                                       fprintf (outfile, "gc finalizer queue being processed at %llu\n", (unsigned long long) time_base);
+                       } else if (subtype == TYPE_GC_FINALIZE_END) {
+                               if (debug)
+                                       fprintf (outfile, "gc finalizer queue finished processing at %llu\n", (unsigned long long) time_base);
+                       } else if (subtype == TYPE_GC_FINALIZE_OBJECT_START) {
+                               intptr_t objdiff = decode_sleb128 (p, &p);
+                               if (debug)
+                                       fprintf (outfile, "gc finalizing object %p at %llu\n", (void *) OBJ_ADDR (objdiff), (unsigned long long) time_base);
+                       } else if (subtype == TYPE_GC_FINALIZE_OBJECT_END) {
+                               intptr_t objdiff = decode_sleb128 (p, &p);
+                               if (debug)
+                                       fprintf (outfile, "gc finalized object %p at %llu\n", (void *) OBJ_ADDR (objdiff), (unsigned long long) time_base);
                        }
                        break;
                }
@@ -2387,11 +2428,8 @@ decode_buffer (ProfContext *ctx)
                        time_base += tdiff;
                        if (mtype == TYPE_CLASS) {
                                intptr_t imptrdiff = decode_sleb128 (p, &p);
-                               uint64_t flags = decode_uleb128 (p, &p);
-                               if (flags) {
-                                       fprintf (outfile, "non-zero flags in class\n");
-                                       return 0;
-                               }
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
                                if (debug)
                                        fprintf (outfile, "%s class %p (%s in %p) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), p, (void*)(ptr_base + imptrdiff), (unsigned long long) time_base);
                                if (subtype == TYPE_END_LOAD)
@@ -2399,11 +2437,8 @@ decode_buffer (ProfContext *ctx)
                                while (*p) p++;
                                p++;
                        } else if (mtype == TYPE_IMAGE) {
-                               uint64_t flags = decode_uleb128 (p, &p);
-                               if (flags) {
-                                       fprintf (outfile, "non-zero flags in image\n");
-                                       return 0;
-                               }
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
                                if (debug)
                                        fprintf (outfile, "%s image %p (%s) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), p, (unsigned long long) time_base);
                                if (subtype == TYPE_END_LOAD)
@@ -2411,11 +2446,8 @@ decode_buffer (ProfContext *ctx)
                                while (*p) p++;
                                p++;
                        } else if (mtype == TYPE_ASSEMBLY) {
-                               uint64_t flags = decode_uleb128 (p, &p);
-                               if (flags) {
-                                       fprintf (outfile, "non-zero flags in assembly\n");
-                                       return 0;
-                               }
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
                                if (debug)
                                        fprintf (outfile, "%s assembly %p (%s) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), p, (unsigned long long) time_base);
                                if (subtype == TYPE_END_LOAD)
@@ -2423,11 +2455,8 @@ decode_buffer (ProfContext *ctx)
                                while (*p) p++;
                                p++;
                        } else if (mtype == TYPE_DOMAIN) {
-                               uint64_t flags = decode_uleb128 (p, &p);
-                               if (flags) {
-                                       fprintf (outfile, "non-zero flags in domain\n");
-                                       return 0;
-                               }
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
                                DomainContext *nd = get_domain (ctx, ptr_base + ptrdiff);
                                /* no subtype means it's a name event, rather than start/stop */
                                if (subtype == 0)
@@ -2443,22 +2472,16 @@ decode_buffer (ProfContext *ctx)
                                        p++;
                                }
                        } else if (mtype == TYPE_CONTEXT) {
-                               uint64_t flags = decode_uleb128 (p, &p);
-                               if (flags) {
-                                       fprintf (outfile, "non-zero flags in context\n");
-                                       return 0;
-                               }
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
                                intptr_t domaindiff = decode_sleb128 (p, &p);
                                if (debug)
                                        fprintf (outfile, "%s context %p (%p) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), (void *) (ptr_base + domaindiff), (unsigned long long) time_base);
                                if (subtype == TYPE_END_LOAD)
                                        get_remctx (ctx, ptr_base + ptrdiff)->domain_id = ptr_base + domaindiff;
                        } else if (mtype == TYPE_THREAD) {
-                               uint64_t flags = decode_uleb128 (p, &p);
-                               if (flags) {
-                                       fprintf (outfile, "non-zero flags in thread\n");
-                                       return 0;
-                               }
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
                                ThreadContext *nt = get_thread (ctx, ptr_base + ptrdiff);
                                /* no subtype means it's a name event, rather than start/stop */
                                if (subtype == 0)
@@ -2493,7 +2516,7 @@ decode_buffer (ProfContext *ctx)
                                fprintf (outfile, "alloced object %p, size %llu (%s) at %llu\n", (void*)OBJ_ADDR (objdiff), (unsigned long long) len, lookup_class (ptr_base + ptrdiff)->name, (unsigned long long) time_base);
                        if (has_bt) {
                                num_bt = 8;
-                               frames = decode_bt (sframes, &num_bt, p, &p, ptr_base);
+                               frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
                                if (!frames) {
                                        fprintf (outfile, "Cannot load backtrace\n");
                                        return 0;
@@ -2561,7 +2584,14 @@ decode_buffer (ProfContext *ctx)
                        if (subtype == TYPE_HEAP_OBJECT) {
                                HeapObjectDesc *ho = NULL;
                                int i;
-                               intptr_t objdiff = decode_sleb128 (p + 1, &p);
+                               intptr_t objdiff;
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       objdiff = decode_sleb128 (p, &p);
+                               } else
+                                       objdiff = decode_sleb128 (p + 1, &p);
                                intptr_t ptrdiff = decode_sleb128 (p, &p);
                                uint64_t size = decode_uleb128 (p, &p);
                                uintptr_t num = decode_uleb128 (p, &p);
@@ -2594,12 +2624,23 @@ decode_buffer (ProfContext *ctx)
                                if (debug && size)
                                        fprintf (outfile, "traced object %p, size %llu (%s), refs: %zd\n", (void*)OBJ_ADDR (objdiff), (unsigned long long) size, cd->name, num);
                        } else if (subtype == TYPE_HEAP_ROOT) {
-                               uintptr_t num = decode_uleb128 (p + 1, &p);
+                               uintptr_t num;
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       num = decode_uleb128 (p, &p);
+                               } else
+                                       num = decode_uleb128 (p + 1, &p);
                                uintptr_t gc_num G_GNUC_UNUSED = decode_uleb128 (p, &p);
                                int i;
                                for (i = 0; i < num; ++i) {
                                        intptr_t objdiff = decode_sleb128 (p, &p);
-                                       int root_type = decode_uleb128 (p, &p);
+                                       int root_type;
+                                       if (ctx->data_version > 12)
+                                               root_type = *p++;
+                                       else
+                                               root_type = decode_uleb128 (p, &p);
                                        /* we just discard the extra info for now */
                                        uintptr_t extra_info = decode_uleb128 (p, &p);
                                        if (debug)
@@ -2670,7 +2711,7 @@ decode_buffer (ProfContext *ctx)
                                }
                                if (has_bt) {
                                        num_bt = 8;
-                                       frames = decode_bt (sframes, &num_bt, p, &p, ptr_base);
+                                       frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
                                        if (!frames) {
                                                fprintf (outfile, "Cannot load backtrace\n");
                                                return 0;
@@ -2725,7 +2766,11 @@ decode_buffer (ProfContext *ctx)
                        if (!(time_base >= time_from && time_base < time_to))
                                record = 0;
                        if (subtype == TYPE_CLAUSE) {
-                               int clause_type = decode_uleb128 (p, &p);
+                               int clause_type;
+                               if (ctx->data_version > 12)
+                                       clause_type = *p++;
+                               else
+                                       clause_type = decode_uleb128 (p, &p);
                                int clause_num = decode_uleb128 (p, &p);
                                int64_t ptrdiff = decode_sleb128 (p, &p);
                                method_base += ptrdiff;
@@ -2739,7 +2784,7 @@ decode_buffer (ProfContext *ctx)
                                        throw_count++;
                                if (has_bt) {
                                        has_bt = 8;
-                                       frames = decode_bt (sframes, &has_bt, p, &p, ptr_base);
+                                       frames = decode_bt (ctx, sframes, &has_bt, p, &p, ptr_base, &method_base);
                                        if (!frames) {
                                                fprintf (outfile, "Cannot load backtrace\n");
                                                return 0;
@@ -2763,7 +2808,11 @@ decode_buffer (ProfContext *ctx)
                        LOG_TIME (time_base, tdiff);
                        time_base += tdiff;
                        if (subtype == TYPE_JITHELPER) {
-                               int type = decode_uleb128 (p, &p);
+                               int type;
+                               if (ctx->data_version > 12)
+                                       type = *p++;
+                               else
+                                       type = decode_uleb128 (p, &p);
                                intptr_t codediff = decode_sleb128 (p, &p);
                                int codelen = decode_uleb128 (p, &p);
                                const char *name;
@@ -2785,8 +2834,18 @@ decode_buffer (ProfContext *ctx)
                        int subtype = *p & 0xf0;
                        if (subtype == TYPE_SAMPLE_HIT) {
                                int i;
-                               int sample_type = decode_uleb128 (p + 1, &p);
-                               uint64_t tstamp = decode_uleb128 (p, &p);
+                               int sample_type;
+                               uint64_t tstamp;
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       sample_type = *p++;
+                                       tstamp = time_base;
+                               } else {
+                                       sample_type = decode_uleb128 (p + 1, &p);
+                                       tstamp = decode_uleb128 (p, &p);
+                               }
                                void *tid = (void *) thread_id;
                                if (ctx->data_version > 10)
                                        tid = (void *) (ptr_base + decode_sleb128 (p, &p));
@@ -2803,17 +2862,26 @@ decode_buffer (ProfContext *ctx)
                                        for (i = 0; i < count; ++i) {
                                                MethodDesc *method;
                                                int64_t ptrdiff = decode_sleb128 (p, &p);
-                                               int il_offset = decode_sleb128 (p, &p);
-                                               int native_offset = decode_sleb128 (p, &p);
                                                method_base += ptrdiff;
                                                method = lookup_method (method_base);
                                                if (debug)
-                                                       fprintf (outfile, "sample hit bt %d: %s at IL offset %d (native: %d)\n", i, method->name, il_offset, native_offset);
+                                                       fprintf (outfile, "sample hit bt %d: %s\n", i, method->name);
+                                               if (ctx->data_version < 13) {
+                                                       decode_sleb128 (p, &p); /* il offset */
+                                                       decode_sleb128 (p, &p); /* native offset */
+                                               }
                                        }
                                }
                        } else if (subtype == TYPE_SAMPLE_USYM) {
                                /* un unmanaged symbol description */
-                               uintptr_t addr = ptr_base + decode_sleb128 (p + 1, &p);
+                               uintptr_t addr;
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       addr = ptr_base + decode_sleb128 (p, &p);
+                               } else
+                                       addr = ptr_base + decode_sleb128 (p + 1, &p);
                                uintptr_t size = decode_uleb128 (p, &p);
                                char *name;
                                name = pstrdup ((char*)p);
@@ -2838,7 +2906,14 @@ decode_buffer (ProfContext *ctx)
                                while (*p) p++;
                                p++;
                        } else if (subtype == TYPE_SAMPLE_COUNTERS_DESC) {
-                               uint64_t i, len = decode_uleb128 (p + 1, &p);
+                               uint64_t i, len;
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       len = decode_uleb128 (p, &p);
+                               } else
+                                       len = decode_uleb128 (p + 1, &p);
                                for (i = 0; i < len; i++) {
                                        uint64_t type, unit, variance, index;
                                        uint64_t section = decode_uleb128 (p, &p);
@@ -2851,9 +2926,15 @@ decode_buffer (ProfContext *ctx)
                                        }
                                        name = pstrdup ((char*)p);
                                        while (*p++);
-                                       type = decode_uleb128 (p, &p);
-                                       unit = decode_uleb128 (p, &p);
-                                       variance = decode_uleb128 (p, &p);
+                                       if (ctx->data_version > 12) {
+                                               type = *p++;
+                                               unit = *p++;
+                                               variance = *p++;
+                                       } else {
+                                               type = decode_uleb128 (p, &p);
+                                               unit = decode_uleb128 (p, &p);
+                                               variance = decode_uleb128 (p, &p);
+                                       }
                                        index = decode_uleb128 (p, &p);
                                        add_counter (section_str, name, (int)type, (int)unit, (int)variance, (int)index);
                                }
@@ -2861,7 +2942,14 @@ decode_buffer (ProfContext *ctx)
                                int i;
                                CounterValue *value, *previous = NULL;
                                CounterList *list;
-                               uint64_t timestamp = decode_uleb128 (p + 1, &p);
+                               uint64_t timestamp; // milliseconds since startup
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       timestamp = (time_base - startup_time) / 1000 / 1000;
+                               } else
+                                       timestamp = decode_uleb128 (p + 1, &p);
                                uint64_t time_between = timestamp / 1000 * 1000 * 1000 * 1000 + startup_time;
                                while (1) {
                                        uint64_t type, index = decode_uleb128 (p, &p);
@@ -2875,7 +2963,10 @@ decode_buffer (ProfContext *ctx)
                                                }
                                        }
 
-                                       type = decode_uleb128 (p, &p);
+                                       if (ctx->data_version > 12)
+                                               type = *p++;
+                                       else
+                                               type = decode_uleb128 (p, &p);
 
                                        value = (CounterValue *)calloc (1, sizeof (CounterValue));
                                        value->timestamp = timestamp;
@@ -2939,6 +3030,13 @@ decode_buffer (ProfContext *ctx)
                                int token, n_offsets, method_id;
 
                                p++;
+
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                               }
+
                                assembly = (const char *)p; while (*p) p++; p++;
                                klass = (const char *)p; while (*p) p++; p++;
                                name = (const char *)p; while (*p) p++; p++;
@@ -2968,6 +3066,13 @@ decode_buffer (ProfContext *ctx)
                                int offset, count, line, column, method_id;
 
                                p++;
+
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                               }
+
                                method_id = decode_uleb128 (p, &p);
                                offset = decode_uleb128 (p, &p);
                                count = decode_uleb128 (p, &p);
@@ -2989,6 +3094,12 @@ decode_buffer (ProfContext *ctx)
                                int number_of_methods, fully_covered, partially_covered;
                                p++;
 
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                               }
+
                                name = (char *)p; while (*p) p++; p++;
                                guid = (char *)p; while (*p) p++; p++;
                                filename = (char *)p; while (*p) p++; p++;
@@ -3012,6 +3123,12 @@ decode_buffer (ProfContext *ctx)
                                int number_of_methods, fully_covered, partially_covered;
                                p++;
 
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                               }
+
                                assembly_name = (char *)p; while (*p) p++; p++;
                                class_name = (char *)p; while (*p) p++; p++;
                                number_of_methods = decode_uleb128 (p, &p);
@@ -3033,6 +3150,18 @@ decode_buffer (ProfContext *ctx)
                        }
                        break;
                }
+               case TYPE_META: {
+                       int subtype = *p & 0xf0;
+                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                       LOG_TIME (time_base, tdiff);
+                       time_base += tdiff;
+                       if (subtype == TYPE_SYNC_POINT) {
+                               int type = *p++;
+                               if (debug)
+                                       fprintf (outfile, "sync point %i (%s)\n", type, sync_point_name (type));
+                       }
+                       break;
+               }
                default:
                        fprintf (outfile, "unhandled profiler event: 0x%x at file offset: %llu + %lld (len: %d\n)\n", *p, (unsigned long long) file_offset, (long long) (p - ctx->buf), len);
                        exit (1);
@@ -3792,6 +3921,8 @@ dump_stats (void)
        DUMP_EVENT_STAT (TYPE_COVERAGE, TYPE_COVERAGE_METHOD);
        DUMP_EVENT_STAT (TYPE_COVERAGE, TYPE_COVERAGE_STATEMENT);
        DUMP_EVENT_STAT (TYPE_COVERAGE, TYPE_COVERAGE_CLASS);
+
+       DUMP_EVENT_STAT (TYPE_META, TYPE_SYNC_POINT);
 }
 
 
index 99e68567571dcf59b3759f143d2642e0861c06de..83da612181e2ed1f2767bc82617d2fe8d2dc4f6e 100644 (file)
@@ -17,6 +17,7 @@
 #include <mono/metadata/threads.h>
 #include <mono/metadata/mono-gc.h>
 #include <mono/metadata/debug-helpers.h>
+#include <mono/metadata/mono-gc.h>
 #include <mono/metadata/mono-perfcounters.h>
 #include <mono/metadata/appdomain.h>
 #include <mono/metadata/assembly.h>
 #include <mono/utils/mono-os-mutex.h>
 #include <mono/utils/mono-os-semaphore.h>
 #include <mono/utils/mono-conc-hashtable.h>
+#include <mono/utils/mono-linked-list-set.h>
 #include <mono/utils/lock-free-alloc.h>
 #include <mono/utils/lock-free-queue.h>
 #include <mono/utils/hazard-pointer.h>
 #include <mono/utils/mono-threads.h>
+#include <mono/utils/mono-threads-api.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
@@ -105,8 +108,10 @@ static int read_perf_mmap (MonoProfiler* prof, int cpu);
 
 /* Worst-case size in bytes of a 64-bit value encoded with LEB128. */
 #define LEB128_SIZE 10
-/* Size in bytes of the event ID prefix. */
-#define EVENT_SIZE 1
+/* Size of a value encoded as a single byte. */
+#define BYTE_SIZE 1
+/* Size in bytes of the event prefix (ID + time). */
+#define EVENT_SIZE (BYTE_SIZE + LEB128_SIZE)
 
 static int nocalls = 0;
 static int notraces = 0;
@@ -146,7 +151,7 @@ static gint32 image_unloads;
 static gint32 class_loads;
 static gint32 class_unloads;
 
-typedef struct _LogBuffer LogBuffer;
+static MonoLinkedListSet profiler_thread_list;
 
 /*
  * file format:
@@ -212,7 +217,6 @@ typedef struct _LogBuffer LogBuffer;
  * strings are represented as a 0-terminated utf8 sequence.
  *
  * backtrace format:
- * [flags: uleb128] must be 0
  * [num: uleb128] number of frames following
  * [frame: sleb128]* num MonoMethod pointers as differences from ptr_base
  *
@@ -228,13 +232,14 @@ typedef struct _LogBuffer LogBuffer;
  * type GC format:
  * type: TYPE_GC
  * exinfo: one of TYPE_GC_EVENT, TYPE_GC_RESIZE, TYPE_GC_MOVE, TYPE_GC_HANDLE_CREATED[_BT],
- * TYPE_GC_HANDLE_DESTROYED[_BT]
+ * TYPE_GC_HANDLE_DESTROYED[_BT], TYPE_GC_FINALIZE_START, TYPE_GC_FINALIZE_END,
+ * TYPE_GC_FINALIZE_OBJECT_START, TYPE_GC_FINALIZE_OBJECT_END
  * [time diff: uleb128] nanoseconds since last timing
  * if exinfo == TYPE_GC_RESIZE
  *     [heap_size: uleb128] new heap size
  * if exinfo == TYPE_GC_EVENT
- *     [event type: uleb128] GC event (MONO_GC_EVENT_* from profiler.h)
- *     [generation: uleb128] GC generation event refers to
+ *     [event type: byte] GC event (MONO_GC_EVENT_* from profiler.h)
+ *     [generation: byte] GC generation event refers to
  * if exinfo == TYPE_GC_MOVE
  *     [num_objects: uleb128] number of object moves that follow
  *     [objaddr: sleb128]+ num_objects object pointer differences from obj_base
@@ -251,6 +256,8 @@ typedef struct _LogBuffer LogBuffer;
  *     upper bits reserved as flags
  *     [handle: uleb128] GC handle value
  *     If exinfo == TYPE_GC_HANDLE_DESTROYED_BT, a backtrace follows.
+ * if exinfo == TYPE_GC_FINALIZE_OBJECT_{START,END}
+ *     [object: sleb128] the object as a difference from obj_base
  *
  * type metadata format:
  * type: TYPE_METADATA
@@ -261,23 +268,16 @@ typedef struct _LogBuffer LogBuffer;
  * [pointer: sleb128] pointer of the metadata type depending on mtype
  * if mtype == TYPE_CLASS
  *     [image: sleb128] MonoImage* as a pointer difference from ptr_base
- *     [flags: uleb128] must be 0
  *     [name: string] full class name
  * if mtype == TYPE_IMAGE
- *     [flags: uleb128] must be 0
  *     [name: string] image file name
  * if mtype == TYPE_ASSEMBLY
- *     [flags: uleb128] must be 0
  *     [name: string] assembly name
- * if mtype == TYPE_DOMAIN
- *     [flags: uleb128] must be 0
  * if mtype == TYPE_DOMAIN && exinfo == 0
  *     [name: string] domain friendly name
  * if mtype == TYPE_CONTEXT
- *     [flags: uleb128] must be 0
  *     [domain: sleb128] domain id as pointer
- * if mtype == TYPE_THREAD && (format_version < 11 || (format_version > 10 && exinfo == 0))
- *     [flags: uleb128] must be 0
+ * if mtype == TYPE_THREAD && exinfo == 0
  *     [name: string] thread name
  *
  * type method format:
@@ -296,7 +296,7 @@ typedef struct _LogBuffer LogBuffer;
  * exinfo: one of: TYPE_JITHELPER
  * [time diff: uleb128] nanoseconds since last timing
  * if exinfo == TYPE_JITHELPER
- *     [type: uleb128] MonoProfilerCodeBufferType enum value
+ *     [type: byte] MonoProfilerCodeBufferType enum value
  *     [buffer address: sleb128] pointer to the native code as a diff from ptr_base
  *     [buffer size: uleb128] size of the generated code
  *     if type == MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE
@@ -322,9 +322,9 @@ typedef struct _LogBuffer LogBuffer;
  *     [class: sleb128] the object MonoClass* as a difference from ptr_base
  *     [size: uleb128] size of the object on the heap
  *     [num_refs: uleb128] number of object references
- *     if (format version > 1) each referenced objref is preceded by a
- *     uleb128 encoded offset: the first offset is from the object address
- *     and each next offset is relative to the previous one
+ *     each referenced objref is preceded by a uleb128 encoded offset: the
+ *     first offset is from the object address and each next offset is relative
+ *     to the previous one
  *     [objrefs: sleb128]+ object referenced as a difference from obj_base
  *     The same object can appear multiple times, but only the first time
  *     with size != 0: in the other cases this data will only be used to
@@ -333,7 +333,7 @@ typedef struct _LogBuffer LogBuffer;
  *     [num_roots: uleb128] number of root references
  *     [num_gc: uleb128] number of major gcs
  *     [object: sleb128] the object as a difference from obj_base
- *     [root_type: uleb128] the root_type: MonoProfileGCRootType (profiler.h)
+ *     [root_type: byte] the root_type: MonoProfileGCRootType (profiler.h)
  *     [extra_info: uleb128] the extra_info value
  *     object, root_type and extra_info are repeated num_roots times
  *
@@ -341,18 +341,14 @@ typedef struct _LogBuffer LogBuffer;
  * type: TYPE_SAMPLE
  * exinfo: one of TYPE_SAMPLE_HIT, TYPE_SAMPLE_USYM, TYPE_SAMPLE_UBIN, TYPE_SAMPLE_COUNTERS_DESC, TYPE_SAMPLE_COUNTERS
  * if exinfo == TYPE_SAMPLE_HIT
- *     [sample_type: uleb128] type of sample (SAMPLE_*)
+ *     [sample_type: byte] type of sample (SAMPLE_*)
  *     [timestamp: uleb128] nanoseconds since startup (note: different from other timestamps!)
- *     if (format_version > 10)
- *             [thread: sleb128] thread id as difference from ptr_base
+ *     [thread: sleb128] thread id as difference from ptr_base
  *     [count: uleb128] number of following instruction addresses
  *     [ip: sleb128]* instruction pointer as difference from ptr_base
- *     if (format_version > 5)
- *             [mbt_count: uleb128] number of managed backtrace info triplets (method + IL offset + native offset)
- *             [method: sleb128]* MonoMethod* as a pointer difference from the last such
- *             pointer or the buffer method_base (the first such method can be also indentified by ip, but this is not neccessarily true)
- *             [il_offset: sleb128]* IL offset inside method where the hit occurred
- *             [native_offset: sleb128]* native offset inside method where the hit occurred
+ *     [mbt_count: uleb128] number of managed backtrace frames
+ *     [method: sleb128]* MonoMethod* as a pointer difference from the last such
+ *     pointer or the buffer method_base (the first such method can be also indentified by ip, but this is not neccessarily true)
  * if exinfo == TYPE_SAMPLE_USYM
  *     [address: sleb128] symbol address as a difference from ptr_base
  *     [size: uleb128] symbol size (may be 0 if unknown)
@@ -370,9 +366,9 @@ typedef struct _LogBuffer LogBuffer;
  *             if section == MONO_COUNTER_PERFCOUNTERS:
  *                     [section_name: string] section name of counter
  *             [name: string] name of counter
- *             [type: uleb128] type of counter
- *             [unit: uleb128] unit of counter
- *             [variance: uleb128] variance of counter
+ *             [type: byte] type of counter
+ *             [unit: byte] unit of counter
+ *             [variance: byte] variance of counter
  *             [index: uleb128] unique index of counter
  * if exinfo == TYPE_SAMPLE_COUNTERS
  *     [timestamp: uleb128] sampling timestamp
@@ -380,7 +376,7 @@ typedef struct _LogBuffer LogBuffer;
  *             [index: uleb128] unique index of counter
  *             if index == 0:
  *                     break
- *             [type: uleb128] type of counter value
+ *             [type: byte] type of counter value
  *             if type == string:
  *                     if value == null:
  *                             [0: uleb128] 0 -> value is null
@@ -425,23 +421,18 @@ typedef struct _LogBuffer LogBuffer;
  *  [partially_covered: uleb128] the number of partially covered methods
  *    currently partially_covered will always be 0, and fully_covered is the
  *    number of methods that are fully and partially covered.
- */
-
-/*
- * Format oddities that we ought to fix:
  *
- * - Methods written in emit_bt () should be based on the buffer's base
- *   method instead of the base pointer.
- * - The TYPE_SAMPLE_HIT event contains (currently) pointless data like
- *   always-one unmanaged frame count and always-zero IL offsets.
- *
- * These are mostly small things and are not worth a format change by
- * themselves. They should be done when some other major change has to
- * be done to the format.
+ * type meta format:
+ * type: TYPE_META
+ * exinfo: one of: TYPE_SYNC_POINT
+ * [time diff: uleb128] nanoseconds since last timing
+ * if exinfo == TYPE_SYNC_POINT
+ *     [type: byte] MonoProfilerSyncPointType enum value
  */
 
 // Pending data to be written to the log, for a single thread.
 // Threads periodically flush their own LogBuffers by calling safe_send
+typedef struct _LogBuffer LogBuffer;
 struct _LogBuffer {
        // Next (older) LogBuffer in processing queue
        LogBuffer *next;
@@ -453,8 +444,6 @@ struct _LogBuffer {
        uintptr_t last_method;
        uintptr_t obj_base;
        uintptr_t thread_id;
-       int locked;
-       int call_depth;
 
        // Bytes allocated for this LogBuffer
        int size;
@@ -469,16 +458,123 @@ struct _LogBuffer {
        unsigned char buf [1];
 };
 
+typedef struct {
+       MonoLinkedListSetNode node;
+
+       // The current log buffer for this thread.
+       LogBuffer *buffer;
+
+       // Methods referenced by events in `buffer`, see `MethodInfo`.
+       GPtrArray *methods;
+
+       // Current call depth for enter/leave events.
+       int call_depth;
+
+       // Indicates whether this thread is currently writing to its `buffer`.
+       int busy;
+} MonoProfilerThread;
+
 static inline void
 ign_res (int G_GNUC_UNUSED unused, ...)
 {
 }
 
-#define ENTER_LOG(lb,str) if ((lb)->locked) {ign_res (write(2, str, strlen(str))); ign_res (write(2, "\n", 1));return;} else {(lb)->locked++;}
-#define EXIT_LOG(lb) (lb)->locked--;
+/*
+ * These macros create a scope to avoid leaking the buffer returned
+ * from ensure_logbuf () as it may have been invalidated by a GC
+ * thread during STW. If you called init_thread () with add_to_lls =
+ * FALSE, then don't use these macros.
+ */
+
+#define ENTER_LOG \
+       do { \
+               buffer_lock (); \
+               g_assert (!PROF_TLS_GET ()->busy++ && "Why are we trying to write a new event while already writing one?")
 
-typedef struct _BinaryObject BinaryObject;
+#define EXIT_LOG \
+               PROF_TLS_GET ()->busy--; \
+               buffer_unlock (); \
+       } while (0)
+
+static volatile gint32 buffer_rwlock_count;
+static volatile gpointer buffer_rwlock_exclusive;
+
+// Can be used recursively.
+static void
+buffer_lock (void)
+{
+       /*
+        * If the thread holding the exclusive lock tries to modify the
+        * reader count, just make it a no-op. This way, we also avoid
+        * invoking the GC safe point macros below, which could break if
+        * done from a thread that is currently the initiator of STW.
+        *
+        * In other words, we rely on the fact that the GC thread takes
+        * the exclusive lock in the gc_event () callback when the world
+        * is about to stop.
+        */
+       if (InterlockedReadPointer (&buffer_rwlock_exclusive) != (gpointer) thread_id ()) {
+               MONO_ENTER_GC_SAFE;
+
+               while (InterlockedReadPointer (&buffer_rwlock_exclusive))
+                       mono_thread_info_yield ();
+
+               InterlockedIncrement (&buffer_rwlock_count);
+
+               MONO_EXIT_GC_SAFE;
+       }
+
+       mono_memory_barrier ();
+}
+
+static void
+buffer_unlock (void)
+{
+       mono_memory_barrier ();
+
+       // See the comment in buffer_lock ().
+       if (InterlockedReadPointer (&buffer_rwlock_exclusive) == (gpointer) thread_id ())
+               return;
+
+       g_assert (InterlockedRead (&buffer_rwlock_count) && "Why are we trying to decrement a zero reader count?");
+
+       InterlockedDecrement (&buffer_rwlock_count);
+}
+
+// Cannot be used recursively.
+static void
+buffer_lock_excl (void)
+{
+       gpointer tid = (gpointer) thread_id ();
 
+       g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) != tid && "Why are we taking the exclusive lock twice?");
+
+       MONO_ENTER_GC_SAFE;
+
+       while (InterlockedCompareExchangePointer (&buffer_rwlock_exclusive, tid, 0))
+               mono_thread_info_yield ();
+
+       while (InterlockedRead (&buffer_rwlock_count))
+               mono_thread_info_yield ();
+
+       MONO_EXIT_GC_SAFE;
+
+       mono_memory_barrier ();
+}
+
+static void
+buffer_unlock_excl (void)
+{
+       mono_memory_barrier ();
+
+       g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) && "Why is the exclusive lock not held?");
+       g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) == (gpointer) thread_id () && "Why does another thread hold the exclusive lock?");
+       g_assert (!InterlockedRead (&buffer_rwlock_count) && "Why are there readers when the exclusive lock is held?");
+
+       InterlockedWritePointer (&buffer_rwlock_exclusive, NULL);
+}
+
+typedef struct _BinaryObject BinaryObject;
 struct _BinaryObject {
        BinaryObject *next;
        void *addr;
@@ -502,6 +598,8 @@ struct _MonoProfiler {
        pthread_t dumper_thread;
 #endif
        volatile gint32 run_writer_thread;
+       MonoLockFreeAllocSizeClass writer_entry_size_class;
+       MonoLockFreeAllocator writer_entry_allocator;
        MonoLockFreeQueue writer_queue;
        MonoSemType writer_queue_sem;
        MonoConcurrentHashTable *method_table;
@@ -516,45 +614,48 @@ struct _MonoProfiler {
        GPtrArray *coverage_filters;
 };
 
-typedef struct _WriterQueueEntry WriterQueueEntry;
-struct _WriterQueueEntry {
+typedef struct {
        MonoLockFreeQueueNode node;
        GPtrArray *methods;
        LogBuffer *buffer;
-};
+} WriterQueueEntry;
+
+#define WRITER_ENTRY_BLOCK_SIZE (mono_pagesize ())
 
-typedef struct _MethodInfo MethodInfo;
-struct _MethodInfo {
+typedef struct {
        MonoMethod *method;
        MonoJitInfo *ji;
        uint64_t time;
-};
-
-#ifdef TLS_INIT
-#undef TLS_INIT
-#endif
+} MethodInfo;
 
 #ifdef HOST_WIN32
-#define TLS_SET(x,y) (TlsSetValue (x, y))
-#define TLS_GET(t,x) ((t *) TlsGetValue (x))
-#define TLS_INIT(x) (x = TlsAlloc ())
-static int tlsbuffer;
-static int tlsmethodlist;
+
+#define PROF_TLS_SET(VAL) (TlsSetValue (profiler_tls, (VAL)))
+#define PROF_TLS_GET() ((MonoProfilerThread *) TlsGetValue (profiler_tls))
+#define PROF_TLS_INIT() (profiler_tls = TlsAlloc ())
+#define PROF_TLS_FREE() (TlsFree (profiler_tls))
+
+static DWORD profiler_tls;
+
 #elif HAVE_KW_THREAD
-#define TLS_SET(x,y) (x = y)
-#define TLS_GET(t,x) (x)
-#define TLS_INIT(x)
-static __thread LogBuffer* tlsbuffer = NULL;
-static __thread GPtrArray* tlsmethodlist = NULL;
+
+#define PROF_TLS_SET(VAL) (profiler_tls = (VAL))
+#define PROF_TLS_GET() (profiler_tls)
+#define PROF_TLS_INIT()
+#define PROF_TLS_FREE()
+
+static __thread MonoProfilerThread *profiler_tls;
+
 #else
-#define TLS_SET(x,y) (pthread_setspecific (x, y))
-#define TLS_GET(t,x) ((t *) pthread_getspecific (x))
-#define TLS_INIT(x) (pthread_key_create (&x, NULL))
-static pthread_key_t tlsbuffer;
-static pthread_key_t tlsmethodlist;
-#endif
 
-static void safe_send (MonoProfiler *profiler, LogBuffer *logbuffer);
+#define PROF_TLS_SET(VAL) (pthread_setspecific (profiler_tls, (VAL)))
+#define PROF_TLS_GET() ((MonoProfilerThread *) pthread_getspecific (profiler_tls))
+#define PROF_TLS_INIT() (pthread_key_create (&profiler_tls, NULL))
+#define PROF_TLS_FREE() (pthread_key_delete (&profiler_tls))
+
+static pthread_key_t profiler_tls;
+
+#endif
 
 static char*
 pstrdup (const char *s)
@@ -581,19 +682,67 @@ create_buffer (void)
 }
 
 static void
-init_thread (void)
+init_buffer_state (MonoProfilerThread *thread)
 {
-       if (!TLS_GET (LogBuffer, tlsbuffer)) {
-               LogBuffer *logbuffer = create_buffer ();
-               TLS_SET (tlsbuffer, logbuffer);
-               logbuffer->thread_id = thread_id ();
-       }
-       if (!TLS_GET (GPtrArray, tlsmethodlist)) {
-               GPtrArray *methodlist = g_ptr_array_new ();
-               TLS_SET (tlsmethodlist, methodlist);
+       thread->buffer = create_buffer ();
+       thread->methods = NULL;
+}
+
+static void
+clear_hazard_pointers (MonoThreadHazardPointers *hp)
+{
+       mono_hazard_pointer_clear (hp, 0);
+       mono_hazard_pointer_clear (hp, 1);
+       mono_hazard_pointer_clear (hp, 2);
+}
+
+static MonoProfilerThread *
+init_thread (gboolean add_to_lls)
+{
+       MonoProfilerThread *thread = PROF_TLS_GET ();
+
+       /*
+        * Sometimes we may try to initialize a thread twice. One example is the
+        * main thread: We initialize it when setting up the profiler, but we will
+        * also get a thread_start () callback for it. Another example is when
+        * attaching new threads to the runtime: We may get a gc_alloc () callback
+        * for that thread's thread object (where we initialize it), soon followed
+        * by a thread_start () callback.
+        *
+        * These cases are harmless anyhow. Just return if we've already done the
+        * initialization work.
+        */
+       if (thread)
+               return thread;
+
+       thread = malloc (sizeof (MonoProfilerThread));
+       thread->node.key = thread_id ();
+       thread->call_depth = 0;
+       thread->busy = 0;
+
+       init_buffer_state (thread);
+
+       /*
+        * Some internal profiler threads don't need to be cleaned up
+        * by the main thread on shutdown.
+        */
+       if (add_to_lls) {
+               MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
+               g_assert (mono_lls_insert (&profiler_thread_list, hp, &thread->node) && "Why can't we insert the thread in the LLS?");
+               clear_hazard_pointers (hp);
        }
 
-       //printf ("thread %p at time %llu\n", (void*)logbuffer->thread_id, logbuffer->time_base);
+       PROF_TLS_SET (thread);
+
+       return thread;
+}
+
+// Only valid if init_thread () was called with add_to_lls = FALSE.
+static void
+deinit_thread (MonoProfilerThread *thread)
+{
+       free (thread);
+       PROF_TLS_SET (NULL);
 }
 
 static LogBuffer *
@@ -602,31 +751,48 @@ ensure_logbuf_inner (LogBuffer *old, int bytes)
        if (old && old->cursor + bytes + 100 < old->buf_end)
                return old;
 
-       LogBuffer *new_ = (LogBuffer *)create_buffer ();
-       new_->thread_id = thread_id ();
+       LogBuffer *new_ = create_buffer ();
        new_->next = old;
 
-       if (old)
-               new_->call_depth = old->call_depth;
-
        return new_;
 }
 
-static LogBuffer*
-ensure_logbuf (int bytes)
+// Only valid if init_thread () was called with add_to_lls = FALSE.
+static LogBuffer *
+ensure_logbuf_unsafe (int bytes)
 {
-       LogBuffer *old = TLS_GET (LogBuffer, tlsbuffer);
+       MonoProfilerThread *thread = PROF_TLS_GET ();
+       LogBuffer *old = thread->buffer;
        LogBuffer *new_ = ensure_logbuf_inner (old, bytes);
 
        if (new_ == old)
                return old; // Still enough space.
 
-       TLS_SET (tlsbuffer, new_);
-       init_thread ();
+       thread->buffer = new_;
 
        return new_;
 }
 
+/*
+ * Any calls to this function should be wrapped in the ENTER_LOG and
+ * EXIT_LOG macros to prevent the returned pointer from leaking
+ * outside of the critical region created by the calls to buffer_lock ()
+ * and buffer_unlock () that those macros insert. If the pointer leaks,
+ * it can and will lead to crashes as the GC or helper thread may
+ * invalidate the pointer at any time.
+ *
+ * Note: If you're calling from a thread that called init_thread () with
+ * add_to_lls = FALSE, you should use ensure_logbuf_unsafe () and omit
+ * the macros.
+ */
+static LogBuffer*
+ensure_logbuf (int bytes)
+{
+       g_assert (PROF_TLS_GET ()->busy && "Why are we trying to expand our buffer without the busy flag set?");
+
+       return ensure_logbuf_unsafe (bytes);
+}
+
 static void
 emit_byte (LogBuffer *logbuffer, int value)
 {
@@ -657,6 +823,19 @@ emit_time (LogBuffer *logbuffer, uint64_t value)
        assert (logbuffer->cursor <= logbuffer->buf_end);
 }
 
+static void
+emit_event_time (LogBuffer *logbuffer, int event, uint64_t time)
+{
+       emit_byte (logbuffer, event);
+       emit_time (logbuffer, time);
+}
+
+static void
+emit_event (LogBuffer *logbuffer, int event)
+{
+       emit_event_time (logbuffer, event, current_time ());
+}
+
 static void
 emit_svalue (LogBuffer *logbuffer, int64_t value)
 {
@@ -751,13 +930,15 @@ register_method_local (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *ji)
                 */
                //g_assert (ji);
 
-               MethodInfo *info = (MethodInfo *)malloc (sizeof (MethodInfo));
+               MethodInfo *info = (MethodInfo *) malloc (sizeof (MethodInfo));
 
                info->method = method;
                info->ji = ji;
                info->time = current_time ();
 
-               g_ptr_array_add (TLS_GET (GPtrArray, tlsmethodlist), info);
+               MonoProfilerThread *thread = PROF_TLS_GET ();
+               GPtrArray *arr = thread->methods ? thread->methods : (thread->methods = g_ptr_array_new ());
+               g_ptr_array_add (arr, info);
        }
 }
 
@@ -768,13 +949,6 @@ emit_method (MonoProfiler *prof, LogBuffer *logbuffer, MonoMethod *method)
        emit_method_inner (logbuffer, method);
 }
 
-static void
-emit_method_as_ptr (MonoProfiler *prof, LogBuffer *logbuffer, MonoMethod *method)
-{
-       register_method_local (prof, method, NULL);
-       emit_ptr (logbuffer, method);
-}
-
 static void
 emit_obj (LogBuffer *logbuffer, void *ptr)
 {
@@ -874,16 +1048,60 @@ dump_header (MonoProfiler *profiler)
 }
 
 static void
-send_buffer (MonoProfiler *prof, GPtrArray *methods, LogBuffer *buffer)
+send_buffer (MonoProfiler *prof, MonoProfilerThread *thread)
 {
-       WriterQueueEntry *entry = (WriterQueueEntry *)calloc (1, sizeof (WriterQueueEntry));
+       WriterQueueEntry *entry = mono_lock_free_alloc (&prof->writer_entry_allocator);
+       entry->methods = thread->methods;
+       entry->buffer = thread->buffer;
+
        mono_lock_free_queue_node_init (&entry->node, FALSE);
-       entry->methods = methods;
-       entry->buffer = buffer;
+
        mono_lock_free_queue_enqueue (&prof->writer_queue, &entry->node);
        mono_os_sem_post (&prof->writer_queue_sem);
 }
 
+static void
+remove_thread (MonoProfiler *prof, MonoProfilerThread *thread, gboolean from_callback)
+{
+       MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
+
+       if (mono_lls_remove (&profiler_thread_list, hp, &thread->node)) {
+               LogBuffer *buffer = thread->buffer;
+
+               /*
+                * No need to take the buffer lock here as no other threads can
+                * be accessing this buffer anymore.
+                */
+
+               if (!from_callback) {
+                       /*
+                        * The thread is being cleaned up by the main thread during
+                        * shutdown. This typically happens for internal runtime
+                        * threads. We need to synthesize a thread end event.
+                        */
+
+                       buffer = ensure_logbuf_inner (buffer,
+                               EVENT_SIZE /* event */ +
+                               BYTE_SIZE /* type */ +
+                               LEB128_SIZE /* tid */
+                       );
+
+                       emit_event (buffer, TYPE_END_UNLOAD | TYPE_METADATA);
+                       emit_byte (buffer, TYPE_THREAD);
+                       emit_ptr (buffer, (void *) thread->node.key);
+               }
+
+               send_buffer (prof, thread);
+
+               mono_thread_hazardous_try_free (thread, free);
+       }
+
+       clear_hazard_pointers (hp);
+
+       if (from_callback)
+               PROF_TLS_SET (NULL);
+}
+
 static void
 dump_buffer (MonoProfiler *profiler, LogBuffer *buf)
 {
@@ -913,6 +1131,15 @@ dump_buffer (MonoProfiler *profiler, LogBuffer *buf)
        free_buffer (buf, buf->size);
 }
 
+static void
+dump_buffer_threadless (MonoProfiler *profiler, LogBuffer *buf)
+{
+       for (LogBuffer *iter = buf; iter; iter = iter->next)
+               iter->thread_id = 0;
+
+       dump_buffer (profiler, buf);
+}
+
 static void
 process_requests (MonoProfiler *profiler)
 {
@@ -921,13 +1148,10 @@ process_requests (MonoProfiler *profiler)
 }
 
 static void counters_init (MonoProfiler *profiler);
-static void counters_sample (MonoProfiler *profiler, uint64_t timestamp, gboolean threadless);
+static void counters_sample (MonoProfiler *profiler, uint64_t timestamp);
 
-/*
- * Can be called only at safe callback locations.
- */
 static void
-safe_send (MonoProfiler *profiler, LogBuffer *logbuffer)
+safe_send (MonoProfiler *profiler)
 {
        /* We need the runtime initialized so that we have threads and hazard
         * pointers available. Otherwise, the lock free queue will not work and
@@ -939,33 +1163,102 @@ safe_send (MonoProfiler *profiler, LogBuffer *logbuffer)
        if (!InterlockedRead (&runtime_inited))
                return;
 
-       int cd = logbuffer->call_depth;
+       MonoProfilerThread *thread = PROF_TLS_GET ();
 
-       send_buffer (profiler, TLS_GET (GPtrArray, tlsmethodlist), TLS_GET (LogBuffer, tlsbuffer));
+       buffer_lock ();
 
-       TLS_SET (tlsbuffer, NULL);
-       TLS_SET (tlsmethodlist, NULL);
+       send_buffer (profiler, thread);
+       init_buffer_state (thread);
 
-       init_thread ();
+       buffer_unlock ();
+}
 
-       TLS_GET (LogBuffer, tlsbuffer)->call_depth = cd;
+static void
+send_if_needed (MonoProfiler *prof)
+{
+       if (PROF_TLS_GET ()->buffer->next)
+               safe_send (prof);
 }
 
 static void
-safe_send_threadless (MonoProfiler *prof, LogBuffer *buf)
+safe_send_threadless (MonoProfiler *prof)
 {
+       LogBuffer *buf = PROF_TLS_GET ()->buffer;
+
        for (LogBuffer *iter = buf; iter; iter = iter->next)
                iter->thread_id = 0;
 
-       safe_send (prof, buf);
+       safe_send (prof);
+}
+
+static void
+send_if_needed_threadless (MonoProfiler *prof)
+{
+       if (PROF_TLS_GET ()->buffer->next)
+               safe_send_threadless (prof);
+}
+
+// Assumes that the exclusive lock is held.
+static void
+sync_point_flush (MonoProfiler *prof)
+{
+       g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) == (gpointer) thread_id () && "Why don't we hold the exclusive lock?");
+
+       MONO_LLS_FOREACH_SAFE (&profiler_thread_list, MonoProfilerThread, thread) {
+               send_buffer (prof, thread);
+               init_buffer_state (thread);
+       } MONO_LLS_FOREACH_SAFE_END
+}
+
+// Assumes that the exclusive lock is held.
+static void
+sync_point_mark (MonoProfiler *prof, MonoProfilerSyncPointType type)
+{
+       g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) == (gpointer) thread_id () && "Why don't we hold the exclusive lock?");
+
+       ENTER_LOG;
+
+       LogBuffer *logbuffer = ensure_logbuf (
+               EVENT_SIZE /* event */ +
+               LEB128_SIZE /* type */
+       );
+
+       emit_event (logbuffer, TYPE_META | TYPE_SYNC_POINT);
+       emit_byte (logbuffer, type);
+
+       EXIT_LOG;
+
+       switch (type) {
+       case SYNC_POINT_PERIODIC:
+               safe_send_threadless (prof);
+               break;
+       case SYNC_POINT_WORLD_STOP:
+       case SYNC_POINT_WORLD_START:
+               safe_send (prof);
+               break;
+       default:
+               g_assert_not_reached ();
+               break;
+       }
+}
+
+// Assumes that the exclusive lock is held.
+static void
+sync_point (MonoProfiler *prof, MonoProfilerSyncPointType type)
+{
+       sync_point_flush (prof);
+       sync_point_mark (prof, type);
 }
 
 static int
 gc_reference (MonoObject *obj, MonoClass *klass, uintptr_t size, uintptr_t num, MonoObject **refs, uintptr_t *offsets, void *data)
 {
-       int i;
-       uintptr_t last_offset = 0;
-       //const char *name = mono_class_get_name (klass);
+       /* account for object alignment in the heap */
+       size += 7;
+       size &= ~7;
+
+       ENTER_LOG;
+
        LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
                LEB128_SIZE /* obj */ +
@@ -977,21 +1270,23 @@ gc_reference (MonoObject *obj, MonoClass *klass, uintptr_t size, uintptr_t num,
                        LEB128_SIZE /* ref */
                )
        );
-       emit_byte (logbuffer, TYPE_HEAP_OBJECT | TYPE_HEAP);
+
+       emit_event (logbuffer, TYPE_HEAP_OBJECT | TYPE_HEAP);
        emit_obj (logbuffer, obj);
        emit_ptr (logbuffer, klass);
-       /* account for object alignment in the heap */
-       size += 7;
-       size &= ~7;
        emit_value (logbuffer, size);
        emit_value (logbuffer, num);
-       for (i = 0; i < num; ++i) {
+
+       uintptr_t last_offset = 0;
+
+       for (int i = 0; i < num; ++i) {
                emit_value (logbuffer, offsets [i] - last_offset);
                last_offset = offsets [i];
                emit_obj (logbuffer, refs [i]);
        }
-       //if (num)
-       //      printf ("obj: %p, klass: %s, refs: %d, size: %d\n", obj, name, (int)num, (int)size);
+
+       EXIT_LOG;
+
        return 0;
 }
 
@@ -1004,85 +1299,132 @@ static uint64_t last_hs_time = 0;
 static void
 heap_walk (MonoProfiler *profiler)
 {
-       int do_walk = 0;
-       uint64_t now;
-       LogBuffer *logbuffer;
        if (!do_heap_shot)
                return;
-       logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */
-       );
-       now = current_time ();
-       if (hs_mode_ms && (now - last_hs_time)/1000000 >= hs_mode_ms)
-               do_walk = 1;
+
+       gboolean do_walk = 0;
+       uint64_t now = current_time ();
+
+       if (hs_mode_ms && (now - last_hs_time) / 1000000 >= hs_mode_ms)
+               do_walk = TRUE;
        else if (hs_mode_gc && (gc_count % hs_mode_gc) == 0)
-               do_walk = 1;
+               do_walk = TRUE;
        else if (hs_mode_ondemand)
                do_walk = heapshot_requested;
        else if (!hs_mode_ms && !hs_mode_gc && profiler->last_gc_gen_started == mono_gc_max_generation ())
-               do_walk = 1;
+               do_walk = TRUE;
 
        if (!do_walk)
                return;
+
        heapshot_requested = 0;
-       emit_byte (logbuffer, TYPE_HEAP_START | TYPE_HEAP);
-       emit_time (logbuffer, now);
+
+       ENTER_LOG;
+
+       LogBuffer *logbuffer = ensure_logbuf (
+               EVENT_SIZE /* event */
+       );
+
+       emit_event (logbuffer, TYPE_HEAP_START | TYPE_HEAP);
+
+       EXIT_LOG;
+
        mono_gc_walk_heap (0, gc_reference, NULL);
-       logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */
+
+       ENTER_LOG;
+
+       LogBuffer *logbuffer = ensure_logbuf (
+               EVENT_SIZE /* event */
        );
+
        now = current_time ();
-       emit_byte (logbuffer, TYPE_HEAP_END | TYPE_HEAP);
-       emit_time (logbuffer, now);
+
+       emit_event (logbuffer, TYPE_HEAP_END | TYPE_HEAP);
+
+       EXIT_LOG;
+
        last_hs_time = now;
 }
 
 static void
-gc_event (MonoProfiler *profiler, MonoGCEvent ev, int generation) {
-       uint64_t now;
+gc_event (MonoProfiler *profiler, MonoGCEvent ev, int generation)
+{
+       ENTER_LOG;
+
        LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
-               LEB128_SIZE /* gc event */ +
-               LEB128_SIZE /* generation */
+               BYTE_SIZE /* gc event */ +
+               BYTE_SIZE /* generation */
        );
-       now = current_time ();
-       ENTER_LOG (logbuffer, "gcevent");
-       emit_byte (logbuffer, TYPE_GC_EVENT | TYPE_GC);
-       emit_time (logbuffer, now);
-       emit_value (logbuffer, ev);
-       emit_value (logbuffer, generation);
-       /* to deal with nested gen1 after gen0 started */
-       if (ev == MONO_GC_EVENT_START) {
+
+       emit_event (logbuffer, TYPE_GC_EVENT | TYPE_GC);
+       emit_byte (logbuffer, ev);
+       emit_byte (logbuffer, generation);
+
+       EXIT_LOG;
+
+       switch (ev) {
+       case MONO_GC_EVENT_START:
+               /* to deal with nested gen1 after gen0 started */
                profiler->last_gc_gen_started = generation;
+
                if (generation == mono_gc_max_generation ())
                        gc_count++;
-       }
-       if (ev == MONO_GC_EVENT_PRE_START_WORLD)
+               break;
+       case MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED:
+               /*
+                * Ensure that no thread can be in the middle of writing to
+                * a buffer when the world stops...
+                */
+               buffer_lock_excl ();
+               break;
+       case MONO_GC_EVENT_POST_STOP_WORLD:
+               /*
+                * ... So that we now have a consistent view of all buffers.
+                * This allows us to flush them. We need to do this because
+                * they may contain object allocation events that need to be
+                * committed to the log file before any object move events
+                * that will be produced during this GC.
+                */
+               sync_point (profiler, SYNC_POINT_WORLD_STOP);
+               break;
+       case MONO_GC_EVENT_PRE_START_WORLD:
                heap_walk (profiler);
-       EXIT_LOG (logbuffer);
-       if (ev == MONO_GC_EVENT_POST_START_WORLD)
-               safe_send (profiler, logbuffer);
-       //printf ("gc event %d for generation %d\n", ev, generation);
+               break;
+       case MONO_GC_EVENT_POST_START_WORLD_UNLOCKED:
+               /*
+                * Similarly, we must now make sure that any object moves
+                * written to the GC thread's buffer are flushed. Otherwise,
+                * object allocation events for certain addresses could come
+                * after the move events that made those addresses available.
+                */
+               sync_point_mark (profiler, SYNC_POINT_WORLD_START);
+
+               /*
+                * Finally, it is safe to allow other threads to write to
+                * their buffers again.
+                */
+               buffer_unlock_excl ();
+               break;
+       default:
+               break;
+       }
 }
 
 static void
-gc_resize (MonoProfiler *profiler, int64_t new_size) {
-       uint64_t now;
+gc_resize (MonoProfiler *profiler, int64_t new_size)
+{
+       ENTER_LOG;
+
        LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
                LEB128_SIZE /* new size */
        );
-       now = current_time ();
-       ENTER_LOG (logbuffer, "gcresize");
-       emit_byte (logbuffer, TYPE_GC_RESIZE | TYPE_GC);
-       emit_time (logbuffer, now);
+
+       emit_event (logbuffer, TYPE_GC_RESIZE | TYPE_GC);
        emit_value (logbuffer, new_size);
-       //printf ("gc resized to %lld\n", new_size);
-       EXIT_LOG (logbuffer);
+
+       EXIT_LOG;
 }
 
 // If you alter MAX_FRAMES, you may need to alter SAMPLE_BLOCK_SIZE too.
@@ -1130,87 +1472,86 @@ emit_bt (MonoProfiler *prof, LogBuffer *logbuffer, FrameData *data)
         */
        if (data->count > num_frames)
                printf ("bad num frames: %d\n", data->count);
-       emit_value (logbuffer, 0); /* flags */
        emit_value (logbuffer, data->count);
        //if (*p != data.count) {
        //      printf ("bad num frames enc at %d: %d -> %d\n", count, data.count, *p); printf ("frames end: %p->%p\n", p, logbuffer->cursor); exit(0);}
        while (data->count) {
-               emit_method_as_ptr (prof, logbuffer, data->methods [--data->count]);
+               emit_method (prof, logbuffer, data->methods [--data->count]);
        }
 }
 
 static void
 gc_alloc (MonoProfiler *prof, MonoObject *obj, MonoClass *klass)
 {
-       uint64_t now;
-       uintptr_t len;
-       int do_bt = (nocalls && InterlockedRead (&runtime_inited) && !notraces)? TYPE_ALLOC_BT: 0;
+       init_thread (TRUE);
+
+       int do_bt = (nocalls && InterlockedRead (&runtime_inited) && !notraces) ? TYPE_ALLOC_BT : 0;
        FrameData data;
-       LogBuffer *logbuffer;
-       len = mono_object_get_size (obj);
+       uintptr_t len = mono_object_get_size (obj);
        /* account for object alignment in the heap */
        len += 7;
        len &= ~7;
+
        if (do_bt)
                collect_bt (&data);
-       logbuffer = ensure_logbuf (
+
+       ENTER_LOG;
+
+       LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
                LEB128_SIZE /* klass */ +
                LEB128_SIZE /* obj */ +
                LEB128_SIZE /* size */ +
                (do_bt ? (
-                       LEB128_SIZE /* flags */ +
                        LEB128_SIZE /* count */ +
                        data.count * (
                                LEB128_SIZE /* method */
                        )
                ) : 0)
        );
-       now = current_time ();
-       ENTER_LOG (logbuffer, "gcalloc");
-       emit_byte (logbuffer, do_bt | TYPE_ALLOC);
-       emit_time (logbuffer, now);
+
+       emit_event (logbuffer, do_bt | TYPE_ALLOC);
        emit_ptr (logbuffer, klass);
        emit_obj (logbuffer, obj);
        emit_value (logbuffer, len);
+
        if (do_bt)
                emit_bt (prof, logbuffer, &data);
-       EXIT_LOG (logbuffer);
-       if (logbuffer->next)
-               safe_send (prof, logbuffer);
+
+       EXIT_LOG;
+
+       send_if_needed (prof);
+
        process_requests (prof);
-       //printf ("gc alloc %s at %p\n", mono_class_get_name (klass), obj);
 }
 
 static void
 gc_moves (MonoProfiler *prof, void **objects, int num)
 {
-       int i;
-       uint64_t now;
+       ENTER_LOG;
+
        LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
                LEB128_SIZE /* num */ +
                num * (
                        LEB128_SIZE /* object */
                )
        );
-       now = current_time ();
-       ENTER_LOG (logbuffer, "gcmove");
-       emit_byte (logbuffer, TYPE_GC_MOVE | TYPE_GC);
-       emit_time (logbuffer, now);
+
+       emit_event (logbuffer, TYPE_GC_MOVE | TYPE_GC);
        emit_value (logbuffer, num);
-       for (i = 0; i < num; ++i)
+
+       for (int i = 0; i < num; ++i)
                emit_obj (logbuffer, objects [i]);
-       //printf ("gc moved %d objects\n", num/2);
-       EXIT_LOG (logbuffer);
+
+       EXIT_LOG;
 }
 
 static void
 gc_roots (MonoProfiler *prof, int num, void **objects, int *root_types, uintptr_t *extra_info)
 {
-       int i;
+       ENTER_LOG;
+
        LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
                LEB128_SIZE /* num */ +
@@ -1221,38 +1562,39 @@ gc_roots (MonoProfiler *prof, int num, void **objects, int *root_types, uintptr_
                        LEB128_SIZE /* extra info */
                )
        );
-       ENTER_LOG (logbuffer, "gcroots");
-       emit_byte (logbuffer, TYPE_HEAP_ROOT | TYPE_HEAP);
+
+       emit_event (logbuffer, TYPE_HEAP_ROOT | TYPE_HEAP);
        emit_value (logbuffer, num);
        emit_value (logbuffer, mono_gc_collection_count (mono_gc_max_generation ()));
-       for (i = 0; i < num; ++i) {
+
+       for (int i = 0; i < num; ++i) {
                emit_obj (logbuffer, objects [i]);
-               emit_value (logbuffer, root_types [i]);
+               emit_byte (logbuffer, root_types [i]);
                emit_value (logbuffer, extra_info [i]);
        }
-       EXIT_LOG (logbuffer);
+
+       EXIT_LOG;
 }
 
 static void
 gc_handle (MonoProfiler *prof, int op, int type, uintptr_t handle, MonoObject *obj)
 {
        int do_bt = nocalls && InterlockedRead (&runtime_inited) && !notraces;
-       uint64_t now;
        FrameData data;
 
        if (do_bt)
                collect_bt (&data);
 
+       ENTER_LOG;
+
        LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
                LEB128_SIZE /* type */ +
                LEB128_SIZE /* handle */ +
                (op == MONO_PROFILER_GC_HANDLE_CREATED ? (
                        LEB128_SIZE /* obj */
                ) : 0) +
                (do_bt ? (
-                       LEB128_SIZE /* flags */ +
                        LEB128_SIZE /* count */ +
                        data.count * (
                                LEB128_SIZE /* method */
@@ -1260,17 +1602,13 @@ gc_handle (MonoProfiler *prof, int op, int type, uintptr_t handle, MonoObject *o
                ) : 0)
        );
 
-       now = current_time ();
-       ENTER_LOG (logbuffer, "gchandle");
-
        if (op == MONO_PROFILER_GC_HANDLE_CREATED)
-               emit_byte (logbuffer, (do_bt ? TYPE_GC_HANDLE_CREATED_BT : TYPE_GC_HANDLE_CREATED) | TYPE_GC);
+               emit_event (logbuffer, (do_bt ? TYPE_GC_HANDLE_CREATED_BT : TYPE_GC_HANDLE_CREATED) | TYPE_GC);
        else if (op == MONO_PROFILER_GC_HANDLE_DESTROYED)
-               emit_byte (logbuffer, (do_bt ? TYPE_GC_HANDLE_DESTROYED_BT : TYPE_GC_HANDLE_DESTROYED) | TYPE_GC);
+               emit_event (logbuffer, (do_bt ? TYPE_GC_HANDLE_DESTROYED_BT : TYPE_GC_HANDLE_DESTROYED) | TYPE_GC);
        else
                g_assert_not_reached ();
 
-       emit_time (logbuffer, now);
        emit_value (logbuffer, type);
        emit_value (logbuffer, handle);
 
@@ -1280,7 +1618,76 @@ gc_handle (MonoProfiler *prof, int op, int type, uintptr_t handle, MonoObject *o
        if (do_bt)
                emit_bt (prof, logbuffer, &data);
 
-       EXIT_LOG (logbuffer);
+       EXIT_LOG;
+
+       process_requests (prof);
+}
+
+static void
+finalize_begin (MonoProfiler *prof)
+{
+       ENTER_LOG;
+
+       LogBuffer *buf = ensure_logbuf (
+               EVENT_SIZE /* event */
+       );
+
+       emit_event (buf, TYPE_GC_FINALIZE_START | TYPE_GC);
+
+       EXIT_LOG;
+
+       process_requests (prof);
+}
+
+static void
+finalize_end (MonoProfiler *prof)
+{
+       ENTER_LOG;
+
+       LogBuffer *buf = ensure_logbuf (
+               EVENT_SIZE /* event */
+       );
+
+       emit_event (buf, TYPE_GC_FINALIZE_END | TYPE_GC);
+
+       EXIT_LOG;
+
+       process_requests (prof);
+}
+
+static void
+finalize_object_begin (MonoProfiler *prof, MonoObject *obj)
+{
+       ENTER_LOG;
+
+       LogBuffer *buf = ensure_logbuf (
+               EVENT_SIZE /* event */ +
+               LEB128_SIZE /* obj */
+       );
+
+       emit_event (buf, TYPE_GC_FINALIZE_OBJECT_START | TYPE_GC);
+       emit_obj (buf, obj);
+
+       EXIT_LOG;
+
+       process_requests (prof);
+}
+
+static void
+finalize_object_end (MonoProfiler *prof, MonoObject *obj)
+{
+       ENTER_LOG;
+
+       LogBuffer *buf = ensure_logbuf (
+               EVENT_SIZE /* event */ +
+               LEB128_SIZE /* obj */
+       );
+
+       emit_event (buf, TYPE_GC_FINALIZE_OBJECT_END | TYPE_GC);
+       emit_obj (buf, obj);
+
+       EXIT_LOG;
+
        process_requests (prof);
 }
 
@@ -1323,35 +1730,31 @@ type_name (MonoClass *klass)
 static void
 image_loaded (MonoProfiler *prof, MonoImage *image, int result)
 {
-       uint64_t now;
-       const char *name;
-       int nlen;
-       LogBuffer *logbuffer;
        if (result != MONO_PROFILE_OK)
                return;
-       name = mono_image_get_filename (image);
-       nlen = strlen (name) + 1;
-       logbuffer = ensure_logbuf (
+
+       const char *name = mono_image_get_filename (image);
+       int nlen = strlen (name) + 1;
+
+       ENTER_LOG;
+
+       LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
-               EVENT_SIZE /* type */ +
+               BYTE_SIZE /* type */ +
                LEB128_SIZE /* image */ +
-               LEB128_SIZE /* flags */ +
                nlen /* name */
        );
-       now = current_time ();
-       ENTER_LOG (logbuffer, "image");
-       emit_byte (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
-       emit_time (logbuffer, now);
+
+       emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
        emit_byte (logbuffer, TYPE_IMAGE);
        emit_ptr (logbuffer, image);
-       emit_value (logbuffer, 0); /* flags */
        memcpy (logbuffer->cursor, name, nlen);
        logbuffer->cursor += nlen;
-       //printf ("loaded image %p (%s)\n", image, name);
-       EXIT_LOG (logbuffer);
-       if (logbuffer->next)
-               safe_send (prof, logbuffer);
+
+       EXIT_LOG;
+
+       send_if_needed (prof);
+
        process_requests (prof);
 
        InterlockedIncrement (&image_loads);
@@ -1362,28 +1765,25 @@ image_unloaded (MonoProfiler *prof, MonoImage *image)
 {
        const char *name = mono_image_get_filename (image);
        int nlen = strlen (name) + 1;
+
+       ENTER_LOG;
+
        LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
-               EVENT_SIZE /* type */ +
+               BYTE_SIZE /* type */ +
                LEB128_SIZE /* image */ +
-               LEB128_SIZE /* flags */ +
                nlen /* name */
        );
-       uint64_t now = current_time ();
 
-       ENTER_LOG (logbuffer, "image-unload");
-       emit_byte (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
-       emit_time (logbuffer, now);
+       emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
        emit_byte (logbuffer, TYPE_IMAGE);
        emit_ptr (logbuffer, image);
-       emit_value (logbuffer, 0); /* flags */
        memcpy (logbuffer->cursor, name, nlen);
        logbuffer->cursor += nlen;
-       EXIT_LOG (logbuffer);
 
-       if (logbuffer->next)
-               safe_send (prof, logbuffer);
+       EXIT_LOG;
+
+       send_if_needed (prof);
 
        process_requests (prof);
 
@@ -1398,30 +1798,27 @@ assembly_loaded (MonoProfiler *prof, MonoAssembly *assembly, int result)
 
        char *name = mono_stringify_assembly_name (mono_assembly_get_name (assembly));
        int nlen = strlen (name) + 1;
+
+       ENTER_LOG;
+
        LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
-               EVENT_SIZE /* type */ +
+               BYTE_SIZE /* type */ +
                LEB128_SIZE /* assembly */ +
-               LEB128_SIZE /* flags */ +
                nlen /* name */
        );
-       uint64_t now = current_time ();
 
-       ENTER_LOG (logbuffer, "assembly-load");
-       emit_byte (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
-       emit_time (logbuffer, now);
+       emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
        emit_byte (logbuffer, TYPE_ASSEMBLY);
        emit_ptr (logbuffer, assembly);
-       emit_value (logbuffer, 0); /* flags */
        memcpy (logbuffer->cursor, name, nlen);
        logbuffer->cursor += nlen;
-       EXIT_LOG (logbuffer);
+
+       EXIT_LOG;
 
        mono_free (name);
 
-       if (logbuffer->next)
-               safe_send (prof, logbuffer);
+       send_if_needed (prof);
 
        process_requests (prof);
 
@@ -1433,30 +1830,27 @@ assembly_unloaded (MonoProfiler *prof, MonoAssembly *assembly)
 {
        char *name = mono_stringify_assembly_name (mono_assembly_get_name (assembly));
        int nlen = strlen (name) + 1;
+
+       ENTER_LOG;
+
        LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
-               EVENT_SIZE /* type */ +
+               BYTE_SIZE /* type */ +
                LEB128_SIZE /* assembly */ +
-               LEB128_SIZE /* flags */ +
                nlen /* name */
        );
-       uint64_t now = current_time ();
 
-       ENTER_LOG (logbuffer, "assembly-unload");
-       emit_byte (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
-       emit_time (logbuffer, now);
+       emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
        emit_byte (logbuffer, TYPE_ASSEMBLY);
        emit_ptr (logbuffer, assembly);
-       emit_value (logbuffer, 0); /* flags */
        memcpy (logbuffer->cursor, name, nlen);
        logbuffer->cursor += nlen;
-       EXIT_LOG (logbuffer);
+
+       EXIT_LOG;
 
        mono_free (name);
 
-       if (logbuffer->next)
-               safe_send (prof, logbuffer);
+       send_if_needed (prof);
 
        process_requests (prof);
 
@@ -1466,46 +1860,45 @@ assembly_unloaded (MonoProfiler *prof, MonoAssembly *assembly)
 static void
 class_loaded (MonoProfiler *prof, MonoClass *klass, int result)
 {
-       uint64_t now;
-       char *name;
-       int nlen;
-       MonoImage *image;
-       LogBuffer *logbuffer;
        if (result != MONO_PROFILE_OK)
                return;
+
+       char *name;
+
        if (InterlockedRead (&runtime_inited))
                name = mono_type_get_name (mono_class_get_type (klass));
        else
                name = type_name (klass);
-       nlen = strlen (name) + 1;
-       image = mono_class_get_image (klass);
-       logbuffer = ensure_logbuf (
+
+       int nlen = strlen (name) + 1;
+       MonoImage *image = mono_class_get_image (klass);
+
+       ENTER_LOG;
+
+       LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
-               EVENT_SIZE /* type */ +
+               BYTE_SIZE /* type */ +
                LEB128_SIZE /* klass */ +
                LEB128_SIZE /* image */ +
-               LEB128_SIZE /* flags */ +
                nlen /* name */
        );
-       now = current_time ();
-       ENTER_LOG (logbuffer, "class");
-       emit_byte (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
-       emit_time (logbuffer, now);
+
+       emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
        emit_byte (logbuffer, TYPE_CLASS);
        emit_ptr (logbuffer, klass);
        emit_ptr (logbuffer, image);
-       emit_value (logbuffer, 0); /* flags */
        memcpy (logbuffer->cursor, name, nlen);
        logbuffer->cursor += nlen;
-       //printf ("loaded class %p (%s)\n", klass, name);
+
+       EXIT_LOG;
+
        if (runtime_inited)
                mono_free (name);
        else
                free (name);
-       EXIT_LOG (logbuffer);
-       if (logbuffer->next)
-               safe_send (prof, logbuffer);
+
+       send_if_needed (prof);
+
        process_requests (prof);
 
        InterlockedIncrement (&class_loads);
@@ -1523,35 +1916,32 @@ class_unloaded (MonoProfiler *prof, MonoClass *klass)
 
        int nlen = strlen (name) + 1;
        MonoImage *image = mono_class_get_image (klass);
+
+       ENTER_LOG;
+
        LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
-               EVENT_SIZE /* type */ +
+               BYTE_SIZE /* type */ +
                LEB128_SIZE /* klass */ +
                LEB128_SIZE /* image */ +
-               LEB128_SIZE /* flags */ +
                nlen /* name */
        );
-       uint64_t now = current_time ();
 
-       ENTER_LOG (logbuffer, "class-unload");
-       emit_byte (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
-       emit_time (logbuffer, now);
+       emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
        emit_byte (logbuffer, TYPE_CLASS);
        emit_ptr (logbuffer, klass);
        emit_ptr (logbuffer, image);
-       emit_value (logbuffer, 0); /* flags */
        memcpy (logbuffer->cursor, name, nlen);
        logbuffer->cursor += nlen;
-       EXIT_LOG (logbuffer);
+
+       EXIT_LOG;
 
        if (runtime_inited)
                mono_free (name);
        else
                free (name);
 
-       if (logbuffer->next)
-               safe_send (prof, logbuffer);
+       send_if_needed (prof);
 
        process_requests (prof);
 
@@ -1565,24 +1955,25 @@ static void process_method_enter_coverage (MonoProfiler *prof, MonoMethod *metho
 static void
 method_enter (MonoProfiler *prof, MonoMethod *method)
 {
-       uint64_t now = current_time ();
+#ifndef DISABLE_HELPER_THREAD
+       process_method_enter_coverage (prof, method);
+#endif /* DISABLE_HELPER_THREAD */
+
+       if (PROF_TLS_GET ()->call_depth++ <= max_call_depth) {
+               ENTER_LOG;
+
+               LogBuffer *logbuffer = ensure_logbuf (
+                       EVENT_SIZE /* event */ +
+                       LEB128_SIZE /* method */
+               );
 
-#ifndef DISABLE_HELPER_THREAD
-       process_method_enter_coverage (prof, method);
-#endif /* DISABLE_HELPER_THREAD */
+               emit_event (logbuffer, TYPE_ENTER | TYPE_METHOD);
+               emit_method (prof, logbuffer, method);
 
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
-               LEB128_SIZE /* method */
-       );
-       if (logbuffer->call_depth++ > max_call_depth)
-               return;
-       ENTER_LOG (logbuffer, "enter");
-       emit_byte (logbuffer, TYPE_ENTER | TYPE_METHOD);
-       emit_time (logbuffer, now);
-       emit_method (prof, logbuffer, method);
-       EXIT_LOG (logbuffer);
+               EXIT_LOG;
+       }
+
+       send_if_needed (prof);
 
        process_requests (prof);
 }
@@ -1590,45 +1981,44 @@ method_enter (MonoProfiler *prof, MonoMethod *method)
 static void
 method_leave (MonoProfiler *prof, MonoMethod *method)
 {
-       uint64_t now;
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
-               LEB128_SIZE /* method */
-       );
-       if (--logbuffer->call_depth > max_call_depth)
-               return;
-       now = current_time ();
-       ENTER_LOG (logbuffer, "leave");
-       emit_byte (logbuffer, TYPE_LEAVE | TYPE_METHOD);
-       emit_time (logbuffer, now);
-       emit_method (prof, logbuffer, method);
-       EXIT_LOG (logbuffer);
-       if (logbuffer->next)
-               safe_send (prof, logbuffer);
+       if (--PROF_TLS_GET ()->call_depth <= max_call_depth) {
+               ENTER_LOG;
+
+               LogBuffer *logbuffer = ensure_logbuf (
+                       EVENT_SIZE /* event */ +
+                       LEB128_SIZE /* method */
+               );
+
+               emit_event (logbuffer, TYPE_LEAVE | TYPE_METHOD);
+               emit_method (prof, logbuffer, method);
+
+               EXIT_LOG;
+       }
+
+       send_if_needed (prof);
+
        process_requests (prof);
 }
 
 static void
 method_exc_leave (MonoProfiler *prof, MonoMethod *method)
 {
-       uint64_t now;
-       LogBuffer *logbuffer;
-       if (nocalls)
-               return;
-       logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
-               LEB128_SIZE /* method */
-       );
-       if (--logbuffer->call_depth > max_call_depth)
-               return;
-       now = current_time ();
-       ENTER_LOG (logbuffer, "eleave");
-       emit_byte (logbuffer, TYPE_EXC_LEAVE | TYPE_METHOD);
-       emit_time (logbuffer, now);
-       emit_method (prof, logbuffer, method);
-       EXIT_LOG (logbuffer);
+       if (!nocalls && --PROF_TLS_GET ()->call_depth <= max_call_depth) {
+               ENTER_LOG;
+
+               LogBuffer *logbuffer = ensure_logbuf (
+                       EVENT_SIZE /* event */ +
+                       LEB128_SIZE /* method */
+               );
+
+               emit_event (logbuffer, TYPE_EXC_LEAVE | TYPE_METHOD);
+               emit_method (prof, logbuffer, method);
+
+               EXIT_LOG;
+       }
+
+       send_if_needed (prof);
+
        process_requests (prof);
 }
 
@@ -1646,93 +2036,95 @@ method_jitted (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *ji, int resu
 static void
 code_buffer_new (MonoProfiler *prof, void *buffer, int size, MonoProfilerCodeBufferType type, void *data)
 {
-       uint64_t now;
-       int nlen;
        char *name;
-       LogBuffer *logbuffer;
+       int nlen;
+
        if (type == MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE) {
-               name = (char *)data;
+               name = (char *) data;
                nlen = strlen (name) + 1;
        } else {
                name = NULL;
                nlen = 0;
        }
-       logbuffer = ensure_logbuf (
+
+       ENTER_LOG;
+
+       LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
-               LEB128_SIZE /* type */ +
+               BYTE_SIZE /* type */ +
                LEB128_SIZE /* buffer */ +
                LEB128_SIZE /* size */ +
                (name ? (
                        nlen /* name */
                ) : 0)
        );
-       now = current_time ();
-       ENTER_LOG (logbuffer, "code buffer");
-       emit_byte (logbuffer, TYPE_JITHELPER | TYPE_RUNTIME);
-       emit_time (logbuffer, now);
-       emit_value (logbuffer, type);
+
+       emit_event (logbuffer, TYPE_JITHELPER | TYPE_RUNTIME);
+       emit_byte (logbuffer, type);
        emit_ptr (logbuffer, buffer);
        emit_value (logbuffer, size);
+
        if (name) {
                memcpy (logbuffer->cursor, name, nlen);
                logbuffer->cursor += nlen;
        }
-       EXIT_LOG (logbuffer);
+
+       EXIT_LOG;
+
        process_requests (prof);
 }
 
 static void
 throw_exc (MonoProfiler *prof, MonoObject *object)
 {
-       int do_bt = (nocalls && InterlockedRead (&runtime_inited) && !notraces)? TYPE_EXCEPTION_BT: 0;
-       uint64_t now;
+       int do_bt = (nocalls && InterlockedRead (&runtime_inited) && !notraces) ? TYPE_EXCEPTION_BT : 0;
        FrameData data;
-       LogBuffer *logbuffer;
+
        if (do_bt)
                collect_bt (&data);
-       logbuffer = ensure_logbuf (
+
+       ENTER_LOG;
+
+       LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
                LEB128_SIZE /* object */ +
                (do_bt ? (
-                       LEB128_SIZE /* flags */ +
                        LEB128_SIZE /* count */ +
                        data.count * (
                                LEB128_SIZE /* method */
                        )
                ) : 0)
        );
-       now = current_time ();
-       ENTER_LOG (logbuffer, "throw");
-       emit_byte (logbuffer, do_bt | TYPE_EXCEPTION);
-       emit_time (logbuffer, now);
+
+       emit_event (logbuffer, do_bt | TYPE_EXCEPTION);
        emit_obj (logbuffer, object);
+
        if (do_bt)
                emit_bt (prof, logbuffer, &data);
-       EXIT_LOG (logbuffer);
+
+       EXIT_LOG;
+
        process_requests (prof);
 }
 
 static void
 clause_exc (MonoProfiler *prof, MonoMethod *method, int clause_type, int clause_num)
 {
-       uint64_t now;
+       ENTER_LOG;
+
        LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
-               LEB128_SIZE /* clause type */ +
+               BYTE_SIZE /* clause type */ +
                LEB128_SIZE /* clause num */ +
                LEB128_SIZE /* method */
        );
-       now = current_time ();
-       ENTER_LOG (logbuffer, "clause");
-       emit_byte (logbuffer, TYPE_EXCEPTION | TYPE_CLAUSE);
-       emit_time (logbuffer, now);
-       emit_value (logbuffer, clause_type);
+
+       emit_event (logbuffer, TYPE_EXCEPTION | TYPE_CLAUSE);
+       emit_byte (logbuffer, clause_type);
        emit_value (logbuffer, clause_num);
        emit_method (prof, logbuffer, method);
-       EXIT_LOG (logbuffer);
+
+       EXIT_LOG;
 
        process_requests (prof);
 }
@@ -1740,60 +2132,56 @@ clause_exc (MonoProfiler *prof, MonoMethod *method, int clause_type, int clause_
 static void
 monitor_event (MonoProfiler *profiler, MonoObject *object, MonoProfilerMonitorEvent event)
 {
-       int do_bt = (nocalls && InterlockedRead (&runtime_inited) && !notraces && event == MONO_PROFILER_MONITOR_CONTENTION)? TYPE_MONITOR_BT: 0;
-       uint64_t now;
+       int do_bt = (nocalls && InterlockedRead (&runtime_inited) && !notraces && event == MONO_PROFILER_MONITOR_CONTENTION) ? TYPE_MONITOR_BT : 0;
        FrameData data;
-       LogBuffer *logbuffer;
+
        if (do_bt)
                collect_bt (&data);
-       logbuffer = ensure_logbuf (
+
+       ENTER_LOG;
+
+       LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
                LEB128_SIZE /* object */ +
                (do_bt ? (
-                       LEB128_SIZE /* flags */ +
                        LEB128_SIZE /* count */ +
                        data.count * (
                                LEB128_SIZE /* method */
                        )
                ) : 0)
        );
-       now = current_time ();
-       ENTER_LOG (logbuffer, "monitor");
-       emit_byte (logbuffer, (event << 4) | do_bt | TYPE_MONITOR);
-       emit_time (logbuffer, now);
+
+       emit_event (logbuffer, (event << 4) | do_bt | TYPE_MONITOR);
        emit_obj (logbuffer, object);
+
        if (do_bt)
                emit_bt (profiler, logbuffer, &data);
-       EXIT_LOG (logbuffer);
+
+       EXIT_LOG;
+
        process_requests (profiler);
 }
 
 static void
 thread_start (MonoProfiler *prof, uintptr_t tid)
 {
-       //printf ("thread start %p\n", (void*)tid);
-       init_thread ();
+       init_thread (TRUE);
+
+       ENTER_LOG;
 
        LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
-               EVENT_SIZE /* type */ +
-               LEB128_SIZE /* tid */ +
-               LEB128_SIZE /* flags */
+               BYTE_SIZE /* type */ +
+               LEB128_SIZE /* tid */
        );
-       uint64_t now = current_time ();
 
-       ENTER_LOG (logbuffer, "thread-start");
-       emit_byte (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
-       emit_time (logbuffer, now);
+       emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
        emit_byte (logbuffer, TYPE_THREAD);
        emit_ptr (logbuffer, (void*) tid);
-       emit_value (logbuffer, 0); /* flags */
-       EXIT_LOG (logbuffer);
 
-       if (logbuffer->next)
-               safe_send (prof, logbuffer);
+       EXIT_LOG;
+
+       send_if_needed (prof);
 
        process_requests (prof);
 
@@ -1803,31 +2191,23 @@ thread_start (MonoProfiler *prof, uintptr_t tid)
 static void
 thread_end (MonoProfiler *prof, uintptr_t tid)
 {
-       if (TLS_GET (LogBuffer, tlsbuffer)) {
-               LogBuffer *logbuffer = ensure_logbuf (
-                       EVENT_SIZE /* event */ +
-                       LEB128_SIZE /* time */ +
-                       EVENT_SIZE /* type */ +
-                       LEB128_SIZE /* tid */ +
-                       LEB128_SIZE /* flags */
-               );
-               uint64_t now = current_time ();
+       ENTER_LOG;
 
-               ENTER_LOG (logbuffer, "thread-end");
-               emit_byte (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
-               emit_time (logbuffer, now);
-               emit_byte (logbuffer, TYPE_THREAD);
-               emit_ptr (logbuffer, (void*) tid);
-               emit_value (logbuffer, 0); /* flags */
-               EXIT_LOG (logbuffer);
+       LogBuffer *logbuffer = ensure_logbuf (
+               EVENT_SIZE /* event */ +
+               BYTE_SIZE /* type */ +
+               LEB128_SIZE /* tid */
+       );
+
+       emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
+       emit_byte (logbuffer, TYPE_THREAD);
+       emit_ptr (logbuffer, (void*) tid);
 
-               send_buffer (prof, TLS_GET (GPtrArray, tlsmethodlist), logbuffer);
+       EXIT_LOG;
 
-               /* Don't process requests as the thread is detached from the runtime. */
-       }
+       // Don't process requests as the thread is detached from the runtime.
 
-       TLS_SET (tlsbuffer, NULL);
-       TLS_SET (tlsmethodlist, NULL);
+       remove_thread (prof, PROF_TLS_GET (), TRUE);
 
        InterlockedIncrement (&thread_ends);
 }
@@ -1838,25 +2218,21 @@ domain_loaded (MonoProfiler *prof, MonoDomain *domain, int result)
        if (result != MONO_PROFILE_OK)
                return;
 
+       ENTER_LOG;
+
        LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
-               EVENT_SIZE /* type */ +
-               LEB128_SIZE /* domain id */ +
-               LEB128_SIZE /* flags */
+               BYTE_SIZE /* type */ +
+               LEB128_SIZE /* domain id */
        );
-       uint64_t now = current_time ();
 
-       ENTER_LOG (logbuffer, "domain-start");
-       emit_byte (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
-       emit_time (logbuffer, now);
+       emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
        emit_byte (logbuffer, TYPE_DOMAIN);
        emit_ptr (logbuffer, (void*)(uintptr_t) mono_domain_get_id (domain));
-       emit_value (logbuffer, 0); /* flags */
-       EXIT_LOG (logbuffer);
 
-       if (logbuffer->next)
-               safe_send (prof, logbuffer);
+       EXIT_LOG;
+
+       send_if_needed (prof);
 
        process_requests (prof);
 
@@ -1866,25 +2242,21 @@ domain_loaded (MonoProfiler *prof, MonoDomain *domain, int result)
 static void
 domain_unloaded (MonoProfiler *prof, MonoDomain *domain)
 {
+       ENTER_LOG;
+
        LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
-               EVENT_SIZE /* type */ +
-               LEB128_SIZE /* domain id */ +
-               LEB128_SIZE /* flags */
+               BYTE_SIZE /* type */ +
+               LEB128_SIZE /* domain id */
        );
-       uint64_t now = current_time ();
 
-       ENTER_LOG (logbuffer, "domain-end");
-       emit_byte (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
-       emit_time (logbuffer, now);
+       emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
        emit_byte (logbuffer, TYPE_DOMAIN);
        emit_ptr (logbuffer, (void*)(uintptr_t) mono_domain_get_id (domain));
-       emit_value (logbuffer, 0); /* flags */
-       EXIT_LOG (logbuffer);
 
-       if (logbuffer->next)
-               safe_send (prof, logbuffer);
+       EXIT_LOG;
+
+       send_if_needed (prof);
 
        process_requests (prof);
 
@@ -1895,28 +2267,25 @@ static void
 domain_name (MonoProfiler *prof, MonoDomain *domain, const char *name)
 {
        int nlen = strlen (name) + 1;
+
+       ENTER_LOG;
+
        LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
-               EVENT_SIZE /* type */ +
+               BYTE_SIZE /* type */ +
                LEB128_SIZE /* domain id */ +
-               LEB128_SIZE /* flags */ +
                nlen /* name */
        );
-       uint64_t now = current_time ();
 
-       ENTER_LOG (logbuffer, "domain-name");
-       emit_byte (logbuffer, TYPE_METADATA);
-       emit_time (logbuffer, now);
+       emit_event (logbuffer, TYPE_METADATA);
        emit_byte (logbuffer, TYPE_DOMAIN);
        emit_ptr (logbuffer, (void*)(uintptr_t) mono_domain_get_id (domain));
-       emit_value (logbuffer, 0); /* flags */
        memcpy (logbuffer->cursor, name, nlen);
        logbuffer->cursor += nlen;
-       EXIT_LOG (logbuffer);
 
-       if (logbuffer->next)
-               safe_send (prof, logbuffer);
+       EXIT_LOG;
+
+       send_if_needed (prof);
 
        process_requests (prof);
 }
@@ -1924,27 +2293,23 @@ domain_name (MonoProfiler *prof, MonoDomain *domain, const char *name)
 static void
 context_loaded (MonoProfiler *prof, MonoAppContext *context)
 {
+       ENTER_LOG;
+
        LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
-               EVENT_SIZE /* type */ +
+               BYTE_SIZE /* type */ +
                LEB128_SIZE /* context id */ +
-               LEB128_SIZE /* flags */ +
                LEB128_SIZE /* domain id */
        );
-       uint64_t now = current_time ();
 
-       ENTER_LOG (logbuffer, "context-start");
-       emit_byte (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
-       emit_time (logbuffer, now);
+       emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
        emit_byte (logbuffer, TYPE_CONTEXT);
        emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_id (context));
-       emit_value (logbuffer, 0); /* flags */
        emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_domain_id (context));
-       EXIT_LOG (logbuffer);
 
-       if (logbuffer->next)
-               safe_send (prof, logbuffer);
+       EXIT_LOG;
+
+       send_if_needed (prof);
 
        process_requests (prof);
 
@@ -1954,27 +2319,23 @@ context_loaded (MonoProfiler *prof, MonoAppContext *context)
 static void
 context_unloaded (MonoProfiler *prof, MonoAppContext *context)
 {
+       ENTER_LOG;
+
        LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
-               EVENT_SIZE /* type */ +
+               BYTE_SIZE /* type */ +
                LEB128_SIZE /* context id */ +
-               LEB128_SIZE /* flags */ +
                LEB128_SIZE /* domain id */
        );
-       uint64_t now = current_time ();
 
-       ENTER_LOG (logbuffer, "context-end");
-       emit_byte (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
-       emit_time (logbuffer, now);
+       emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
        emit_byte (logbuffer, TYPE_CONTEXT);
        emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_id (context));
-       emit_value (logbuffer, 0); /* flags */
        emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_domain_id (context));
-       EXIT_LOG (logbuffer);
 
-       if (logbuffer->next)
-               safe_send (prof, logbuffer);
+       EXIT_LOG;
+
+       send_if_needed (prof);
 
        process_requests (prof);
 
@@ -1985,29 +2346,25 @@ static void
 thread_name (MonoProfiler *prof, uintptr_t tid, const char *name)
 {
        int len = strlen (name) + 1;
-       uint64_t now;
-       LogBuffer *logbuffer;
-       logbuffer = ensure_logbuf (
+
+       ENTER_LOG;
+
+       LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
-               EVENT_SIZE /* type */ +
+               BYTE_SIZE /* type */ +
                LEB128_SIZE /* tid */ +
-               LEB128_SIZE /* flags */ +
                len /* name */
        );
-       now = current_time ();
-       ENTER_LOG (logbuffer, "tname");
-       emit_byte (logbuffer, TYPE_METADATA);
-       emit_time (logbuffer, now);
+
+       emit_event (logbuffer, TYPE_METADATA);
        emit_byte (logbuffer, TYPE_THREAD);
        emit_ptr (logbuffer, (void*)tid);
-       emit_value (logbuffer, 0); /* flags */
        memcpy (logbuffer->cursor, name, len);
        logbuffer->cursor += len;
-       EXIT_LOG (logbuffer);
 
-       if (logbuffer->next)
-               safe_send (prof, logbuffer);
+       EXIT_LOG;
+
+       send_if_needed (prof);
 
        process_requests (prof);
 }
@@ -2022,7 +2379,7 @@ typedef struct {
 typedef struct {
        MonoLockFreeQueueNode node;
        MonoProfiler *prof;
-       uint64_t elapsed;
+       uint64_t time;
        uintptr_t tid;
        void *ip;
        int count;
@@ -2079,8 +2436,6 @@ mono_sample_hit (MonoProfiler *profiler, unsigned char *ip, void *context)
 
        InterlockedIncrement (&sample_hits);
 
-       uint64_t now = current_time ();
-
        SampleHit *sample = (SampleHit *) mono_lock_free_queue_dequeue (&profiler->sample_reuse_queue);
 
        if (!sample) {
@@ -2101,16 +2456,14 @@ mono_sample_hit (MonoProfiler *profiler, unsigned char *ip, void *context)
        sample->count = 0;
        mono_stack_walk_async_safe (&async_walk_stack, context, sample);
 
-       uintptr_t elapsed = (now - profiler->startup_time) / 10000;
-
-       sample->elapsed = elapsed;
+       sample->time = current_time ();
        sample->tid = thread_id ();
        sample->ip = ip;
 
        if (do_debug) {
                int len;
                char buf [256];
-               snprintf (buf, sizeof (buf), "hit at %p in thread %p after %llu ms\n", ip, (void *) thread_id (), (unsigned long long int) elapsed / 100);
+               snprintf (buf, sizeof (buf), "hit at %p in thread %p after %llu ms\n", ip, (void *) sample->tid, (unsigned long long int) ((sample->time - profiler->startup_time) / 10000 / 100));
                len = strlen (buf);
                ign_res (write (2, buf, len));
        }
@@ -2177,46 +2530,50 @@ add_code_pointer (uintptr_t ip)
 static void
 dump_ubin (const char *filename, uintptr_t load_addr, uint64_t offset, uintptr_t size)
 {
-       uint64_t now;
-       LogBuffer *logbuffer;
-       int len;
-       len = strlen (filename) + 1;
-       now = current_time ();
-       logbuffer = ensure_logbuf (
+       int len = strlen (filename) + 1;
+
+       ENTER_LOG;
+
+       LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */ +
                LEB128_SIZE /* load address */ +
                LEB128_SIZE /* offset */ +
                LEB128_SIZE /* size */ +
                nlen /* file name */
        );
-       emit_byte (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_UBIN);
-       emit_time (logbuffer, now);
+
+       emit_event (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_UBIN);
        emit_svalue (logbuffer, load_addr);
        emit_uvalue (logbuffer, offset);
        emit_uvalue (logbuffer, size);
        memcpy (logbuffer->cursor, filename, len);
        logbuffer->cursor += len;
+
+       EXIT_LOG;
 }
 #endif
 
 static void
 dump_usym (const char *name, uintptr_t value, uintptr_t size)
 {
-       LogBuffer *logbuffer;
-       int len;
-       len = strlen (name) + 1;
-       logbuffer = ensure_logbuf (
+       int len = strlen (name) + 1;
+
+       ENTER_LOG;
+
+       LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
                LEB128_SIZE /* value */ +
                LEB128_SIZE /* size */ +
                len /* name */
        );
-       emit_byte (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_USYM);
+
+       emit_event (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_USYM);
        emit_ptr (logbuffer, (void*)value);
        emit_value (logbuffer, size);
        memcpy (logbuffer->cursor, name, len);
        logbuffer->cursor += len;
+
+       EXIT_LOG;
 }
 
 /* ELF code crashes on some systems. */
@@ -2592,7 +2949,6 @@ setup_perf_map (PerfData *perf)
 static void
 dump_perf_hits (MonoProfiler *prof, void *buf, int size)
 {
-       LogBuffer *logbuffer;
        int count = 1;
        int mbt_count = 0;
        void *end = (char*)buf + size;
@@ -2612,10 +2968,12 @@ dump_perf_hits (MonoProfiler *prof, void *buf, int size)
                /*ip = (void*)s->ip;
                printf ("sample: %d, size: %d, ip: %p (%s), timestamp: %llu, nframes: %llu\n",
                        s->h.type, s->h.size, ip, symbol_for (ip), s->timestamp, s->nframes);*/
-               logbuffer = ensure_logbuf (
+
+               ENTER_LOG;
+
+               LogBuffer *logbuffer = ensure_logbuf (
                        EVENT_SIZE /* event */ +
-                       LEB128_SIZE /* type */ +
-                       LEB128_SIZE /* time */ +
+                       BYTE_SIZE /* type */ +
                        LEB128_SIZE /* tid */ +
                        LEB128_SIZE /* count */ +
                        count * (
@@ -2623,14 +2981,12 @@ dump_perf_hits (MonoProfiler *prof, void *buf, int size)
                        ) +
                        LEB128_SIZE /* managed count */ +
                        mbt_count * (
-                               LEB128_SIZE /* method */ +
-                               LEB128_SIZE /* il offset */ +
-                               LEB128_SIZE /* native offset */
+                               LEB128_SIZE /* method */
                        )
                );
-               emit_byte (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_HIT);
-               emit_value (logbuffer, sample_type);
-               emit_uvalue (logbuffer, s->timestamp - prof->startup_time);
+
+               emit_event (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_HIT);
+               emit_byte (logbuffer, sample_type);
                /*
                 * No useful thread ID to write here, since throughout the
                 * profiler we use pthread_self () but the ID we get from
@@ -2639,9 +2995,12 @@ dump_perf_hits (MonoProfiler *prof, void *buf, int size)
                emit_ptr (logbuffer, 0);
                emit_value (logbuffer, count);
                emit_ptr (logbuffer, (void*)(uintptr_t)s->ip);
-               add_code_pointer (s->ip);
                /* no support here yet for the managed backtrace */
                emit_uvalue (logbuffer, mbt_count);
+
+               EXIT_LOG;
+
+               add_code_pointer (s->ip);
                buf = (char*)buf + s->h.size;
                samples++;
        }
@@ -2833,10 +3192,9 @@ counters_init (MonoProfiler *profiler)
 }
 
 static void
-counters_emit (MonoProfiler *profiler, gboolean threadless)
+counters_emit (MonoProfiler *profiler)
 {
        MonoCounterAgent *agent;
-       LogBuffer *logbuffer;
        int len = 0;
        int size =
                EVENT_SIZE /* event */ +
@@ -2855,9 +3213,9 @@ counters_emit (MonoProfiler *profiler, gboolean threadless)
                size +=
                        LEB128_SIZE /* section */ +
                        strlen (mono_counter_get_name (agent->counter)) + 1 /* name */ +
-                       LEB128_SIZE /* type */ +
-                       LEB128_SIZE /* unit */ +
-                       LEB128_SIZE /* variance */ +
+                       BYTE_SIZE /* type */ +
+                       BYTE_SIZE /* unit */ +
+                       BYTE_SIZE /* variance */ +
                        LEB128_SIZE /* index */
                ;
 
@@ -2869,11 +3227,13 @@ counters_emit (MonoProfiler *profiler, gboolean threadless)
                return;
        }
 
-       logbuffer = ensure_logbuf (size);
+       ENTER_LOG;
+
+       LogBuffer *logbuffer = ensure_logbuf (size);
 
-       ENTER_LOG (logbuffer, "counters");
-       emit_byte (logbuffer, TYPE_SAMPLE_COUNTERS_DESC | TYPE_SAMPLE);
+       emit_event (logbuffer, TYPE_SAMPLE_COUNTERS_DESC | TYPE_SAMPLE);
        emit_value (logbuffer, len);
+
        for (agent = counters; agent; agent = agent->next) {
                const char *name;
 
@@ -2883,29 +3243,24 @@ counters_emit (MonoProfiler *profiler, gboolean threadless)
                name = mono_counter_get_name (agent->counter);
                emit_value (logbuffer, mono_counter_get_section (agent->counter));
                emit_string (logbuffer, name, strlen (name) + 1);
-               emit_value (logbuffer, mono_counter_get_type (agent->counter));
-               emit_value (logbuffer, mono_counter_get_unit (agent->counter));
-               emit_value (logbuffer, mono_counter_get_variance (agent->counter));
+               emit_byte (logbuffer, mono_counter_get_type (agent->counter));
+               emit_byte (logbuffer, mono_counter_get_unit (agent->counter));
+               emit_byte (logbuffer, mono_counter_get_variance (agent->counter));
                emit_value (logbuffer, agent->index);
 
                agent->emitted = 1;
        }
-       EXIT_LOG (logbuffer);
 
-       if (threadless)
-               safe_send_threadless (profiler, logbuffer);
-       else
-               safe_send (profiler, logbuffer);
+       EXIT_LOG;
 
        mono_os_mutex_unlock (&counters_mutex);
 }
 
 static void
-counters_sample (MonoProfiler *profiler, uint64_t timestamp, gboolean threadless)
+counters_sample (MonoProfiler *profiler, uint64_t timestamp)
 {
        MonoCounterAgent *agent;
        MonoCounter *counter;
-       LogBuffer *logbuffer;
        int type;
        int buffer_size;
        void *buffer;
@@ -2914,7 +3269,7 @@ counters_sample (MonoProfiler *profiler, uint64_t timestamp, gboolean threadless
        if (!counters_initialized)
                return;
 
-       counters_emit (profiler, threadless);
+       counters_emit (profiler);
 
        buffer_size = 8;
        buffer = calloc (1, buffer_size);
@@ -2922,14 +3277,13 @@ counters_sample (MonoProfiler *profiler, uint64_t timestamp, gboolean threadless
        mono_os_mutex_lock (&counters_mutex);
 
        size =
-               EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */
+               EVENT_SIZE /* event */
        ;
 
        for (agent = counters; agent; agent = agent->next) {
                size +=
                        LEB128_SIZE /* index */ +
-                       LEB128_SIZE /* type */ +
+                       BYTE_SIZE /* type */ +
                        mono_counter_get_size (agent->counter) /* value */
                ;
        }
@@ -2938,11 +3292,12 @@ counters_sample (MonoProfiler *profiler, uint64_t timestamp, gboolean threadless
                LEB128_SIZE /* stop marker */
        ;
 
-       logbuffer = ensure_logbuf (size);
+       ENTER_LOG;
+
+       LogBuffer *logbuffer = ensure_logbuf (size);
+
+       emit_event_time (logbuffer, TYPE_SAMPLE_COUNTERS | TYPE_SAMPLE, timestamp);
 
-       ENTER_LOG (logbuffer, "counters");
-       emit_byte (logbuffer, TYPE_SAMPLE_COUNTERS | TYPE_SAMPLE);
-       emit_uvalue (logbuffer, timestamp);
        for (agent = counters; agent; agent = agent->next) {
                size_t size;
 
@@ -2977,7 +3332,7 @@ counters_sample (MonoProfiler *profiler, uint64_t timestamp, gboolean threadless
                }
 
                emit_uvalue (logbuffer, agent->index);
-               emit_uvalue (logbuffer, type);
+               emit_byte (logbuffer, type);
                switch (type) {
                case MONO_COUNTER_INT:
 #if SIZEOF_VOID_P == 4
@@ -3024,12 +3379,8 @@ counters_sample (MonoProfiler *profiler, uint64_t timestamp, gboolean threadless
        free (buffer);
 
        emit_value (logbuffer, 0);
-       EXIT_LOG (logbuffer);
 
-       if (threadless)
-               safe_send_threadless (profiler, logbuffer);
-       else
-               safe_send (profiler, logbuffer);
+       EXIT_LOG;
 
        mono_os_mutex_unlock (&counters_mutex);
 }
@@ -3050,10 +3401,9 @@ struct _PerfCounterAgent {
 static PerfCounterAgent *perfcounters = NULL;
 
 static void
-perfcounters_emit (MonoProfiler *profiler, gboolean threadless)
+perfcounters_emit (MonoProfiler *profiler)
 {
        PerfCounterAgent *pcagent;
-       LogBuffer *logbuffer;
        int len = 0;
        int size =
                EVENT_SIZE /* event */ +
@@ -3068,9 +3418,9 @@ perfcounters_emit (MonoProfiler *profiler, gboolean threadless)
                        LEB128_SIZE /* section */ +
                        strlen (pcagent->category_name) + 1 /* category name */ +
                        strlen (pcagent->name) + 1 /* name */ +
-                       LEB128_SIZE /* type */ +
-                       LEB128_SIZE /* unit */ +
-                       LEB128_SIZE /* variance */ +
+                       BYTE_SIZE /* type */ +
+                       BYTE_SIZE /* unit */ +
+                       BYTE_SIZE /* variance */ +
                        LEB128_SIZE /* index */
                ;
 
@@ -3080,11 +3430,13 @@ perfcounters_emit (MonoProfiler *profiler, gboolean threadless)
        if (!len)
                return;
 
-       logbuffer = ensure_logbuf (size);
+       ENTER_LOG;
 
-       ENTER_LOG (logbuffer, "perfcounters");
-       emit_byte (logbuffer, TYPE_SAMPLE_COUNTERS_DESC | TYPE_SAMPLE);
+       LogBuffer *logbuffer = ensure_logbuf (size);
+
+       emit_event (logbuffer, TYPE_SAMPLE_COUNTERS_DESC | TYPE_SAMPLE);
        emit_value (logbuffer, len);
+
        for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
                if (pcagent->emitted)
                        continue;
@@ -3092,19 +3444,15 @@ perfcounters_emit (MonoProfiler *profiler, gboolean threadless)
                emit_value (logbuffer, MONO_COUNTER_PERFCOUNTERS);
                emit_string (logbuffer, pcagent->category_name, strlen (pcagent->category_name) + 1);
                emit_string (logbuffer, pcagent->name, strlen (pcagent->name) + 1);
-               emit_value (logbuffer, MONO_COUNTER_LONG);
-               emit_value (logbuffer, MONO_COUNTER_RAW);
-               emit_value (logbuffer, MONO_COUNTER_VARIABLE);
+               emit_byte (logbuffer, MONO_COUNTER_LONG);
+               emit_byte (logbuffer, MONO_COUNTER_RAW);
+               emit_byte (logbuffer, MONO_COUNTER_VARIABLE);
                emit_value (logbuffer, pcagent->index);
 
                pcagent->emitted = 1;
        }
-       EXIT_LOG (logbuffer);
 
-       if (threadless)
-               safe_send_threadless (profiler, logbuffer);
-       else
-               safe_send (profiler, logbuffer);
+       EXIT_LOG;
 }
 
 static gboolean
@@ -3141,10 +3489,9 @@ perfcounters_foreach (char *category_name, char *name, unsigned char type, gint6
 }
 
 static void
-perfcounters_sample (MonoProfiler *profiler, uint64_t timestamp, gboolean threadless)
+perfcounters_sample (MonoProfiler *profiler, uint64_t timestamp)
 {
        PerfCounterAgent *pcagent;
-       LogBuffer *logbuffer;
        int size;
 
        if (!counters_initialized)
@@ -3158,11 +3505,10 @@ perfcounters_sample (MonoProfiler *profiler, uint64_t timestamp, gboolean thread
 
        mono_perfcounter_foreach (perfcounters_foreach, perfcounters);
 
-       perfcounters_emit (profiler, threadless);
+       perfcounters_emit (profiler);
 
        size =
-               EVENT_SIZE /* event */ +
-               LEB128_SIZE /* time */
+               EVENT_SIZE /* event */
        ;
 
        for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
@@ -3171,7 +3517,7 @@ perfcounters_sample (MonoProfiler *profiler, uint64_t timestamp, gboolean thread
 
                size +=
                        LEB128_SIZE /* index */ +
-                       LEB128_SIZE /* type */ +
+                       BYTE_SIZE /* type */ +
                        LEB128_SIZE /* value */
                ;
        }
@@ -3180,44 +3526,36 @@ perfcounters_sample (MonoProfiler *profiler, uint64_t timestamp, gboolean thread
                LEB128_SIZE /* stop marker */
        ;
 
-       logbuffer = ensure_logbuf (size);
+       ENTER_LOG;
+
+       LogBuffer *logbuffer = ensure_logbuf (size);
+
+       emit_event_time (logbuffer, TYPE_SAMPLE_COUNTERS | TYPE_SAMPLE, timestamp);
 
-       ENTER_LOG (logbuffer, "perfcounters");
-       emit_byte (logbuffer, TYPE_SAMPLE_COUNTERS | TYPE_SAMPLE);
-       emit_uvalue (logbuffer, timestamp);
        for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
                if (pcagent->deleted || !pcagent->updated)
                        continue;
                emit_uvalue (logbuffer, pcagent->index);
-               emit_uvalue (logbuffer, MONO_COUNTER_LONG);
+               emit_byte (logbuffer, MONO_COUNTER_LONG);
                emit_svalue (logbuffer, pcagent->value);
 
                pcagent->updated = 0;
        }
 
        emit_value (logbuffer, 0);
-       EXIT_LOG (logbuffer);
 
-       if (threadless)
-               safe_send_threadless (profiler, logbuffer);
-       else
-               safe_send (profiler, logbuffer);
+       EXIT_LOG;
 
        mono_os_mutex_unlock (&counters_mutex);
 }
 
 static void
-counters_and_perfcounters_sample (MonoProfiler *prof, gboolean threadless)
+counters_and_perfcounters_sample (MonoProfiler *prof)
 {
-       static uint64_t start = -1;
-       uint64_t now;
-
-       if (start == -1)
-               start = current_time ();
+       uint64_t now = current_time ();
 
-       now = current_time ();
-       counters_sample (prof, (now - start) / 1000/ 1000, threadless);
-       perfcounters_sample (prof, (now - start) / 1000/ 1000, threadless);
+       counters_sample (prof, now);
+       perfcounters_sample (prof, now);
 }
 
 #define COVERAGE_DEBUG(x) if (debug_coverage) {x}
@@ -3235,20 +3573,18 @@ static gboolean coverage_initialized = FALSE;
 static GPtrArray *coverage_data = NULL;
 static int previous_offset = 0;
 
-typedef struct _MethodNode MethodNode;
-struct _MethodNode {
+typedef struct {
        MonoLockFreeQueueNode node;
        MonoMethod *method;
-};
+} MethodNode;
 
-typedef struct _CoverageEntry CoverageEntry;
-struct _CoverageEntry {
+typedef struct {
        int offset;
        int counter;
        char *filename;
        int line;
        int column;
-};
+} CoverageEntry;
 
 static void
 free_coverage_entry (gpointer data, gpointer userdata)
@@ -3332,7 +3668,6 @@ build_method_buffer (gpointer key, gpointer value, gpointer userdata)
        MonoImage *image;
        char *class_name;
        const char *image_name, *method_name, *sig, *first_filename;
-       LogBuffer *logbuffer;
        guint i;
 
        previous_offset = 0;
@@ -3358,7 +3693,9 @@ build_method_buffer (gpointer key, gpointer value, gpointer userdata)
        sig = sig ? sig : "";
        method_name = method_name ? method_name : "";
 
-       logbuffer = ensure_logbuf (
+       ENTER_LOG;
+
+       LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
                strlen (image_name) + 1 /* image name */ +
                strlen (class_name) + 1 /* class name */ +
@@ -3369,9 +3706,8 @@ build_method_buffer (gpointer key, gpointer value, gpointer userdata)
                LEB128_SIZE /* method id */ +
                LEB128_SIZE /* entries */
        );
-       ENTER_LOG (logbuffer, "coverage-methods");
 
-       emit_byte (logbuffer, TYPE_COVERAGE_METHOD | TYPE_COVERAGE);
+       emit_event (logbuffer, TYPE_COVERAGE_METHOD | TYPE_COVERAGE);
        emit_string (logbuffer, image_name, strlen (image_name) + 1);
        emit_string (logbuffer, class_name, strlen (class_name) + 1);
        emit_string (logbuffer, method_name, strlen (method_name) + 1);
@@ -3382,13 +3718,16 @@ build_method_buffer (gpointer key, gpointer value, gpointer userdata)
        emit_uvalue (logbuffer, method_id);
        emit_value (logbuffer, coverage_data->len);
 
-       EXIT_LOG (logbuffer);
-       safe_send (prof, logbuffer);
+       EXIT_LOG;
+
+       send_if_needed (prof);
 
        for (i = 0; i < coverage_data->len; i++) {
                CoverageEntry *entry = (CoverageEntry *)coverage_data->pdata[i];
 
-               logbuffer = ensure_logbuf (
+               ENTER_LOG;
+
+               LogBuffer *logbuffer = ensure_logbuf (
                        EVENT_SIZE /* event */ +
                        LEB128_SIZE /* method id */ +
                        LEB128_SIZE /* offset */ +
@@ -3396,17 +3735,17 @@ build_method_buffer (gpointer key, gpointer value, gpointer userdata)
                        LEB128_SIZE /* line */ +
                        LEB128_SIZE /* column */
                );
-               ENTER_LOG (logbuffer, "coverage-statement");
 
-               emit_byte (logbuffer, TYPE_COVERAGE_STATEMENT | TYPE_COVERAGE);
+               emit_event (logbuffer, TYPE_COVERAGE_STATEMENT | TYPE_COVERAGE);
                emit_uvalue (logbuffer, method_id);
                emit_uvalue (logbuffer, entry->offset);
                emit_uvalue (logbuffer, entry->counter);
                emit_uvalue (logbuffer, entry->line);
                emit_uvalue (logbuffer, entry->column);
 
-               EXIT_LOG (logbuffer);
-               safe_send (prof, logbuffer);
+               EXIT_LOG;
+
+               send_if_needed (prof);
        }
 
        method_id++;
@@ -3444,7 +3783,6 @@ build_class_buffer (gpointer key, gpointer value, gpointer userdata)
        const char *assembly_name;
        int number_of_methods, partially_covered;
        guint fully_covered;
-       LogBuffer *logbuffer;
 
        image = mono_class_get_image (klass);
        assembly_name = mono_image_get_name (image);
@@ -3456,7 +3794,9 @@ build_class_buffer (gpointer key, gpointer value, gpointer userdata)
        /* We don't handle partial covered yet */
        partially_covered = 0;
 
-       logbuffer = ensure_logbuf (
+       ENTER_LOG;
+
+       LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
                strlen (assembly_name) + 1 /* assembly name */ +
                strlen (class_name) + 1 /* class name */ +
@@ -3465,16 +3805,16 @@ build_class_buffer (gpointer key, gpointer value, gpointer userdata)
                LEB128_SIZE /* partially covered */
        );
 
-       ENTER_LOG (logbuffer, "coverage-class");
-       emit_byte (logbuffer, TYPE_COVERAGE_CLASS | TYPE_COVERAGE);
+       emit_event (logbuffer, TYPE_COVERAGE_CLASS | TYPE_COVERAGE);
        emit_string (logbuffer, assembly_name, strlen (assembly_name) + 1);
        emit_string (logbuffer, class_name, strlen (class_name) + 1);
        emit_uvalue (logbuffer, number_of_methods);
        emit_uvalue (logbuffer, fully_covered);
        emit_uvalue (logbuffer, partially_covered);
-       EXIT_LOG (logbuffer);
 
-       safe_send (prof, logbuffer);
+       EXIT_LOG;
+
+       send_if_needed (prof);
 
        g_free (class_name);
 }
@@ -3500,7 +3840,6 @@ build_assembly_buffer (gpointer key, gpointer value, gpointer userdata)
        MonoAssembly *assembly = (MonoAssembly *)value;
        MonoProfiler *prof = (MonoProfiler *)userdata;
        MonoImage *image = mono_assembly_get_image (assembly);
-       LogBuffer *logbuffer;
        const char *name, *guid, *filename;
        int number_of_methods = 0, partially_covered = 0;
        guint fully_covered = 0;
@@ -3515,7 +3854,9 @@ build_assembly_buffer (gpointer key, gpointer value, gpointer userdata)
 
        get_coverage_for_image (image, &number_of_methods, &fully_covered, &partially_covered);
 
-       logbuffer = ensure_logbuf (
+       ENTER_LOG;
+
+       LogBuffer *logbuffer = ensure_logbuf (
                EVENT_SIZE /* event */ +
                strlen (name) + 1 /* name */ +
                strlen (guid) + 1 /* guid */ +
@@ -3525,17 +3866,17 @@ build_assembly_buffer (gpointer key, gpointer value, gpointer userdata)
                LEB128_SIZE /* partially covered */
        );
 
-       ENTER_LOG (logbuffer, "coverage-assemblies");
-       emit_byte (logbuffer, TYPE_COVERAGE_ASSEMBLY | TYPE_COVERAGE);
+       emit_event (logbuffer, TYPE_COVERAGE_ASSEMBLY | TYPE_COVERAGE);
        emit_string (logbuffer, name, strlen (name) + 1);
        emit_string (logbuffer, guid, strlen (guid) + 1);
        emit_string (logbuffer, filename, strlen (filename) + 1);
        emit_uvalue (logbuffer, number_of_methods);
        emit_uvalue (logbuffer, fully_covered);
        emit_uvalue (logbuffer, partially_covered);
-       EXIT_LOG (logbuffer);
 
-       safe_send (prof, logbuffer);
+       EXIT_LOG;
+
+       send_if_needed (prof);
 }
 
 static void
@@ -3882,7 +4223,7 @@ log_shutdown (MonoProfiler *prof)
 
        in_shutdown = 1;
 #ifndef DISABLE_HELPER_THREAD
-       counters_and_perfcounters_sample (prof, FALSE);
+       counters_and_perfcounters_sample (prof);
 
        dump_coverage (prof);
 
@@ -3900,11 +4241,16 @@ log_shutdown (MonoProfiler *prof)
        }
 #endif
 
-       if (TLS_GET (LogBuffer, tlsbuffer))
-               send_buffer (prof, TLS_GET (GPtrArray, tlsmethodlist), TLS_GET (LogBuffer, tlsbuffer));
-
-       TLS_SET (tlsbuffer, NULL);
-       TLS_SET (tlsmethodlist, NULL);
+       /*
+        * Ensure that we empty the LLS completely, even if some nodes are
+        * not immediately removed upon calling mono_lls_remove (), by
+        * iterating until the head is NULL.
+        */
+       while (profiler_thread_list.head) {
+               MONO_LLS_FOREACH_SAFE (&profiler_thread_list, MonoProfilerThread, thread) {
+                       remove_thread (prof, thread, FALSE);
+               } MONO_LLS_FOREACH_SAFE_END
+       }
 
        InterlockedWrite (&prof->run_dumper_thread, 0);
        mono_os_sem_post (&prof->dumper_queue_sem);
@@ -3918,6 +4264,9 @@ log_shutdown (MonoProfiler *prof)
 
        cleanup_reusable_samples (prof);
 
+       g_assert (!InterlockedRead (&buffer_rwlock_count) && "Why is the reader count still non-zero?");
+       g_assert (!InterlockedReadPointer (&buffer_rwlock_exclusive) && "Why does someone still hold the exclusive lock?");
+
 #if defined (HAVE_SYS_ZLIB)
        if (prof->gzfile)
                gzclose (prof->gzfile);
@@ -3946,6 +4295,8 @@ log_shutdown (MonoProfiler *prof)
                mono_os_mutex_destroy (&coverage_mutex);
        }
 
+       PROF_TLS_FREE ();
+
        free (prof);
 }
 
@@ -4020,11 +4371,12 @@ helper_thread (void* arg)
        int command_socket;
        int len;
        char buf [64];
-       MonoThread *thread = NULL;
 
        mono_threads_attach_tools_thread ();
        mono_native_thread_set_name (mono_native_thread_id_get (), "Profiler helper");
 
+       init_thread (FALSE);
+
        //fprintf (stderr, "Server listening\n");
        command_socket = -1;
        while (1) {
@@ -4055,7 +4407,13 @@ helper_thread (void* arg)
                }
 #endif
 
-               counters_and_perfcounters_sample (prof, TRUE);
+               counters_and_perfcounters_sample (prof);
+
+               buffer_lock_excl ();
+
+               sync_point (prof, SYNC_POINT_PERIODIC);
+
+               buffer_unlock_excl ();
 
                tv.tv_sec = 1;
                tv.tv_usec = 0;
@@ -4072,8 +4430,6 @@ helper_thread (void* arg)
                if (FD_ISSET (prof->pipes [0], &rfds)) {
                        char c;
                        read (prof->pipes [0], &c, 1);
-                       if (thread)
-                               mono_thread_detach (thread);
                        if (do_debug)
                                fprintf (stderr, "helper shutdown\n");
 #if USE_PERF_EVENTS
@@ -4087,7 +4443,7 @@ helper_thread (void* arg)
                                }
                        }
 #endif
-                       safe_send_threadless (prof, ensure_logbuf (0));
+                       safe_send_threadless (prof);
                        return NULL;
                }
 #if USE_PERF_EVENTS
@@ -4098,7 +4454,7 @@ helper_thread (void* arg)
                                        continue;
                                if (FD_ISSET (perf_data [i].perf_fd, &rfds)) {
                                        read_perf_mmap (prof, i);
-                                       safe_send_threadless (prof, ensure_logbuf (0));
+                                       send_if_needed_threadless (prof);
                                }
                        }
                }
@@ -4113,18 +4469,10 @@ helper_thread (void* arg)
                                continue;
                        }
                        buf [len] = 0;
-                       if (strcmp (buf, "heapshot\n") == 0) {
+                       if (strcmp (buf, "heapshot\n") == 0 && hs_mode_ondemand) {
+                               // Rely on the finalization callbacks invoking process_requests ().
                                heapshot_requested = 1;
-                               //fprintf (stderr, "perform heapshot\n");
-                               if (InterlockedRead (&runtime_inited) && !thread) {
-                                       thread = mono_thread_attach (mono_get_root_domain ());
-                                       /*fprintf (stderr, "attached\n");*/
-                               }
-                               if (thread) {
-                                       process_requests (prof);
-                                       mono_thread_detach (thread);
-                                       thread = NULL;
-                               }
+                               mono_gc_finalize_notify ();
                        }
                        continue;
                }
@@ -4186,30 +4534,39 @@ start_helper_thread (MonoProfiler* prof)
 }
 #endif
 
+static void
+free_writer_entry (gpointer p)
+{
+       mono_lock_free_free (p, WRITER_ENTRY_BLOCK_SIZE);
+}
+
 static gboolean
 handle_writer_queue_entry (MonoProfiler *prof)
 {
        WriterQueueEntry *entry;
 
        if ((entry = (WriterQueueEntry *) mono_lock_free_queue_dequeue (&prof->writer_queue))) {
-               LogBuffer *method_buffer = NULL;
-               gboolean new_methods = FALSE;
+               if (!entry->methods)
+                       goto no_methods;
 
-               if (entry->methods->len)
-                       method_buffer = create_buffer ();
+               LogBuffer *buf = NULL;
 
                /*
                 * Encode the method events in a temporary log buffer that we
                 * flush to disk before the main buffer, ensuring that all
                 * methods have metadata emitted before they're referenced.
+                *
+                * We use a 'proper' thread-local buffer for this as opposed
+                * to allocating and freeing a buffer by hand because the call
+                * to mono_method_full_name () below may trigger class load
+                * events when it retrieves the signature of the method. So a
+                * thread-local buffer needs to exist when such events occur.
                 */
                for (guint i = 0; i < entry->methods->len; i++) {
-                       MethodInfo *info = (MethodInfo *)g_ptr_array_index (entry->methods, i);
+                       MethodInfo *info = (MethodInfo *) g_ptr_array_index (entry->methods, i);
 
                        if (mono_conc_hashtable_lookup (prof->method_table, info->method))
-                               continue;
-
-                       new_methods = TRUE;
+                               goto free_info; // This method already has metadata emitted.
 
                        /*
                         * Other threads use this hash table to get a general
@@ -4230,41 +4587,39 @@ handle_writer_queue_entry (MonoProfiler *prof)
                        void *cstart = info->ji ? mono_jit_info_get_code_start (info->ji) : NULL;
                        int csize = info->ji ? mono_jit_info_get_code_size (info->ji) : 0;
 
-                       method_buffer = ensure_logbuf_inner (method_buffer,
+                       buf = ensure_logbuf_unsafe (
                                EVENT_SIZE /* event */ +
-                               LEB128_SIZE /* time */ +
                                LEB128_SIZE /* method */ +
                                LEB128_SIZE /* start */ +
                                LEB128_SIZE /* size */ +
                                nlen /* name */
                        );
 
-                       emit_byte (method_buffer, TYPE_JIT | TYPE_METHOD);
-                       emit_time (method_buffer, info->time);
-                       emit_method_inner (method_buffer, info->method);
-                       emit_ptr (method_buffer, cstart);
-                       emit_value (method_buffer, csize);
+                       emit_event_time (buf, TYPE_JIT | TYPE_METHOD, info->time);
+                       emit_method_inner (buf, info->method);
+                       emit_ptr (buf, cstart);
+                       emit_value (buf, csize);
 
-                       memcpy (method_buffer->cursor, name, nlen);
-                       method_buffer->cursor += nlen;
+                       memcpy (buf->cursor, name, nlen);
+                       buf->cursor += nlen;
 
                        mono_free (name);
+
+               free_info:
                        free (info);
                }
 
                g_ptr_array_free (entry->methods, TRUE);
 
-               if (new_methods) {
-                       for (LogBuffer *iter = method_buffer; iter; iter = iter->next)
-                               iter->thread_id = 0;
-
-                       dump_buffer (prof, method_buffer);
-               } else if (method_buffer)
-                       free_buffer (method_buffer, method_buffer->size);
+               if (buf) {
+                       dump_buffer_threadless (prof, buf);
+                       init_buffer_state (PROF_TLS_GET ());
+               }
 
+       no_methods:
                dump_buffer (prof, entry->buffer);
 
-               mono_thread_hazardous_try_free (entry, free);
+               mono_thread_hazardous_try_free (entry, free_writer_entry);
 
                return TRUE;
        }
@@ -4282,6 +4637,8 @@ writer_thread (void *arg)
 
        dump_header (prof);
 
+       MonoProfilerThread *thread = init_thread (FALSE);
+
        while (InterlockedRead (&prof->run_writer_thread)) {
                mono_os_sem_wait (&prof->writer_queue_sem, MONO_SEM_FLAGS_NONE);
                handle_writer_queue_entry (prof);
@@ -4290,6 +4647,9 @@ writer_thread (void *arg)
        /* Drain any remaining entries on shutdown. */
        while (handle_writer_queue_entry (prof));
 
+       free_buffer (thread->buffer, thread->buffer->size);
+       deinit_thread (thread);
+
        mono_thread_info_detach ();
 
        return NULL;
@@ -4324,8 +4684,8 @@ handle_dumper_queue_entry (MonoProfiler *prof)
                        void *address = sample->frames [i].base_address;
 
                        if (!method) {
-                               g_assert (domain);
-                               g_assert (address);
+                               g_assert (domain && "What happened to the domain pointer?");
+                               g_assert (address && "What happened to the instruction pointer?");
 
                                MonoJitInfo *ji = mono_jit_info_table_find (domain, (char *) address);
 
@@ -4334,10 +4694,9 @@ handle_dumper_queue_entry (MonoProfiler *prof)
                        }
                }
 
-               LogBuffer *logbuffer = ensure_logbuf (
+               LogBuffer *logbuffer = ensure_logbuf_unsafe (
                        EVENT_SIZE /* event */ +
-                       LEB128_SIZE /* type */ +
-                       LEB128_SIZE /* time */ +
+                       BYTE_SIZE /* type */ +
                        LEB128_SIZE /* tid */ +
                        LEB128_SIZE /* count */ +
                        1 * (
@@ -4345,15 +4704,12 @@ handle_dumper_queue_entry (MonoProfiler *prof)
                        ) +
                        LEB128_SIZE /* managed count */ +
                        sample->count * (
-                               LEB128_SIZE /* method */ +
-                               LEB128_SIZE /* il offset */ +
-                               LEB128_SIZE /* native offset */
+                               LEB128_SIZE /* method */
                        )
                );
 
-               emit_byte (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_HIT);
-               emit_value (logbuffer, sample_type);
-               emit_uvalue (logbuffer, prof->startup_time + sample->elapsed * 10000);
+               emit_event_time (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_HIT, sample->time);
+               emit_byte (logbuffer, sample_type);
                emit_ptr (logbuffer, (void *) sample->tid);
                emit_value (logbuffer, 1);
 
@@ -4366,18 +4722,14 @@ handle_dumper_queue_entry (MonoProfiler *prof)
                /* new in data version 6 */
                emit_uvalue (logbuffer, sample->count);
 
-               for (int i = 0; i < sample->count; ++i) {
+               for (int i = 0; i < sample->count; ++i)
                        emit_method (prof, logbuffer, sample->frames [i].method);
-                       emit_svalue (logbuffer, 0); /* il offset will always be 0 from now on */
-                       emit_svalue (logbuffer, sample->frames [i].offset);
-               }
 
                mono_thread_hazardous_try_free (sample, reuse_sample_hit);
 
                dump_unmanaged_coderefs (prof);
 
-               if (logbuffer->next)
-                       safe_send_threadless (prof, logbuffer);
+               send_if_needed_threadless (prof);
        }
 
        return FALSE;
@@ -4391,6 +4743,8 @@ dumper_thread (void *arg)
        mono_threads_attach_tools_thread ();
        mono_native_thread_set_name (mono_native_thread_id_get (), "Profiler dumper");
 
+       MonoProfilerThread *thread = init_thread (FALSE);
+
        while (InterlockedRead (&prof->run_dumper_thread)) {
                mono_os_sem_wait (&prof->dumper_queue_sem, MONO_SEM_FLAGS_NONE);
                handle_dumper_queue_entry (prof);
@@ -4399,7 +4753,8 @@ dumper_thread (void *arg)
        /* Drain any remaining entries on shutdown. */
        while (handle_dumper_queue_entry (prof));
 
-       safe_send_threadless (prof, ensure_logbuf (0));
+       safe_send_threadless (prof);
+       deinit_thread (thread);
 
        mono_thread_info_detach ();
 
@@ -4417,6 +4772,8 @@ start_dumper_thread (MonoProfiler* prof)
 static void
 runtime_initialized (MonoProfiler *profiler)
 {
+       InterlockedWrite (&runtime_inited, 1);
+
 #ifndef DISABLE_HELPER_THREAD
        if (hs_mode_ondemand || need_helper_thread) {
                if (!start_helper_thread (profiler))
@@ -4427,13 +4784,29 @@ runtime_initialized (MonoProfiler *profiler)
        start_writer_thread (profiler);
        start_dumper_thread (profiler);
 
-       InterlockedWrite (&runtime_inited, 1);
+       mono_counters_register ("Sample hits", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &sample_hits);
+       mono_counters_register ("Sample flushes", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &sample_flushes);
+       mono_counters_register ("Sample events allocated", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &sample_allocations);
+       mono_counters_register ("Log buffers allocated", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &buffer_allocations);
+       mono_counters_register ("Thread start events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &thread_starts);
+       mono_counters_register ("Thread stop events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &thread_ends);
+       mono_counters_register ("Domain load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &domain_loads);
+       mono_counters_register ("Domain unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &domain_unloads);
+       mono_counters_register ("Context load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &context_loads);
+       mono_counters_register ("Context unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &context_unloads);
+       mono_counters_register ("Assembly load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &assembly_loads);
+       mono_counters_register ("Assembly unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &assembly_unloads);
+       mono_counters_register ("Image load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &image_loads);
+       mono_counters_register ("Image unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &image_unloads);
+       mono_counters_register ("Class load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &class_loads);
+       mono_counters_register ("Class unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &class_unloads);
+
 #ifndef DISABLE_HELPER_THREAD
        counters_init (profiler);
-       counters_sample (profiler, 0, FALSE);
+       counters_sample (profiler, 0);
 #endif
        /* ensure the main thread data and startup are available soon */
-       safe_send (profiler, ensure_logbuf (0));
+       safe_send (profiler);
 }
 
 static MonoProfiler*
@@ -4520,6 +4893,12 @@ create_profiler (const char *filename, GPtrArray *filters)
 
 #endif
 
+       g_assert (sizeof (WriterQueueEntry) * 2 < LOCK_FREE_ALLOC_SB_USABLE_SIZE (WRITER_ENTRY_BLOCK_SIZE));
+
+       // FIXME: We should free this stuff too.
+       mono_lock_free_allocator_init_size_class (&prof->writer_entry_size_class, sizeof (WriterQueueEntry), WRITER_ENTRY_BLOCK_SIZE);
+       mono_lock_free_allocator_init_allocator (&prof->writer_entry_allocator, &prof->writer_entry_size_class);
+
        mono_lock_free_queue_init (&prof->writer_queue);
        mono_os_sem_init (&prof->writer_queue_sem, 0);
 
@@ -4728,27 +5107,10 @@ mono_profiler_startup (const char *desc)
                MONO_PROFILE_ENTER_LEAVE|MONO_PROFILE_JIT_COMPILATION|MONO_PROFILE_EXCEPTIONS|
                MONO_PROFILE_MONITOR_EVENTS|MONO_PROFILE_MODULE_EVENTS|MONO_PROFILE_GC_ROOTS|
                MONO_PROFILE_INS_COVERAGE|MONO_PROFILE_APPDOMAIN_EVENTS|MONO_PROFILE_CONTEXT_EVENTS|
-               MONO_PROFILE_ASSEMBLY_EVENTS;
+               MONO_PROFILE_ASSEMBLY_EVENTS|MONO_PROFILE_GC_FINALIZATION;
 
        max_allocated_sample_hits = mono_cpu_count () * 1000;
 
-       mono_counters_register ("Sample hits", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &sample_hits);
-       mono_counters_register ("Sample flushes", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &sample_flushes);
-       mono_counters_register ("Sample events allocated", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &sample_allocations);
-       mono_counters_register ("Log buffers allocated", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &buffer_allocations);
-       mono_counters_register ("Thread start events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &thread_starts);
-       mono_counters_register ("Thread stop events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &thread_ends);
-       mono_counters_register ("Domain load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &domain_loads);
-       mono_counters_register ("Domain unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &domain_unloads);
-       mono_counters_register ("Context load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &context_loads);
-       mono_counters_register ("Context unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &context_unloads);
-       mono_counters_register ("Assembly load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &assembly_loads);
-       mono_counters_register ("Assembly unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &assembly_unloads);
-       mono_counters_register ("Image load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &image_loads);
-       mono_counters_register ("Image unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &image_unloads);
-       mono_counters_register ("Class load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &class_loads);
-       mono_counters_register ("Class unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &class_unloads);
-
        p = desc;
        if (strncmp (p, "log", 3))
                usage (1);
@@ -4932,17 +5294,24 @@ mono_profiler_startup (const char *desc)
 
        utils_init (fast_time);
 
+       PROF_TLS_INIT ();
+
        prof = create_profiler (filename, filters);
-       if (!prof)
+       if (!prof) {
+               PROF_TLS_FREE ();
                return;
+       }
 
-       init_thread ();
+       mono_lls_init (&profiler_thread_list, NULL);
+
+       init_thread (TRUE);
 
        mono_profiler_install (prof, log_shutdown);
        mono_profiler_install_gc (gc_event, gc_resize);
        mono_profiler_install_allocation (gc_alloc);
        mono_profiler_install_gc_moves (gc_moves);
        mono_profiler_install_gc_roots (gc_handle, gc_roots);
+       mono_profiler_install_gc_finalize (finalize_begin, finalize_object_begin, finalize_object_end, finalize_end);
        mono_profiler_install_appdomain (NULL, domain_loaded, domain_unloaded, NULL);
        mono_profiler_install_appdomain_name (domain_name);
        mono_profiler_install_context (context_loaded, context_unloaded);
@@ -4967,7 +5336,4 @@ mono_profiler_startup (const char *desc)
        }
 
        mono_profiler_set_events ((MonoProfileFlags)events);
-
-       TLS_INIT (tlsbuffer);
-       TLS_INIT (tlsmethodlist);
 }
index ecb0e43b82334160ce788b255733b12902fce6ae..96f4fa958d657297e755b95908025ce6340571cb 100644 (file)
@@ -5,7 +5,7 @@
 #define LOG_HEADER_ID 0x4D505A01
 #define LOG_VERSION_MAJOR 0
 #define LOG_VERSION_MINOR 4
-#define LOG_DATA_VERSION 12
+#define LOG_DATA_VERSION 13
 /*
  * Changes in data versions:
  * version 2: added offsets in heap walk
                added TYPE_GC_HANDLE_{CREATED,DESTROYED}_BT
                TYPE_JIT events are no longer guaranteed to have code start/size info (can be zero)
  * version 12: added MONO_COUNTER_PROFILER
+ * version 13: added MONO_GC_EVENT_{PRE_STOP_WORLD_LOCKED,POST_START_WORLD_UNLOCKED}
+               added TYPE_META + TYPE_SYNC_POINT
+               removed il and native offset in TYPE_SAMPLE_HIT
+               methods in backtraces are now encoded as proper method pointers
+               removed flags in backtrace format
+               removed flags in metadata events
+               changed the following fields to a single byte rather than leb128
+                   TYPE_GC_EVENT: event_type, generation
+                   TYPE_HEAP_ROOT: root_type
+                   TYPE_JITHELPER: type
+                   TYPE_SAMPLE_HIT: sample_type
+                   TYPE_CLAUSE: clause_type
+                   TYPE_SAMPLE_COUNTERS_DESC: type, unit, variance
+                   TYPE_SAMPLE_COUNTERS: type
+               added time fields to all events that were missing one
+                   TYPE_HEAP_OBJECT
+                   TYPE_HEAP_ROOT
+                   TYPE_SAMPLE_USYM
+                   TYPE_SAMPLE_COUNTERS_DESC
+                   TYPE_COVERAGE_METHOD
+                   TYPE_COVERAGE_STATEMENT
+                   TYPE_COVERAGE_CLASS
+                   TYPE_COVERAGE_ASSEMBLY
+               moved the time field in TYPE_SAMPLE_HIT to right after the event byte, now encoded as a regular time field
+               changed the time field in TYPE_SAMPLE_COUNTERS to be encoded as a regular time field (in nanoseconds)
+               added TYPE_GC_FINALIZE_{START,END,OBJECT_START,OBJECT_END}
  */
 
 enum {
@@ -40,6 +66,7 @@ enum {
        TYPE_SAMPLE,
        TYPE_RUNTIME,
        TYPE_COVERAGE,
+       TYPE_META,
        /* extended type for TYPE_HEAP */
        TYPE_HEAP_START  = 0 << 4,
        TYPE_HEAP_END    = 1 << 4,
@@ -63,6 +90,10 @@ enum {
        TYPE_GC_HANDLE_DESTROYED    = 5 << 4,
        TYPE_GC_HANDLE_CREATED_BT   = 6 << 4,
        TYPE_GC_HANDLE_DESTROYED_BT = 7 << 4,
+       TYPE_GC_FINALIZE_START = 8 << 4,
+       TYPE_GC_FINALIZE_END = 9 << 4,
+       TYPE_GC_FINALIZE_OBJECT_START = 10 << 4,
+       TYPE_GC_FINALIZE_OBJECT_END = 11 << 4,
        /* extended type for TYPE_METHOD */
        TYPE_LEAVE     = 1 << 4,
        TYPE_ENTER     = 2 << 4,
@@ -91,9 +122,17 @@ enum {
        TYPE_COVERAGE_METHOD   = 1 << 4,
        TYPE_COVERAGE_STATEMENT = 2 << 4,
        TYPE_COVERAGE_CLASS = 3 << 4,
+       /* extended type for TYPE_META */
+       TYPE_SYNC_POINT = 0 << 4,
        TYPE_END
 };
 
+typedef enum {
+       SYNC_POINT_PERIODIC,
+       SYNC_POINT_WORLD_STOP,
+       SYNC_POINT_WORLD_START
+} MonoProfilerSyncPointType;
+
 // Sampling sources
 // Unless you have compiled with --enable-perf-events, only SAMPLE_CYCLES is available
 enum {
index 753024dcf72963e30c7ebef03da79e54b7cdc7e0..c3e14e4af89065ae8683cd821e6d155251eab515 100644 (file)
@@ -418,7 +418,7 @@ uintptr_t
 process_id (void)
 {
 #ifdef HOST_WIN32
-       return 0; /* FIXME */
+       return GetCurrentProcessId ();
 #else
        return (uintptr_t)getpid ();
 #endif
index aa5ef1a44a93ace9fe040a3089e3bcffbf19f93e..a215c44502c12b226359ff45fddafe511f569374 100644 (file)
@@ -1138,10 +1138,7 @@ major_get_and_reset_num_major_objects_marked (void)
 
 /* gcc 4.2.1 from xcode4 crashes on sgen_card_table_get_card_address () when this is enabled */
 #if defined(PLATFORM_MACOSX)
-#define GCC_VERSION (__GNUC__ * 10000 \
-                               + __GNUC_MINOR__ * 100 \
-                               + __GNUC_PATCHLEVEL__)
-#if GCC_VERSION <= 40300
+#if MONO_GNUC_VERSION <= 40300
 #undef PREFETCH_CARDS
 #endif
 #endif
index 68fc0a5d0603301897fe4cbad95de05495156d25..7c8dbc087311677c159a0f3b86b57f8e6d62ef6f 100644 (file)
@@ -111,13 +111,29 @@ class Driver {
                var heads = new Bridge [FAN_OUT];
                for (int i = 0; i < FAN_OUT; ++i)
                        heads [i] = new Bridge ();
-               var multiplexer = new Bridge [FAN_OUT];
-               for (int i = 0; i < FAN_OUT; ++i)
-               {
-                       heads [i].Links.Add (multiplexer);
-                       multiplexer [i] = new Bridge ();
+
+               // We make five identical multiplexers to verify Tarjan-bridge can merge them together correctly.
+               var MULTIPLEXER_COUNT = 5;
+               Bridge[] multiplexer0 = null;
+               for(int m = 0; m < MULTIPLEXER_COUNT; m++) {
+                       var multiplexer = new Bridge [FAN_OUT];
+                       if (m == 0) {
+                               multiplexer0 = multiplexer;
+                               for (int i = 0; i < FAN_OUT; ++i)
+                               {
+                                       heads [i].Links.Add (multiplexer);
+                                       multiplexer [i] = new Bridge ();
+                               }
+                       } else {
+                               for (int i = 0; i < FAN_OUT; ++i)
+                               {
+                                       heads [i].Links.Add (multiplexer);
+                                       multiplexer [i] = multiplexer0 [i];
+                               }
+                       }
                }
-               Console.WriteLine ("-double fan done-");
+
+               Console.WriteLine ("-double fan x5 done-");
        }
 
        /*
index 3841581e0bb02fd61fe9f407dbcbef8891a0cea9..a5e01ebe09ec6e5f913e1ad936c822596d39ecde 100644 (file)
@@ -74,11 +74,11 @@ worker (void *arg)
                        break;
                case STATE_OUT:
                        if (InterlockedCompareExchange (&nodes [i].state, STATE_BUSY, STATE_OUT) == STATE_OUT) {
-                               result = mono_lls_find (&lls, hp, i, HAZARD_FREE_SAFE_CTX);
+                               result = mono_lls_find (&lls, hp, i);
                                assert (!result);
                                mono_hazard_pointer_clear_all (hp, -1);
 
-                               result = mono_lls_insert (&lls, hp, &nodes [i].node, HAZARD_FREE_SAFE_CTX);
+                               result = mono_lls_insert (&lls, hp, &nodes [i].node);
                                mono_hazard_pointer_clear_all (hp, -1);
 
                                assert (nodes [i].state == STATE_BUSY);
@@ -89,12 +89,12 @@ worker (void *arg)
                        break;
                case STATE_IN:
                        if (InterlockedCompareExchange (&nodes [i].state, STATE_BUSY, STATE_IN) == STATE_IN) {
-                               result = mono_lls_find (&lls, hp, i, HAZARD_FREE_SAFE_CTX);
+                               result = mono_lls_find (&lls, hp, i);
                                assert (result);
                                assert (mono_hazard_pointer_get_val (hp, 1) == &nodes [i].node);
                                mono_hazard_pointer_clear_all (hp, -1);
 
-                               result = mono_lls_remove (&lls, hp, &nodes [i].node, HAZARD_FREE_SAFE_CTX);
+                               result = mono_lls_remove (&lls, hp, &nodes [i].node);
                                mono_hazard_pointer_clear_all (hp, -1);
 
                                ++thread_data->num_removes;
@@ -126,7 +126,7 @@ main (int argc, char *argv [])
 
        mono_threads_init (&thread_callbacks, 0);
 
-       mono_lls_init (&lls, free_node, HAZARD_FREE_NO_LOCK);
+       mono_lls_init (&lls, free_node);
 
        for (i = 0; i < N; ++i) {
                nodes [i].node.key = i;
index 2e873cde79844c8793f096b5913a5cc854e28103..d67b9ff1fed2bb89a6a5697356203fd73b123b95 100644 (file)
@@ -130,6 +130,7 @@ monoutils_sources = \
        atomic.c        \
        mono-hwcap.h    \
        mono-hwcap.c    \
+       mono-hwcap-vars.h       \
        bsearch.h       \
        bsearch.c       \
        mono-signal-handler.h   \
@@ -182,48 +183,56 @@ arch_sources += mach-support-unknown.c
 
 endif
 
+if !CROSS_COMPILE
+
 if X86
-arch_sources += mono-hwcap-x86.c mono-hwcap-x86.h
+arch_sources += mono-hwcap-x86.c
 endif
 
 if AMD64
-arch_sources += mono-hwcap-x86.c mono-hwcap-x86.h
+arch_sources += mono-hwcap-x86.c
 endif
 
 if ARM
-arch_sources += mono-hwcap-arm.c mono-hwcap-arm.h
+arch_sources += mono-hwcap-arm.c
 endif
 
 if ARM64
-arch_sources += mono-hwcap-arm64.c mono-hwcap-arm64.h
+arch_sources += mono-hwcap-arm64.c
 endif
 
 if MIPS
-arch_sources += mono-hwcap-mips.c mono-hwcap-mips.h
+arch_sources += mono-hwcap-mips.c
 endif
 
 if POWERPC
-arch_sources += mono-hwcap-ppc.c mono-hwcap-ppc.h
+arch_sources += mono-hwcap-ppc.c
 endif
 
 if POWERPC64
-arch_sources += mono-hwcap-ppc.c mono-hwcap-ppc.h
+arch_sources += mono-hwcap-ppc.c
 endif
 
 if SPARC
-arch_sources += mono-hwcap-sparc.c mono-hwcap-sparc.h
+arch_sources += mono-hwcap-sparc.c
 endif
 
 if SPARC64
-arch_sources += mono-hwcap-sparc.c mono-hwcap-sparc.h
+arch_sources += mono-hwcap-sparc.c
 endif
 
 if IA64
-arch_sources += mono-hwcap-ia64.c mono-hwcap-ia64.h
+arch_sources += mono-hwcap-ia64.c
 endif
 
 if S390X
-arch_sources += mono-hwcap-s390x.c mono-hwcap-s390x.h
+arch_sources += mono-hwcap-s390x.c
+endif
+
+else
+
+arch_sources += mono-hwcap-cross.c
+
 endif
 
 libmonoutils_la_SOURCES = $(monoutils_sources) $(arch_sources)
index 4f5f010afd31bd61551347f754fe9f31639b0bae..dca6170a1a1e72cfe2f03cc77a5ce9a2895e1d6d 100755 (executable)
@@ -14,6 +14,7 @@
 
 #include "config.h"
 #include <glib.h>
+#include <mono/utils/mono-membar.h>
 
 /*
 The current Nexus 7 arm-v7a fails with:
@@ -29,7 +30,6 @@ Apple targets have historically being problematic, xcode 4.6 would miscompile th
 #define WIN32_LEAN_AND_MEAN
 #endif
 #include <windows.h>
-#include <mono/utils/mono-membar.h>
 
 /* mingw is missing InterlockedCompareExchange64 () from winbase.h */
 #if HAVE_DECL_INTERLOCKEDCOMPAREEXCHANGE64==0
@@ -180,30 +180,63 @@ static inline void InterlockedWrite16(volatile gint16 *dst, gint16 val)
 /* Prefer GCC atomic ops if the target supports it (see configure.ac). */
 #elif defined(USE_GCC_ATOMIC_OPS)
 
+/*
+ * As of this comment (August 2016), all current Clang versions get atomic
+ * intrinsics on ARM64 wrong. All GCC versions prior to 5.3.0 do, too. The bug
+ * is the same: The compiler developers thought that the acq + rel barriers
+ * that ARM64 load/store instructions can impose are sufficient to provide
+ * sequential consistency semantics. This is not the case:
+ *
+ *     http://lists.infradead.org/pipermail/linux-arm-kernel/2014-February/229588.html
+ *
+ * We work around this bug by inserting full barriers around each atomic
+ * intrinsic if we detect that we're built with a buggy compiler.
+ */
+
+#if defined (HOST_ARM64) && (defined (__clang__) || MONO_GNUC_VERSION < 50300)
+#define WRAP_ATOMIC_INTRINSIC(INTRIN) \
+       ({ \
+               mono_memory_barrier (); \
+               __typeof__ (INTRIN) atomic_ret__ = (INTRIN); \
+               mono_memory_barrier (); \
+               atomic_ret__; \
+       })
+
+#define gcc_sync_val_compare_and_swap(a, b, c) WRAP_ATOMIC_INTRINSIC (__sync_val_compare_and_swap (a, b, c))
+#define gcc_sync_add_and_fetch(a, b) WRAP_ATOMIC_INTRINSIC (__sync_add_and_fetch (a, b))
+#define gcc_sync_sub_and_fetch(a, b) WRAP_ATOMIC_INTRINSIC (__sync_sub_and_fetch (a, b))
+#define gcc_sync_fetch_and_add(a, b) WRAP_ATOMIC_INTRINSIC (__sync_fetch_and_add (a, b))
+#else
+#define gcc_sync_val_compare_and_swap(a, b, c) __sync_val_compare_and_swap (a, b, c)
+#define gcc_sync_add_and_fetch(a, b) __sync_add_and_fetch (a, b)
+#define gcc_sync_sub_and_fetch(a, b) __sync_sub_and_fetch (a, b)
+#define gcc_sync_fetch_and_add(a, b) __sync_fetch_and_add (a, b)
+#endif
+
 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
                                                gint32 exch, gint32 comp)
 {
-       return __sync_val_compare_and_swap (dest, comp, exch);
+       return gcc_sync_val_compare_and_swap (dest, comp, exch);
 }
 
 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
 {
-       return __sync_val_compare_and_swap (dest, comp, exch);
+       return gcc_sync_val_compare_and_swap (dest, comp, exch);
 }
 
 static inline gint32 InterlockedAdd(volatile gint32 *dest, gint32 add)
 {
-       return __sync_add_and_fetch (dest, add);
+       return gcc_sync_add_and_fetch (dest, add);
 }
 
 static inline gint32 InterlockedIncrement(volatile gint32 *val)
 {
-       return __sync_add_and_fetch (val, 1);
+       return gcc_sync_add_and_fetch (val, 1);
 }
 
 static inline gint32 InterlockedDecrement(volatile gint32 *val)
 {
-       return __sync_sub_and_fetch (val, 1);
+       return gcc_sync_sub_and_fetch (val, 1);
 }
 
 static inline gint32 InterlockedExchange(volatile gint32 *val, gint32 new_val)
@@ -211,7 +244,7 @@ static inline gint32 InterlockedExchange(volatile gint32 *val, gint32 new_val)
        gint32 old_val;
        do {
                old_val = *val;
-       } while (__sync_val_compare_and_swap (val, old_val, new_val) != old_val);
+       } while (gcc_sync_val_compare_and_swap (val, old_val, new_val) != old_val);
        return old_val;
 }
 
@@ -221,30 +254,30 @@ static inline gpointer InterlockedExchangePointer(volatile gpointer *val,
        gpointer old_val;
        do {
                old_val = *val;
-       } while (__sync_val_compare_and_swap (val, old_val, new_val) != old_val);
+       } while (gcc_sync_val_compare_and_swap (val, old_val, new_val) != old_val);
        return old_val;
 }
 
 static inline gint32 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
 {
-       return __sync_fetch_and_add (val, add);
+       return gcc_sync_fetch_and_add (val, add);
 }
 
 static inline gint8 InterlockedRead8(volatile gint8 *src)
 {
        /* Kind of a hack, but GCC doesn't give us anything better, and it's
         * certainly not as bad as using a CAS loop. */
-       return __sync_fetch_and_add (src, 0);
+       return gcc_sync_fetch_and_add (src, 0);
 }
 
 static inline gint16 InterlockedRead16(volatile gint16 *src)
 {
-       return __sync_fetch_and_add (src, 0);
+       return gcc_sync_fetch_and_add (src, 0);
 }
 
 static inline gint32 InterlockedRead(volatile gint32 *src)
 {
-       return __sync_fetch_and_add (src, 0);
+       return gcc_sync_fetch_and_add (src, 0);
 }
 
 static inline void InterlockedWrite8(volatile gint8 *dst, gint8 val)
@@ -253,7 +286,7 @@ static inline void InterlockedWrite8(volatile gint8 *dst, gint8 val)
        gint8 old_val;
        do {
                old_val = *dst;
-       } while (__sync_val_compare_and_swap (dst, old_val, val) != old_val);
+       } while (gcc_sync_val_compare_and_swap (dst, old_val, val) != old_val);
 }
 
 static inline void InterlockedWrite16(volatile gint16 *dst, gint16 val)
@@ -261,7 +294,7 @@ static inline void InterlockedWrite16(volatile gint16 *dst, gint16 val)
        gint16 old_val;
        do {
                old_val = *dst;
-       } while (__sync_val_compare_and_swap (dst, old_val, val) != old_val);
+       } while (gcc_sync_val_compare_and_swap (dst, old_val, val) != old_val);
 }
 
 static inline void InterlockedWrite(volatile gint32 *dst, gint32 val)
@@ -270,7 +303,7 @@ static inline void InterlockedWrite(volatile gint32 *dst, gint32 val)
        gint32 old_val;
        do {
                old_val = *dst;
-       } while (__sync_val_compare_and_swap (dst, old_val, val) != old_val);
+       } while (gcc_sync_val_compare_and_swap (dst, old_val, val) != old_val);
 }
 
 #if defined (TARGET_OSX) || defined (__arm__) || (defined (__mips__) && !defined (__mips64)) || (defined (__powerpc__) && !defined (__powerpc64__)) || (defined (__sparc__) && !defined (__arch64__))
@@ -281,33 +314,33 @@ static inline void InterlockedWrite(volatile gint32 *dst, gint32 val)
 
 static inline gint64 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp)
 {
-       return __sync_val_compare_and_swap (dest, comp, exch);
+       return gcc_sync_val_compare_and_swap (dest, comp, exch);
 }
 
 static inline gint64 InterlockedAdd64(volatile gint64 *dest, gint64 add)
 {
-       return __sync_add_and_fetch (dest, add);
+       return gcc_sync_add_and_fetch (dest, add);
 }
 
 static inline gint64 InterlockedIncrement64(volatile gint64 *val)
 {
-       return __sync_add_and_fetch (val, 1);
+       return gcc_sync_add_and_fetch (val, 1);
 }
 
 static inline gint64 InterlockedDecrement64(volatile gint64 *val)
 {
-       return __sync_sub_and_fetch (val, 1);
+       return gcc_sync_sub_and_fetch (val, 1);
 }
 
 static inline gint64 InterlockedExchangeAdd64(volatile gint64 *val, gint64 add)
 {
-       return __sync_fetch_and_add (val, add);
+       return gcc_sync_fetch_and_add (val, add);
 }
 
 static inline gint64 InterlockedRead64(volatile gint64 *src)
 {
        /* Kind of a hack, but GCC doesn't give us anything better. */
-       return __sync_fetch_and_add (src, 0);
+       return gcc_sync_fetch_and_add (src, 0);
 }
 
 #else
@@ -393,122 +426,6 @@ static inline void InterlockedWrite64(volatile gint64 *dst, gint64 val)
        InterlockedExchange64 (dst, val);
 }
 
-#elif defined(__ia64__)
-
-#ifdef __INTEL_COMPILER
-#include <ia64intrin.h>
-#endif
-
-static inline gint32 InterlockedCompareExchange(gint32 volatile *dest,
-                                               gint32 exch, gint32 comp)
-{
-       gint32 old;
-       guint64 real_comp;
-
-#ifdef __INTEL_COMPILER
-       old = _InterlockedCompareExchange (dest, exch, comp);
-#else
-       /* cmpxchg4 zero extends the value read from memory */
-       real_comp = (guint64)(guint32)comp;
-       asm volatile ("mov ar.ccv = %2 ;;\n\t"
-                                 "cmpxchg4.acq %0 = [%1], %3, ar.ccv\n\t"
-                                 : "=r" (old) : "r" (dest), "r" (real_comp), "r" (exch));
-#endif
-
-       return(old);
-}
-
-static inline gpointer InterlockedCompareExchangePointer(gpointer volatile *dest,
-                                               gpointer exch, gpointer comp)
-{
-       gpointer old;
-
-#ifdef __INTEL_COMPILER
-       old = _InterlockedCompareExchangePointer (dest, exch, comp);
-#else
-       asm volatile ("mov ar.ccv = %2 ;;\n\t"
-                                 "cmpxchg8.acq %0 = [%1], %3, ar.ccv\n\t"
-                                 : "=r" (old) : "r" (dest), "r" (comp), "r" (exch));
-#endif
-
-       return(old);
-}
-
-static inline gint32 InterlockedIncrement(gint32 volatile *val)
-{
-#ifdef __INTEL_COMPILER
-       return _InterlockedIncrement (val);
-#else
-       gint32 old;
-
-       do {
-               old = *val;
-       } while (InterlockedCompareExchange (val, old + 1, old) != old);
-
-       return old + 1;
-#endif
-}
-
-static inline gint32 InterlockedDecrement(gint32 volatile *val)
-{
-#ifdef __INTEL_COMPILER
-       return _InterlockedDecrement (val);
-#else
-       gint32 old;
-
-       do {
-               old = *val;
-       } while (InterlockedCompareExchange (val, old - 1, old) != old);
-
-       return old - 1;
-#endif
-}
-
-static inline gint32 InterlockedExchange(gint32 volatile *dest, gint32 new_val)
-{
-#ifdef __INTEL_COMPILER
-       return _InterlockedExchange (dest, new_val);
-#else
-       gint32 res;
-
-       do {
-               res = *dest;
-       } while (InterlockedCompareExchange (dest, new_val, res) != res);
-
-       return res;
-#endif
-}
-
-static inline gpointer InterlockedExchangePointer(gpointer volatile *dest, gpointer new_val)
-{
-#ifdef __INTEL_COMPILER
-       return (gpointer)_InterlockedExchange64 ((gint64*)dest, (gint64)new_val);
-#else
-       gpointer res;
-
-       do {
-               res = *dest;
-       } while (InterlockedCompareExchangePointer (dest, new_val, res) != res);
-
-       return res;
-#endif
-}
-
-static inline gint32 InterlockedExchangeAdd(gint32 volatile *val, gint32 add)
-{
-       gint32 old;
-
-#ifdef __INTEL_COMPILER
-       old = _InterlockedExchangeAdd (val, add);
-#else
-       do {
-               old = *val;
-       } while (InterlockedCompareExchange (val, old + add, old) != old);
-
-       return old;
-#endif
-}
-
 #else
 
 #define WAPI_NO_ATOMIC_ASM
index efe6b649b3039450cbdc176f0373cd55754a69be..f31e154e792866e7413086a4de492ac170513db5 100644 (file)
@@ -29,7 +29,6 @@
 typedef struct {
        gpointer p;
        MonoHazardousFreeFunc free_func;
-       HazardFreeLocking locking;
 } DelayedFreeItem;
 
 /* The hazard table */
@@ -191,7 +190,7 @@ mono_hazard_pointer_get (void)
    mono_jit_info_table_add(), which doesn't have to care about hazards
    because it holds the respective domain lock. */
 gpointer
-get_hazardous_pointer (gpointer volatile *pp, MonoThreadHazardPointers *hp, int hazard_index)
+mono_get_hazardous_pointer (gpointer volatile *pp, MonoThreadHazardPointers *hp, int hazard_index)
 {
        gpointer p;
 
@@ -288,7 +287,7 @@ mono_hazard_pointer_restore_for_signal_handler (int small_id)
 }
 
 static gboolean
-try_free_delayed_free_item (HazardFreeContext context)
+try_free_delayed_free_item (void)
 {
        DelayedFreeItem item;
        gboolean popped = mono_lock_free_array_queue_pop (&delayed_free_queue, &item);
@@ -296,8 +295,7 @@ try_free_delayed_free_item (HazardFreeContext context)
        if (!popped)
                return FALSE;
 
-       if ((context == HAZARD_FREE_ASYNC_CTX && item.locking == HAZARD_FREE_MAY_LOCK) ||
-           (is_pointer_hazardous (item.p))) {
+       if (is_pointer_hazardous (item.p)) {
                mono_lock_free_array_queue_push (&delayed_free_queue, &item);
                return FALSE;
        }
@@ -348,7 +346,7 @@ mono_thread_hazardous_try_free (gpointer p, MonoHazardousFreeFunc free_func)
 void
 mono_thread_hazardous_queue_free (gpointer p, MonoHazardousFreeFunc free_func)
 {
-       DelayedFreeItem item = { p, free_func, HAZARD_FREE_MAY_LOCK };
+       DelayedFreeItem item = { p, free_func };
 
        InterlockedIncrement (&hazardous_pointer_count);
 
@@ -369,7 +367,7 @@ mono_hazard_pointer_install_free_queue_size_callback (MonoHazardFreeQueueSizeCal
 void
 mono_thread_hazardous_try_free_all (void)
 {
-       while (try_free_delayed_free_item (HAZARD_FREE_SAFE_CTX))
+       while (try_free_delayed_free_item ())
                ;
 }
 
@@ -378,7 +376,7 @@ mono_thread_hazardous_try_free_some (void)
 {
        int i;
        for (i = 0; i < 10; ++i)
-               try_free_delayed_free_item (HAZARD_FREE_SAFE_CTX);
+               try_free_delayed_free_item ();
 }
 
 void
index 0102c103f7629785b1eb8c231a88f86269dbc56c..d27264b1209cb9686ee7c715282037c4dab42d53 100644 (file)
@@ -20,23 +20,13 @@ typedef struct {
 
 typedef void (*MonoHazardousFreeFunc) (gpointer p);
 
-typedef enum {
-       HAZARD_FREE_MAY_LOCK,
-       HAZARD_FREE_NO_LOCK,
-} HazardFreeLocking;
-
-typedef enum {
-       HAZARD_FREE_SAFE_CTX,
-       HAZARD_FREE_ASYNC_CTX,
-} HazardFreeContext;
-
 MONO_API gboolean mono_thread_hazardous_try_free (gpointer p, MonoHazardousFreeFunc free_func);
-void mono_thread_hazardous_queue_free (gpointer p, MonoHazardousFreeFunc free_func);
+MONO_API void mono_thread_hazardous_queue_free (gpointer p, MonoHazardousFreeFunc free_func);
 
 void mono_thread_hazardous_try_free_all (void);
 void mono_thread_hazardous_try_free_some (void);
-MonoThreadHazardPointers* mono_hazard_pointer_get (void);
-gpointer get_hazardous_pointer (gpointer volatile *pp, MonoThreadHazardPointers *hp, int hazard_index);
+MONO_API MonoThreadHazardPointers* mono_hazard_pointer_get (void);
+gpointer mono_get_hazardous_pointer (gpointer volatile *pp, MonoThreadHazardPointers *hp, int hazard_index);
 
 #define mono_hazard_pointer_set(hp,i,v)        \
        do { g_assert ((i) >= 0 && (i) < HAZARD_POINTER_COUNT); \
index d103ef6aa333eeb96a920d8e62ef0af79db5ecb2..d5da3896343906457b70d185db3f4df793f9828e 100644 (file)
@@ -170,7 +170,7 @@ desc_alloc (void)
        for (;;) {
                gboolean success;
 
-               desc = (Descriptor *) get_hazardous_pointer ((gpointer * volatile)&desc_avail, hp, 1);
+               desc = (Descriptor *) mono_get_hazardous_pointer ((gpointer * volatile)&desc_avail, hp, 1);
                if (desc) {
                        Descriptor *next = desc->next;
                        success = (InterlockedCompareExchangePointer ((gpointer * volatile)&desc_avail, next, desc) == desc);
index 2e06b63f526258de4e6f2004e3fd397d8f523611..3abb84104732786d6978fed3f01d42496de8585d 100644 (file)
@@ -133,7 +133,7 @@ mono_lock_free_queue_enqueue (MonoLockFreeQueue *q, MonoLockFreeQueueNode *node)
        for (;;) {
                MonoLockFreeQueueNode *next;
 
-               tail = (MonoLockFreeQueueNode *) get_hazardous_pointer ((gpointer volatile*)&q->tail, hp, 0);
+               tail = (MonoLockFreeQueueNode *) mono_get_hazardous_pointer ((gpointer volatile*)&q->tail, hp, 0);
                mono_memory_read_barrier ();
                /*
                 * We never dereference next so we don't need a
@@ -243,7 +243,7 @@ mono_lock_free_queue_dequeue (MonoLockFreeQueue *q)
        for (;;) {
                MonoLockFreeQueueNode *tail, *next;
 
-               head = (MonoLockFreeQueueNode *) get_hazardous_pointer ((gpointer volatile*)&q->head, hp, 0);
+               head = (MonoLockFreeQueueNode *) mono_get_hazardous_pointer ((gpointer volatile*)&q->head, hp, 0);
                tail = (MonoLockFreeQueueNode*)q->tail;
                mono_memory_read_barrier ();
                next = head->next;
index 2b3b86e2ef2e305dd8de427b6eb4902b999283de..d03ba8051aa565a53319b35aad89cecae2b9f450 100644 (file)
@@ -303,5 +303,9 @@ typedef SSIZE_T ssize_t;
 #define MONO_COLD
 #endif
 
+#if defined (__GNUC__) && defined (__GNUC_MINOR__) && defined (__GNUC_PATCHLEVEL__)
+#define MONO_GNUC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+#endif
+
 #endif /* __UTILS_MONO_COMPILER_H__*/
 
index b5b3539d116c00eef3eba67d112ff9d521df3f9c..9b92493191ed1a08bad915c7ab7df8ecd6a5fcb5 100644 (file)
@@ -164,7 +164,7 @@ mono_conc_hashtable_lookup (MonoConcurrentHashTable *hash_table, gpointer key)
        hp = mono_hazard_pointer_get ();
 
 retry:
-       table = (conc_table *)get_hazardous_pointer ((gpointer volatile*)&hash_table->table, hp, 0);
+       table = (conc_table *)mono_get_hazardous_pointer ((gpointer volatile*)&hash_table->table, hp, 0);
        table_mask = table->table_size - 1;
        kvs = table->kvs;
        i = hash & table_mask;
index 758c3dc6fc2651487fc8cc87fcd97714f1882d13..e51387776b93ed25d0c69b83d1abdd1d77d9b7f9 100644 (file)
@@ -19,7 +19,7 @@
  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
-#include "mono/utils/mono-hwcap-arm.h"
+#include "mono/utils/mono-hwcap.h"
 
 #if defined(HAVE_SYS_AUXV_H) && !defined(PLATFORM_ANDROID)
 #include <sys/auxv.h>
 #include <stdio.h>
 #endif
 
-gboolean mono_hwcap_arm_is_v5 = FALSE;
-gboolean mono_hwcap_arm_is_v6 = FALSE;
-gboolean mono_hwcap_arm_is_v7 = FALSE;
-gboolean mono_hwcap_arm_has_vfp = FALSE;
-gboolean mono_hwcap_arm_has_vfp3 = FALSE;
-gboolean mono_hwcap_arm_has_vfp3_d16 = FALSE;
-gboolean mono_hwcap_arm_has_thumb = FALSE;
-gboolean mono_hwcap_arm_has_thumb2 = FALSE;
-
 void
 mono_hwcap_arch_init (void)
 {
@@ -202,16 +193,3 @@ mono_hwcap_arch_init (void)
        }
 #endif
 }
-
-void
-mono_hwcap_print(FILE *f)
-{
-       g_fprintf (f, "mono_hwcap_arm_is_v5 = %i\n", mono_hwcap_arm_is_v5);
-       g_fprintf (f, "mono_hwcap_arm_is_v6 = %i\n", mono_hwcap_arm_is_v6);
-       g_fprintf (f, "mono_hwcap_arm_is_v7 = %i\n", mono_hwcap_arm_is_v7);
-       g_fprintf (f, "mono_hwcap_arm_has_vfp = %i\n", mono_hwcap_arm_has_vfp);
-       g_fprintf (f, "mono_hwcap_arm_has_vfp3 = %i\n", mono_hwcap_arm_has_vfp3);
-       g_fprintf (f, "mono_hwcap_arm_has_vfp3_d16 = %i\n", mono_hwcap_arm_has_vfp3_d16);
-       g_fprintf (f, "mono_hwcap_arm_has_thumb = %i\n", mono_hwcap_arm_has_thumb);
-       g_fprintf (f, "mono_hwcap_arm_has_thumb2 = %i\n", mono_hwcap_arm_has_thumb2);
-}
diff --git a/mono/utils/mono-hwcap-arm.h b/mono/utils/mono-hwcap-arm.h
deleted file mode 100644 (file)
index 29adf7b..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef __MONO_UTILS_HWCAP_ARM_H__
-#define __MONO_UTILS_HWCAP_ARM_H__
-
-#include "mono/utils/mono-hwcap.h"
-
-extern gboolean mono_hwcap_arm_is_v5;
-extern gboolean mono_hwcap_arm_is_v6;
-extern gboolean mono_hwcap_arm_is_v7;
-extern gboolean mono_hwcap_arm_has_vfp;
-extern gboolean mono_hwcap_arm_has_vfp3;
-extern gboolean mono_hwcap_arm_has_vfp3_d16;
-extern gboolean mono_hwcap_arm_has_thumb;
-extern gboolean mono_hwcap_arm_has_thumb2;
-
-#endif /* __MONO_UTILS_HWCAP_ARM_H__ */
index 5491cff96cfd60ec93560dee66aa7343c11c5803..f541ea3df2bebc78f42295ad212f739f63f1982f 100644 (file)
@@ -1,25 +1,13 @@
 /*
- * mono-hwcap-arm64.c: ARM hardware feature detection
+ * mono-hwcap-arm64.c: ARM64 hardware feature detection
  *
  * Copyright 2013 Xamarin Inc
  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
-#include "mono/utils/mono-hwcap-arm64.h"
+#include "mono/utils/mono-hwcap.h"
 
-#if defined(MONO_CROSS_COMPILE)
 void
 mono_hwcap_arch_init (void)
 {
 }
-#else
-void
-mono_hwcap_arch_init (void)
-{
-}
-#endif
-
-void
-mono_hwcap_print(FILE *f)
-{
-}
diff --git a/mono/utils/mono-hwcap-arm64.h b/mono/utils/mono-hwcap-arm64.h
deleted file mode 100644 (file)
index 2d41209..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __MONO_UTILS_HWCAP_ARM64_H__
-#define __MONO_UTILS_HWCAP_ARM64_H__
-
-#include "mono/utils/mono-hwcap.h"
-
-#endif
diff --git a/mono/utils/mono-hwcap-cross.c b/mono/utils/mono-hwcap-cross.c
new file mode 100644 (file)
index 0000000..4311a99
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * mono-hwcap-cross.c: No-op hardware feature detection
+ *
+ * Author:
+ *  Alex Rønne Petersen (alexrp@xamarin.com)
+ *
+ * Copyright 2015 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+
+#include "mono/utils/mono-hwcap.h"
+
+void
+mono_hwcap_arch_init (void)
+{
+}
index b5979862208a32a61fc594f5b150a183f225df6d..dd1edbd8d40dcb6d79e62325a157d585845ddd6c 100644 (file)
  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
-#include "mono/utils/mono-hwcap-ia64.h"
+#include "mono/utils/mono-hwcap.h"
 
 void
 mono_hwcap_arch_init (void)
-{
-       /* Nothing needed here yet. */
-}
-
-void
-mono_hwcap_print (FILE *f)
 {
 }
diff --git a/mono/utils/mono-hwcap-ia64.h b/mono/utils/mono-hwcap-ia64.h
deleted file mode 100644 (file)
index 15b64a8..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __MONO_UTILS_HWCAP_IA64_H__
-#define __MONO_UTILS_HWCAP_IA64_H__
-
-#include "mono/utils/mono-hwcap.h"
-
-/* Nothing needed here yet. */
-
-#endif /* __MONO_UTILS_HWCAP_IA64_H__ */
index 6d809a79ac54cf488c61faf587a0f5a5d3e50196..119f930a685a4d0915736d14f4d623b4291deca8 100644 (file)
  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
-#include "mono/utils/mono-hwcap-mips.h"
+#include "mono/utils/mono-hwcap.h"
 
 void
 mono_hwcap_arch_init (void)
-{
-       /* Nothing needed here yet. */
-}
-
-void
-mono_hwcap_print (FILE *f)
 {
 }
diff --git a/mono/utils/mono-hwcap-mips.h b/mono/utils/mono-hwcap-mips.h
deleted file mode 100644 (file)
index dd0622a..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __MONO_UTILS_HWCAP_MIPS_H__
-#define __MONO_UTILS_HWCAP_MIPS_H__
-
-#include "mono/utils/mono-hwcap.h"
-
-/* Nothing needed here yet. */
-
-#endif /* __MONO_UTILS_HWCAP_MIPS_H__ */
index 174cc620a202c7af27d8012b11075f09d78d93ed..af36c4d5473191c740746c83b47b726e4ddc0524 100644 (file)
  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
-#include "mono/utils/mono-hwcap-ppc.h"
+#include "mono/utils/mono-hwcap.h"
 
 #if defined(__linux__) && defined(HAVE_SYS_AUXV_H)
 #include <string.h>
 #include <sys/auxv.h>
 #endif
 
-gboolean mono_hwcap_ppc_has_icache_snoop = FALSE;
-gboolean mono_hwcap_ppc_is_isa_2x = FALSE;
-gboolean mono_hwcap_ppc_is_isa_64 = FALSE;
-gboolean mono_hwcap_ppc_has_move_fpr_gpr = FALSE;
-gboolean mono_hwcap_ppc_has_multiple_ls_units = FALSE;
-
 void
 mono_hwcap_arch_init (void)
 {
@@ -66,13 +60,3 @@ mono_hwcap_arch_init (void)
        }
 #endif
 }
-
-void
-mono_hwcap_print (FILE* f)
-{
-       g_fprintf (f, "mono_hwcap_ppc_has_icache_snoop = %i\n", mono_hwcap_ppc_has_icache_snoop);
-       g_fprintf (f, "mono_hwcap_ppc_is_isa_2x = %i\n", mono_hwcap_ppc_is_isa_2x);
-       g_fprintf (f, "mono_hwcap_ppc_is_isa_64 = %i\n", mono_hwcap_ppc_is_isa_64);
-       g_fprintf (f, "mono_hwcap_ppc_has_move_fpr_gpr = %i\n", mono_hwcap_ppc_has_move_fpr_gpr);
-       g_fprintf (f, "mono_hwcap_ppc_has_multiple_ls_units = %i\n", mono_hwcap_ppc_has_multiple_ls_units);
-}
diff --git a/mono/utils/mono-hwcap-ppc.h b/mono/utils/mono-hwcap-ppc.h
deleted file mode 100644 (file)
index 0ae2578..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef __MONO_UTILS_HWCAP_PPC_H__
-#define __MONO_UTILS_HWCAP_PPC_H__
-
-#include "mono/utils/mono-hwcap.h"
-
-extern gboolean mono_hwcap_ppc_has_icache_snoop;
-extern gboolean mono_hwcap_ppc_is_isa_2x;
-extern gboolean mono_hwcap_ppc_is_isa_64;
-extern gboolean mono_hwcap_ppc_has_move_fpr_gpr;
-extern gboolean mono_hwcap_ppc_has_multiple_ls_units;
-
-#endif /* __MONO_UTILS_HWCAP_PPC_H__ */
index 19a7fba11017251a55864c39a93fa94ff5b5b2de..c578a620d925d87eca46a3709d5df296c5570654 100644 (file)
  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
-#include "mono/utils/mono-hwcap-s390x.h"
+#include "mono/utils/mono-hwcap.h"
+
 #include <signal.h>
 
-facilityList_t facs;
+typedef struct {
+       uint8_t n3:1;           // 000 - N3 instructions
+       uint8_t zi:1;           // 001 - z/Arch installed
+       uint8_t za:1;           // 002 - z/Arch active
+       uint8_t date:1;         // 003 - DAT-enhancement
+       uint8_t idtes:1;        // 004 - IDTE-segment tables
+       uint8_t idter:1;        // 005 - IDTE-region tables
+       uint8_t asnlx:1;        // 006 - ASN-LX reuse
+       uint8_t stfle:1;        // 007 - STFLE
+       uint8_t edat1:1;        // 008 - EDAT 1
+       uint8_t srs:1;          // 009 - Sense-Running-Status
+       uint8_t csske:1;        // 010 - Conditional SSKE
+       uint8_t ctf:1;          // 011 - Configuration-topology
+       uint8_t ibm01:1;        // 012 - Assigned to IBM
+       uint8_t ipter:1;        // 013 - IPTE-range
+       uint8_t nqks:1;         // 014 - Nonquiescing key-setting
+       uint8_t ibm02:1;        // 015 - Assigned to IBM
+       uint8_t etf2:1;         // 016 - Extended translation 2
+       uint8_t msa:1;          // 017 - Message security assist 1
+       uint8_t ld:1;           // 018 - Long displacement
+       uint8_t ldh:1;          // 019 - Long displacement high perf
+       uint8_t mas:1;          // 020 - HFP multiply-add-subtract
+       uint8_t eif:1;          // 021 - Extended immediate
+       uint8_t etf3:1;         // 022 - Extended translation 3
+       uint8_t hux:1;          // 023 - HFP unnormalized extension
+       uint8_t etf2e:1;        // 024 - Extended translation enhanced 2
+       uint8_t stckf:1;        // 025 - Store clock fast
+       uint8_t pe:1;           // 026 - Parsing enhancement
+       uint8_t mvcos:1;        // 027 - Move with optional specs
+       uint8_t tods:1;         // 028 - TOD steering
+       uint8_t x000:1;         // 029 - Undefined
+       uint8_t etf3e:1;        // 030 - ETF3 enhancement
+       uint8_t ecput:1;        // 031 - Extract CPU time
+       uint8_t csst:1;         // 032 - Compare swap and store
+       uint8_t csst2:1;        // 033 - Compare swap and store 2
+       uint8_t gie:1;          // 034 - General instructions extension
+       uint8_t ee:1;           // 035 - Execute extensions
+       uint8_t em:1;           // 036 - Enhanced monitor
+       uint8_t fpe:1;          // 037 - Floating point extension
+       uint8_t x001:1;         // 038 - Undefined
+       uint8_t ibm03:1;        // 039 - Assigned to IBM
+       uint8_t spp:1;          // 040 - Set program parameters
+       uint8_t fpse:1;         // 041 - FP support enhancement
+       uint8_t dfp:1;          // 042 - DFP
+       uint8_t dfph:1;         // 043 - DFP high performance
+       uint8_t pfpo:1;         // 044 - PFPO instruction
+       uint8_t multi:1;        // 045 - Multiple inc load/store on CC 1
+       uint8_t ibm04:1;        // 046 - Assigned to IBM
+       uint8_t cmpsce:1;       // 047 - CMPSC enhancement
+       uint8_t dfpzc:1;        // 048 - DFP zoned conversion
+       uint8_t misc:1;         // 049 - Multiple inc load and trap
+       uint8_t ctx:1;          // 050 - Constrained transactional-execution
+       uint8_t ltlb:1;         // 051 - Local TLB clearing
+       uint8_t ia:1;           // 052 - Interlocked access
+       uint8_t lsoc2:1;        // 053 - Load/store on CC 2
+       uint8_t x002:1;         // 054 - Undefined
+       uint8_t ibm05:1;        // 055 - Assigned to IBM
+       uint8_t x003:1;         // 056 - Undefined
+       uint8_t msa5:1;         // 057 - Message security assist 5
+       uint8_t x004:1;         // 058 - Undefined
+       uint8_t x005:1;         // 059 - Undefined
+       uint8_t x006:1;         // 060 - Undefined
+       uint8_t x007:1;         // 061 - Undefined
+       uint8_t ibm06:1;        // 062 - Assigned to IBM
+       uint8_t x008:1;         // 063 - Undefined
+       uint8_t x009:1;         // 064 - Undefined
+       uint8_t ibm07:1;        // 065 - Assigned to IBM
+       uint8_t rrbm:1;         // 066 - Reset reference bits multiple
+       uint8_t cmc:1;          // 067 - CPU measurement counter
+       uint8_t cms:1;          // 068 - CPU Measurement sampling
+       uint8_t ibm08:1;        // 069 - Assigned to IBM
+       uint8_t ibm09:1;        // 070 - Assigned to IBM
+       uint8_t ibm10:1;        // 071 - Assigned to IBM
+       uint8_t ibm11:1;        // 072 - Assigned to IBM
+       uint8_t txe:1;          // 073 - Transactional execution
+       uint8_t sthy:1;         // 074 - Store hypervisor information
+       uint8_t aefsi:1;        // 075 - Access exception fetch/store indication
+       uint8_t msa3:1;         // 076 - Message security assist 3
+       uint8_t msa4:1;         // 077 - Message security assist 4
+       uint8_t edat2:1;        // 078 - Enhanced DAT 2
+       uint8_t x010:1;         // 079 - Undefined
+       uint8_t dfppc:1;        // 080 - DFP packed conversion
+       uint8_t x011:7;         // 081-87 - Undefined
+       uint8_t x012[5];        // 088-127 - Undefined
+       uint8_t ibm12:1;        // 128 - Assigned to IBM
+       uint8_t vec:1;          // 129 - Vector facility
+       uint8_t x013:6;         // 130-135 - Undefined
+       uint8_t x014:6;         // 136-141 - Undefined
+       uint8_t sccm:1;         // 142 - Store CPU counter multiple
+       uint8_t ibm13:1;        // 143 - Assigned to IBM
+       uint8_t x015[14];       // 144-256 Undefined
+} __attribute__ ((packed)) __attribute__ ((aligned(8))) facilityList_t;
 
 void
 mono_hwcap_arch_init (void)
 {
-       int lFacs = sizeof(facs) / 8;
+       facilityList_t facs;
+       int lFacs = sizeof (facs) / 8;
 
-       __asm__ ("      lgfr    0,%1\n"
-                "      .insn   s,0xb2b00000,%0\n"
-                : "=m" (facs) : "r" (lFacs) : "0", "cc");
-}
+       __asm__ __volatile__ (
+               "lgfr\t0,%1\n\t"
+               ".insn\ts,0xb2b00000,%0\n\t"
+               : "=m" (facs)
+               : "r" (lFacs)
+               : "0", "cc"
+       );
 
-void
-mono_hwcap_print (FILE *f)
-{
+       mono_hwcap_s390x_has_fpe = facs.fpe;
+       mono_hwcap_s390x_has_vec = facs.vec;
 }
diff --git a/mono/utils/mono-hwcap-s390x.h b/mono/utils/mono-hwcap-s390x.h
deleted file mode 100644 (file)
index 7a4522f..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-#ifndef __MONO_UTILS_HWCAP_S390X_H__
-#define __MONO_UTILS_HWCAP_S390X_H__
-
-#include "mono/utils/mono-hwcap.h"
-
-typedef struct __FACLIST__ {
-       uint8_t n3:1;           // 000 - N3 instructions
-       uint8_t zi:1;           // 001 - z/Arch installed
-       uint8_t za:1;           // 002 - z/Arch active
-       uint8_t date:1;         // 003 - DAT-enhancement
-       uint8_t idtes:1;        // 004 - IDTE-segment tables
-       uint8_t idter:1;        // 005 - IDTE-region tables
-       uint8_t asnlx:1;        // 006 - ASN-LX reuse
-       uint8_t stfle:1;        // 007 - STFLE
-       uint8_t edat1:1;        // 008 - EDAT 1
-       uint8_t srs:1;          // 009 - Sense-Running-Status
-       uint8_t csske:1;        // 010 - Conditional SSKE
-       uint8_t ctf:1;          // 011 - Configuration-topology
-       uint8_t ibm01:1;        // 012 - Assigned to IBM
-       uint8_t ipter:1;        // 013 - IPTE-range
-       uint8_t nqks:1;         // 014 - Nonquiescing key-setting
-       uint8_t ibm02:1;        // 015 - Assigned to IBM
-       uint8_t etf2:1;         // 016 - Extended translation 2
-       uint8_t msa:1;          // 017 - Message security assist 1
-       uint8_t ld:1;           // 018 - Long displacement
-       uint8_t ldh:1;          // 019 - Long displacement high perf
-       uint8_t mas:1;          // 020 - HFP multiply-add-subtract
-       uint8_t eif:1;          // 021 - Extended immediate
-       uint8_t etf3:1;         // 022 - Extended translation 3
-       uint8_t hux:1;          // 023 - HFP unnormalized extension
-       uint8_t etf2e:1;        // 024 - Extended translation enhanced 2
-       uint8_t stckf:1;        // 025 - Store clock fast
-       uint8_t pe:1;           // 026 - Parsing enhancement
-       uint8_t mvcos:1;        // 027 - Move with optional specs
-       uint8_t tods:1;         // 028 - TOD steering
-       uint8_t x000:1;         // 029 - Undefined
-       uint8_t etf3e:1;        // 030 - ETF3 enhancement
-       uint8_t ecput:1;        // 031 - Extract CPU time
-       uint8_t csst:1;         // 032 - Compare swap and store
-       uint8_t csst2:1;        // 033 - Compare swap and store 2
-       uint8_t gie:1;          // 034 - General instructions extension
-       uint8_t ee:1;           // 035 - Execute extensions
-       uint8_t em:1;           // 036 - Enhanced monitor
-       uint8_t fpe:1;          // 037 - Floating point extension
-       uint8_t x001:1;         // 038 - Undefined
-       uint8_t ibm03:1;        // 039 - Assigned to IBM
-       uint8_t spp:1;          // 040 - Set program parameters
-       uint8_t fpse:1;         // 041 - FP support enhancement
-       uint8_t dfp:1;          // 042 - DFP
-       uint8_t dfph:1;         // 043 - DFP high performance
-       uint8_t pfpo:1;         // 044 - PFPO instruction
-       uint8_t multi:1;        // 045 - Multiple inc load/store on CC 1
-       uint8_t ibm04:1;        // 046 - Assigned to IBM
-       uint8_t cmpsce:1;       // 047 - CMPSC enhancement
-       uint8_t dfpzc:1;        // 048 - DFP zoned conversion
-       uint8_t misc:1;         // 049 - Multiple inc load and trap
-       uint8_t ctx:1;          // 050 - Constrained transactional-execution
-       uint8_t ltlb:1;         // 051 - Local TLB clearing
-       uint8_t ia:1;           // 052 - Interlocked access
-       uint8_t lsoc2:1;        // 053 - Load/store on CC 2
-       uint8_t x002:1;         // 054 - Undefined
-       uint8_t ibm05:1;        // 055 - Assigned to IBM
-       uint8_t x003:1;         // 056 - Undefined
-       uint8_t msa5:1;         // 057 - Message security assist 5
-       uint8_t x004:1;         // 058 - Undefined
-       uint8_t x005:1;         // 059 - Undefined
-       uint8_t x006:1;         // 060 - Undefined
-       uint8_t x007:1;         // 061 - Undefined
-       uint8_t ibm06:1;        // 062 - Assigned to IBM
-       uint8_t x008:1;         // 063 - Undefined
-       uint8_t x009:1;         // 064 - Undefined
-       uint8_t ibm07:1;        // 065 - Assigned to IBM
-       uint8_t rrbm:1;         // 066 - Reset reference bits multiple
-       uint8_t cmc:1;          // 067 - CPU measurement counter
-       uint8_t cms:1;          // 068 - CPU Measurement sampling
-       uint8_t ibm08:1;        // 069 - Assigned to IBM
-       uint8_t ibm09:1;        // 070 - Assigned to IBM
-       uint8_t ibm10:1;        // 071 - Assigned to IBM
-       uint8_t ibm11:1;        // 072 - Assigned to IBM
-       uint8_t txe:1;          // 073 - Transactional execution
-       uint8_t sthy:1;         // 074 - Store hypervisor information
-       uint8_t aefsi:1;        // 075 - Access exception fetch/store indication
-       uint8_t msa3:1;         // 076 - Message security assist 3
-       uint8_t msa4:1;         // 077 - Message security assist 4
-       uint8_t edat2:1;        // 078 - Enhanced DAT 2
-       uint8_t x010:1;         // 079 - Undefined
-       uint8_t dfppc:1;        // 080 - DFP packed conversion
-       uint8_t x011:7;         // 081-87 - Undefined
-       uint8_t x012[5];        // 088-127 - Undefined
-       uint8_t ibm12:1;        // 128 - Assigned to IBM
-       uint8_t vec:1;          // 129 - Vector facility
-       uint8_t x013:6;         // 130-135 - Undefined
-       uint8_t x014:6;         // 136-141 - Undefined
-       uint8_t sccm:1;         // 142 - Store CPU counter multiple
-       uint8_t ibm13:1;        // 143 - Assigned to IBM
-       uint8_t x015[14];       // 144-256 Undefined
-} __attribute__ ((packed)) __attribute__ ((aligned(8))) facilityList_t;
-
-extern facilityList_t facs;
-
-#endif /* __MONO_UTILS_HWCAP_S390X_H__ */
index ba849873632cf0798c66c34ecddf2990056d9873..75208bdeff7bc02996f188a00eeaed769007d138 100644 (file)
  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
-#include "mono/utils/mono-hwcap-sparc.h"
+#include "mono/utils/mono-hwcap.h"
 
 #include <string.h>
-
 #if !defined(__linux__)
 #include <sys/systeminfo.h>
 #else
 #include <unistd.h>
 #endif
 
-gboolean mono_hwcap_sparc_is_v9 = FALSE;
-
 void
 mono_hwcap_arch_init (void)
 {
        char buf [1024];
 
 #if !defined(__linux__)
-       if (!sysinfo (SI_ISALIST, buf, 1024))
-               g_assert_not_reached ();
+       g_assert (sysinfo (SI_ISALIST, buf, 1024));
 #else
        /* If the page size is 8192, we're on a 64-bit SPARC, which
         * in turn means a v9 or better.
@@ -51,9 +47,3 @@ mono_hwcap_arch_init (void)
 
        mono_hwcap_sparc_is_v9 = strstr (buf, "sparcv9");
 }
-
-void
-mono_hwcap_print (FILE *f)
-{
-       g_fprintf (f, "mono_hwcap_sparc_is_v9 = %i\n", mono_hwcap_sparc_is_v9);
-}
diff --git a/mono/utils/mono-hwcap-vars.h b/mono/utils/mono-hwcap-vars.h
new file mode 100644 (file)
index 0000000..620a3d4
--- /dev/null
@@ -0,0 +1,56 @@
+#include "config.h"
+
+#if defined (TARGET_ARM)
+
+MONO_HWCAP_VAR(arm_is_v5)
+MONO_HWCAP_VAR(arm_is_v6)
+MONO_HWCAP_VAR(arm_is_v7)
+MONO_HWCAP_VAR(arm_has_vfp)
+MONO_HWCAP_VAR(arm_has_vfp3)
+MONO_HWCAP_VAR(arm_has_vfp3_d16)
+MONO_HWCAP_VAR(arm_has_thumb)
+MONO_HWCAP_VAR(arm_has_thumb2)
+
+#elif defined (TARGET_ARM64)
+
+// Nothing here yet.
+
+#elif defined (TARGET_IA64)
+
+// Nothing here yet.
+
+#elif defined (TARGET_MIPS)
+
+// Nothing here yet.
+
+#elif defined (TARGET_POWERPC) || defined (TARGET_POWERPC64)
+
+MONO_HWCAP_VAR(ppc_has_icache_snoop)
+MONO_HWCAP_VAR(ppc_is_isa_2x)
+MONO_HWCAP_VAR(ppc_is_isa_64)
+MONO_HWCAP_VAR(ppc_has_move_fpr_gpr)
+MONO_HWCAP_VAR(ppc_has_multiple_ls_units)
+
+#elif defined (TARGET_S390X)
+
+MONO_HWCAP_VAR(s390x_has_fpe)
+MONO_HWCAP_VAR(s390x_has_vec)
+
+#elif defined (TARGET_SPARC) || defined (TARGET_SPARC64)
+
+MONO_HWCAP_VAR(sparc_is_v9)
+
+#elif defined (TARGET_X86) || defined (TARGET_AMD64)
+
+MONO_HWCAP_VAR(x86_is_xen)
+MONO_HWCAP_VAR(x86_has_cmov)
+MONO_HWCAP_VAR(x86_has_fcmov)
+MONO_HWCAP_VAR(x86_has_sse1)
+MONO_HWCAP_VAR(x86_has_sse2)
+MONO_HWCAP_VAR(x86_has_sse3)
+MONO_HWCAP_VAR(x86_has_ssse3)
+MONO_HWCAP_VAR(x86_has_sse41)
+MONO_HWCAP_VAR(x86_has_sse42)
+MONO_HWCAP_VAR(x86_has_sse4a)
+
+#endif
index 4a96aa3a088eeb3d6a646c123c603bb305c29296..5d72a4c7e2030260e74b82369ffc82db450636f4 100644 (file)
  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
-#include "mono/utils/mono-hwcap-x86.h"
+#include "mono/utils/mono-hwcap.h"
 
 #if defined(HAVE_UNISTD_H)
 #include <unistd.h>
 #endif
-
 #if defined(_MSC_VER)
 #include <intrin.h>
 #endif
 
-gboolean mono_hwcap_x86_is_xen = FALSE;
-gboolean mono_hwcap_x86_has_cmov = FALSE;
-gboolean mono_hwcap_x86_has_fcmov = FALSE;
-gboolean mono_hwcap_x86_has_sse1 = FALSE;
-gboolean mono_hwcap_x86_has_sse2 = FALSE;
-gboolean mono_hwcap_x86_has_sse3 = FALSE;
-gboolean mono_hwcap_x86_has_ssse3 = FALSE;
-gboolean mono_hwcap_x86_has_sse41 = FALSE;
-gboolean mono_hwcap_x86_has_sse42 = FALSE;
-gboolean mono_hwcap_x86_has_sse4a = FALSE;
-
 static gboolean
 cpuid (int id, int *p_eax, int *p_ebx, int *p_ecx, int *p_edx)
 {
@@ -162,18 +150,3 @@ mono_hwcap_arch_init (void)
        mono_hwcap_x86_is_xen = !access ("/proc/xen", F_OK);
 #endif
 }
-
-void
-mono_hwcap_print (FILE *f)
-{
-       g_fprintf (f, "mono_hwcap_x86_is_xen = %i\n", mono_hwcap_x86_is_xen);
-       g_fprintf (f, "mono_hwcap_x86_has_cmov = %i\n", mono_hwcap_x86_has_cmov);
-       g_fprintf (f, "mono_hwcap_x86_has_fcmov = %i\n", mono_hwcap_x86_has_fcmov);
-       g_fprintf (f, "mono_hwcap_x86_has_sse1 = %i\n", mono_hwcap_x86_has_sse1);
-       g_fprintf (f, "mono_hwcap_x86_has_sse2 = %i\n", mono_hwcap_x86_has_sse2);
-       g_fprintf (f, "mono_hwcap_x86_has_sse3 = %i\n", mono_hwcap_x86_has_sse3);
-       g_fprintf (f, "mono_hwcap_x86_has_ssse3 = %i\n", mono_hwcap_x86_has_ssse3);
-       g_fprintf (f, "mono_hwcap_x86_has_sse41 = %i\n", mono_hwcap_x86_has_sse41);
-       g_fprintf (f, "mono_hwcap_x86_has_sse42 = %i\n", mono_hwcap_x86_has_sse42);
-       g_fprintf (f, "mono_hwcap_x86_has_sse4a = %i\n", mono_hwcap_x86_has_sse4a);
-}
diff --git a/mono/utils/mono-hwcap-x86.h b/mono/utils/mono-hwcap-x86.h
deleted file mode 100644 (file)
index 5e1f4f7..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef __MONO_UTILS_HWCAP_X86_H__
-#define __MONO_UTILS_HWCAP_X86_H__
-
-#include "mono/utils/mono-hwcap.h"
-
-extern gboolean mono_hwcap_x86_is_xen;
-extern gboolean mono_hwcap_x86_has_cmov;
-extern gboolean mono_hwcap_x86_has_fcmov;
-extern gboolean mono_hwcap_x86_has_sse1;
-extern gboolean mono_hwcap_x86_has_sse2;
-extern gboolean mono_hwcap_x86_has_sse3;
-extern gboolean mono_hwcap_x86_has_ssse3;
-extern gboolean mono_hwcap_x86_has_sse41;
-extern gboolean mono_hwcap_x86_has_sse42;
-extern gboolean mono_hwcap_x86_has_sse4a;
-
-#endif /* __MONO_UTILS_HWCAP_X86_H__ */
index a3d2b6078bfdb0d3e401d6e2854497e5ec7f3b8f..00fad690193a5f8415f4afc317b1c28afa97fd99 100644 (file)
 
 #include "mono/utils/mono-hwcap.h"
 
+#define MONO_HWCAP_VAR(NAME) gboolean mono_hwcap_ ## NAME = FALSE;
+#include "mono/utils/mono-hwcap-vars.h"
+#undef MONO_HWCAP_VAR
+
 static gboolean hwcap_inited = FALSE;
 
 void
@@ -35,19 +39,21 @@ mono_hwcap_init (void)
        if (hwcap_inited)
                return;
 
-#ifdef MONO_CROSS_COMPILE
-       /*
-        * If we're cross-compiling, we want to be as
-        * conservative as possible so that we produce
-        * code that's portable. Default to that.
-        */
-       if (!conservative)
-               conservative = "1";
-#endif
-
        if (!conservative || strncmp (conservative, "1", 1))
                mono_hwcap_arch_init ();
 
        if (verbose && !strncmp (verbose, "1", 1))
-               mono_hwcap_print (stdout);
+               mono_hwcap_print ();
+}
+
+void
+mono_hwcap_print (void)
+{
+       g_print ("[mono-hwcap] Detected following hardware capabilities:\n\n");
+
+#define MONO_HWCAP_VAR(NAME) g_print ("\t" #NAME " = %s\n", mono_hwcap_ ## NAME ? "yes" : "no");
+#include "mono/utils/mono-hwcap-vars.h"
+#undef MONO_HWCAP_VAR
+
+       g_print ("\n");
 }
index af5d665426905beefe8e3e89318e82e1a2610f49..1867d3d258a62bbb0c0e4d8b820892a691781586 100644 (file)
@@ -8,6 +8,10 @@
 
 #include "mono/utils/mono-compiler.h"
 
+#define MONO_HWCAP_VAR(NAME) extern gboolean mono_hwcap_ ## NAME;
+#include "mono/utils/mono-hwcap-vars.h"
+#undef MONO_HWCAP_VAR
+
 /* Call this function to perform hardware feature detection. Until
  * this function has been called, all feature variables will be
  * FALSE as a default.
  * result in an inconsistent state of the variables. Further,
  * feature variables should not be read *while* this function is
  * executing.
- *
- * To get at feature variables, include the appropriate header,
- * e.g. mono-hwcap-x86.h for x86(-64).
  */
 void mono_hwcap_init (void);
 
 /* Implemented in mono-hwcap-$TARGET.c. Do not call. */
 void mono_hwcap_arch_init (void);
 
-/* Print detected features to the given file. */
-void mono_hwcap_print (FILE *f);
+/* Print detected features to stdout. */
+void mono_hwcap_print (void);
 
 /* Please note: If you're going to use the Linux auxiliary vector
  * to detect CPU features, don't use any of the constant names in
index f076034da21d7f0dc9ff4aa6c3e1e535f20c8ef5..ea11fcc634bbc948e11af5338c56f1304cdc6f31 100644 (file)
@@ -25,7 +25,7 @@ mask (gpointer n, uintptr_t bit)
 }
 
 gpointer
-get_hazardous_pointer_with_mask (gpointer volatile *pp, MonoThreadHazardPointers *hp, int hazard_index)
+mono_lls_get_hazardous_pointer_with_mask (gpointer volatile *pp, MonoThreadHazardPointers *hp, int hazard_index)
 {
        gpointer p;
 
@@ -56,28 +56,21 @@ get_hazardous_pointer_with_mask (gpointer volatile *pp, MonoThreadHazardPointers
 /*
 Initialize @list and will use @free_node_func to release memory.
 If @free_node_func is null the caller is responsible for releasing node memory.
-If @free_node_func may lock, @free_node_func_locking must be
-HAZARD_FREE_MAY_LOCK; otherwise, HAZARD_FREE_NO_LOCK. It is ignored if
-@free_node_func is null.
 */
 void
-mono_lls_init (MonoLinkedListSet *list, void (*free_node_func)(void *), HazardFreeLocking free_node_func_locking)
+mono_lls_init (MonoLinkedListSet *list, void (*free_node_func)(void *))
 {
        list->head = NULL;
        list->free_node_func = free_node_func;
-       list->locking = free_node_func_locking;
 }
 
 /*
 Search @list for element with key @key.
-@context specifies whether the function is being called from a lock-free (i.e.
-signal handler or world stopped) context. It is only relevant if a node free
-function was given.
 The nodes next, cur and prev are returned in @hp.
 Returns true if a node with key @key was found.
 */
 gboolean
-mono_lls_find (MonoLinkedListSet *list, MonoThreadHazardPointers *hp, uintptr_t key, HazardFreeContext context)
+mono_lls_find (MonoLinkedListSet *list, MonoThreadHazardPointers *hp, uintptr_t key)
 {
        MonoLinkedListSetNode *cur, *next;
        MonoLinkedListSetNode **prev;
@@ -95,12 +88,12 @@ try_again:
         */
        mono_hazard_pointer_set (hp, 2, prev);
 
-       cur = (MonoLinkedListSetNode *) get_hazardous_pointer_with_mask ((gpointer*)prev, hp, 1);
+       cur = (MonoLinkedListSetNode *) mono_lls_get_hazardous_pointer_with_mask ((gpointer*)prev, hp, 1);
 
        while (1) {
                if (cur == NULL)
                        return FALSE;
-               next = (MonoLinkedListSetNode *) get_hazardous_pointer_with_mask ((gpointer*)&cur->next, hp, 0);
+               next = (MonoLinkedListSetNode *) mono_lls_get_hazardous_pointer_with_mask ((gpointer*)&cur->next, hp, 0);
                cur_key = cur->key;
 
                /*
@@ -137,15 +130,12 @@ try_again:
 
 /*
 Insert @value into @list.
-@context specifies whether the function is being called from a lock-free (i.e.
-signal handler or world stopped) context. It is only relevant if a node free
-function was given.
 The nodes value, cur and prev are returned in @hp.
 Return true if @value was inserted by this call. If it returns FALSE, it's the caller
 resposibility to release memory.
 */
 gboolean
-mono_lls_insert (MonoLinkedListSet *list, MonoThreadHazardPointers *hp, MonoLinkedListSetNode *value, HazardFreeContext context)
+mono_lls_insert (MonoLinkedListSet *list, MonoThreadHazardPointers *hp, MonoLinkedListSetNode *value)
 {
        MonoLinkedListSetNode *cur, **prev;
        /*We must do a store barrier before inserting 
@@ -153,7 +143,7 @@ mono_lls_insert (MonoLinkedListSet *list, MonoThreadHazardPointers *hp, MonoLink
        mono_memory_barrier ();
 
        while (1) {
-               if (mono_lls_find (list, hp, value->key, context))
+               if (mono_lls_find (list, hp, value->key))
                        return FALSE;
                cur = (MonoLinkedListSetNode *) mono_hazard_pointer_get_val (hp, 1);
                prev = (MonoLinkedListSetNode **) mono_hazard_pointer_get_val (hp, 2);
@@ -169,18 +159,15 @@ mono_lls_insert (MonoLinkedListSet *list, MonoThreadHazardPointers *hp, MonoLink
 
 /*
 Search @list for element with key @key and remove it.
-@context specifies whether the function is being called from a lock-free (i.e.
-signal handler or world stopped) context. It is only relevant if a node free
-function was given.
 The nodes next, cur and prev are returned in @hp
 Returns true if @value was removed by this call.
 */
 gboolean
-mono_lls_remove (MonoLinkedListSet *list, MonoThreadHazardPointers *hp, MonoLinkedListSetNode *value, HazardFreeContext context)
+mono_lls_remove (MonoLinkedListSet *list, MonoThreadHazardPointers *hp, MonoLinkedListSetNode *value)
 {
        MonoLinkedListSetNode *cur, **prev, *next;
        while (1) {
-               if (!mono_lls_find (list, hp, value->key, context))
+               if (!mono_lls_find (list, hp, value->key))
                        return FALSE;
 
                next = (MonoLinkedListSetNode *) mono_hazard_pointer_get_val (hp, 0);
@@ -198,9 +185,9 @@ mono_lls_remove (MonoLinkedListSet *list, MonoThreadHazardPointers *hp, MonoLink
                        mono_memory_write_barrier ();
                        mono_hazard_pointer_clear (hp, 1);
                        if (list->free_node_func)
-                               mono_thread_hazardous_try_free (value, list->free_node_func);
+                               mono_thread_hazardous_queue_free (value, list->free_node_func);
                } else
-                       mono_lls_find (list, hp, value->key, context);
+                       mono_lls_find (list, hp, value->key);
                return TRUE;
        }
 }
index 947602f0c34e2177d3a829fd6863850208d24c6f..ee4d77799ec50d1d54573851d4c20994899a21de 100644 (file)
@@ -24,7 +24,6 @@ struct _MonoLinkedListSetNode {
 typedef struct {
        MonoLinkedListSetNode *head;
        void (*free_node_func)(void *);
-       HazardFreeLocking locking;
 } MonoLinkedListSet;
 
 
@@ -45,20 +44,20 @@ Those are low level operations. prev, cur, next are returned in the hazard point
 You must manually clean the hazard pointer table after using them.
 */
 
-void
-mono_lls_init (MonoLinkedListSet *list, void (*free_node_func)(void *), HazardFreeLocking free_node_func_locking);
+MONO_API void
+mono_lls_init (MonoLinkedListSet *list, void (*free_node_func)(void *));
 
-gboolean
-mono_lls_find (MonoLinkedListSet *list, MonoThreadHazardPointers *hp, uintptr_t key, HazardFreeContext context);
+MONO_API gboolean
+mono_lls_find (MonoLinkedListSet *list, MonoThreadHazardPointers *hp, uintptr_t key);
 
-gboolean
-mono_lls_insert (MonoLinkedListSet *list, MonoThreadHazardPointers *hp, MonoLinkedListSetNode *value, HazardFreeContext context);
+MONO_API gboolean
+mono_lls_insert (MonoLinkedListSet *list, MonoThreadHazardPointers *hp, MonoLinkedListSetNode *value);
 
-gboolean
-mono_lls_remove (MonoLinkedListSet *list, MonoThreadHazardPointers *hp, MonoLinkedListSetNode *value, HazardFreeContext context);
+MONO_API gboolean
+mono_lls_remove (MonoLinkedListSet *list, MonoThreadHazardPointers *hp, MonoLinkedListSetNode *value);
 
-gpointer
-get_hazardous_pointer_with_mask (gpointer volatile *pp, MonoThreadHazardPointers *hp, int hazard_index);
+MONO_API gpointer
+mono_lls_get_hazardous_pointer_with_mask (gpointer volatile *pp, MonoThreadHazardPointers *hp, int hazard_index);
 
 static inline gboolean
 mono_lls_filter_accept_all (gpointer elem)
@@ -108,12 +107,12 @@ mono_lls_filter_accept_all (gpointer elem)
                        restart__ = FALSE; \
                        MonoLinkedListSetNode **prev__ = &list__->head; \
                        mono_hazard_pointer_set (hp__, 2, prev__); \
-                       MonoLinkedListSetNode *cur__ = (MonoLinkedListSetNode *) get_hazardous_pointer_with_mask ((gpointer *) prev__, hp__, 1); \
+                       MonoLinkedListSetNode *cur__ = (MonoLinkedListSetNode *) mono_lls_get_hazardous_pointer_with_mask ((gpointer *) prev__, hp__, 1); \
                        while (1) { \
                                if (!cur__) { \
                                        break; \
                                } \
-                               MonoLinkedListSetNode *next__ = (MonoLinkedListSetNode *) get_hazardous_pointer_with_mask ((gpointer *) &cur__->next, hp__, 0); \
+                               MonoLinkedListSetNode *next__ = (MonoLinkedListSetNode *) mono_lls_get_hazardous_pointer_with_mask ((gpointer *) &cur__->next, hp__, 0); \
                                uintptr_t ckey__ = cur__->key; \
                                mono_memory_read_barrier (); \
                                if (*prev__ != cur__) { \
index 60f6164dc4511921906c9076701ea86db707f50e..b59ffff85f93b28573c3089420381f8eeef6b484 100644 (file)
@@ -56,21 +56,6 @@ static inline void mono_memory_read_barrier (void)
        mono_memory_barrier ();
 }
 
-static inline void mono_memory_write_barrier (void)
-{
-       mono_memory_barrier ();
-}
-#elif defined(__ia64__)
-static inline void mono_memory_barrier (void)
-{
-       __asm__ __volatile__ ("mf" : : : "memory");
-}
-
-static inline void mono_memory_read_barrier (void)
-{
-       mono_memory_barrier ();
-}
-
 static inline void mono_memory_write_barrier (void)
 {
        mono_memory_barrier ();
index 60f5585e1823dbb35454d0a5197cc0886d02efc0..c92f7bb316f814400e151a10f59a798ca5a74697 100644 (file)
@@ -228,17 +228,6 @@ mono_threads_platform_create_thread (MonoThreadStart start_routine, gpointer arg
        return start_info.handle;
 }
 
-/*
- * mono_threads_platform_resume_created:
- *
- *   Resume a newly created thread created using CREATE_SUSPENDED.
- */
-void
-mono_threads_platform_resume_created (MonoThreadInfo *info, MonoNativeThreadId tid)
-{
-       mono_coop_sem_post (&info->create_suspended_sem);
-}
-
 gboolean
 mono_threads_platform_yield (void)
 {
index f66e6936b6dc1df123ab5060db34eb65a74ef86f..97f75f0db1e5544155933bf8846256723c9f8b36 100644 (file)
@@ -154,7 +154,6 @@ typedef struct {
        gint32 priority;
        MonoCoopSem registered;
        gboolean suspend;
-       HANDLE suspend_event;
        HANDLE handle;
 } ThreadStartInfo;
 
@@ -166,22 +165,28 @@ inner_start_thread (LPVOID arg)
        LPTHREAD_START_ROUTINE start_func = start_info->start_routine;
        DWORD result;
        gboolean suspend = start_info->suspend;
-       HANDLE suspend_event = start_info->suspend_event;
        MonoThreadInfo *info;
+       int res;
 
        info = mono_thread_info_attach (&result);
        info->runtime_thread = TRUE;
-       info->create_suspended = suspend;
 
        start_info->handle = info->handle;
 
        mono_threads_platform_set_priority(info, start_info->priority);
 
+       if (suspend) {
+               info->create_suspended = TRUE;
+               mono_coop_sem_init (&info->create_suspended_sem, 0);
+       }
+
        mono_coop_sem_post (&(start_info->registered));
 
        if (suspend) {
-               WaitForSingleObject (suspend_event, INFINITE); /* caller will suspend the thread before setting the event. */
-               CloseHandle (suspend_event);
+               res = mono_coop_sem_wait (&info->create_suspended_sem, MONO_SEM_FLAGS_NONE);
+               g_assert (res != -1);
+
+               mono_coop_sem_destroy (&info->create_suspended_sem);
        }
 
        result = start_func (t_arg);
@@ -207,11 +212,6 @@ mono_threads_platform_create_thread (MonoThreadStart start_routine, gpointer arg
        start_info.suspend = creation_flags & CREATE_SUSPENDED;
        start_info.priority = tp->priority;
        creation_flags &= ~CREATE_SUSPENDED;
-       if (start_info.suspend) {
-               start_info.suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
-               if (!start_info.suspend_event)
-                       return NULL;
-       }
 
        result = CreateThread (NULL, tp->stack_size, inner_start_thread, &start_info, creation_flags, &thread_id);
        if (result) {
@@ -221,13 +221,6 @@ mono_threads_platform_create_thread (MonoThreadStart start_routine, gpointer arg
                /* A new handle has been opened when attaching
                 * the thread, so we don't need this one */
                CloseHandle (result);
-
-               if (start_info.suspend) {
-                       g_assert (SuspendThread (start_info.handle) != (DWORD)-1);
-                       SetEvent (start_info.suspend_event);
-               }
-       } else if (start_info.suspend) {
-               CloseHandle (start_info.suspend_event);
        }
        if (out_tid)
                *out_tid = thread_id;
@@ -254,17 +247,6 @@ mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
        return CreateThread (NULL, 0, (func), (arg), 0, (tid)) != NULL;
 }
 
-void
-mono_threads_platform_resume_created (MonoThreadInfo *info, MonoNativeThreadId tid)
-{
-       HANDLE handle;
-
-       handle = OpenThread (THREAD_ALL_ACCESS, TRUE, tid);
-       g_assert (handle);
-       ResumeThread (handle);
-       CloseHandle (handle);
-}
-
 #if HAVE_DECL___READFSDWORD==0
 static MONO_ALWAYS_INLINE unsigned long long
 __readfsdword (unsigned long offset)
index 5add7fe0f86f32f82803d805762bd4d865e4d78e..12c95c7861bda5eb2bb8f92d3efce2e72dac577d 100644 (file)
@@ -281,7 +281,7 @@ mono_thread_info_lookup (MonoNativeThreadId id)
 {
                MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
 
-       if (!mono_lls_find (&thread_list, hp, (uintptr_t)id, HAZARD_FREE_ASYNC_CTX)) {
+       if (!mono_lls_find (&thread_list, hp, (uintptr_t)id)) {
                mono_hazard_pointer_clear_all (hp, -1);
                return NULL;
        } 
@@ -295,7 +295,7 @@ mono_thread_info_insert (MonoThreadInfo *info)
 {
        MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
 
-       if (!mono_lls_insert (&thread_list, hp, (MonoLinkedListSetNode*)info, HAZARD_FREE_SAFE_CTX)) {
+       if (!mono_lls_insert (&thread_list, hp, (MonoLinkedListSetNode*)info)) {
                mono_hazard_pointer_clear_all (hp, -1);
                return FALSE;
        } 
@@ -311,7 +311,7 @@ mono_thread_info_remove (MonoThreadInfo *info)
        gboolean res;
 
        THREADS_DEBUG ("removing info %p\n", info);
-       res = mono_lls_remove (&thread_list, hp, (MonoLinkedListSetNode*)info, HAZARD_FREE_SAFE_CTX);
+       res = mono_lls_remove (&thread_list, hp, (MonoLinkedListSetNode*)info);
        mono_hazard_pointer_clear_all (hp, -1);
        return res;
 }
@@ -691,7 +691,7 @@ mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size)
        mono_os_sem_init (&global_suspend_semaphore, 1);
        mono_os_sem_init (&suspend_semaphore, 0);
 
-       mono_lls_init (&thread_list, NULL, HAZARD_FREE_NO_LOCK);
+       mono_lls_init (&thread_list, NULL);
        mono_thread_smr_init ();
        mono_threads_platform_init ();
        mono_threads_suspend_init ();
@@ -770,7 +770,7 @@ mono_thread_info_core_resume (MonoThreadInfo *info)
                MonoNativeThreadId tid = mono_thread_info_get_tid (info);
                /* Have to special case this, as the normal suspend/resume pair are racy, they don't work if he resume is received before the suspend */
                info->create_suspended = FALSE;
-               mono_threads_platform_resume_created (info, tid);
+               mono_coop_sem_post (&info->create_suspended_sem);
                return TRUE;
        }
 
index 96e197980a05fce513369c12755c83b74a836c9d..a59430e855cf2b374f77fd96db6022890b693862 100644 (file)
@@ -416,7 +416,7 @@ mono_thread_info_is_async_context (void);
 void
 mono_thread_info_get_stack_bounds (guint8 **staddr, size_t *stsize);
 
-gboolean
+MONO_API gboolean
 mono_thread_info_yield (void);
 
 gint
@@ -536,7 +536,6 @@ gboolean mono_threads_suspend_needs_abort_syscall (void);
 void mono_threads_platform_register (THREAD_INFO_TYPE *info);
 void mono_threads_platform_unregister (THREAD_INFO_TYPE *info);
 HANDLE mono_threads_platform_create_thread (MonoThreadStart start, gpointer arg, MonoThreadParm *, MonoNativeThreadId *out_tid);
-void mono_threads_platform_resume_created (THREAD_INFO_TYPE *info, MonoNativeThreadId tid);
 void mono_threads_platform_get_stack_bounds (guint8 **staddr, size_t *stsize);
 gboolean mono_threads_platform_yield (void);
 void mono_threads_platform_exit (int exit_code);