IgnoreRemoved {
get { return ignoreRemoved; }
@@ -83,11 +88,12 @@ public static int Main (string[] args)
var options = new OptionSet {
{ "h|help", "Show this help", v => showHelp = true },
{ "d|diff=", "HTML diff file out output (omit for stdout)", v => diff = v },
- { "i|ignore=", "Ignore both added and removed members whose description matches a given C# regular expression (see below).",
+ { "i|ignore=", "Ignore new, added, and removed members whose description matches a given C# regular expression (see below).",
v => {
var r = new Regex (v);
State.IgnoreAdded.Add (r);
State.IgnoreRemoved.Add (r);
+ State.IgnoreNew.Add (r);
}
},
{ "a|ignore-added=", "Ignore added members whose description matches a given C# regular expression (see below).",
@@ -96,6 +102,9 @@ public static int Main (string[] args)
{ "r|ignore-removed=", "Ignore removed members whose description matches a given C# regular expression (see below).",
v => State.IgnoreRemoved.Add (new Regex (v))
},
+ { "n|ignore-new=", "Ignore new namespaces and types whose description matches a given C# regular expression (see below).",
+ v => State.IgnoreNew.Add (new Regex (v))
+ },
{ "x|lax", "Ignore duplicate XML entries", v => State.Lax = true }
};
diff --git a/mcs/tools/corcompare/mono-api-html/ClassComparer.cs b/mcs/tools/corcompare/mono-api-html/ClassComparer.cs
index bdf22fea489..d96613c3e8a 100644
--- a/mcs/tools/corcompare/mono-api-html/ClassComparer.cs
+++ b/mcs/tools/corcompare/mono-api-html/ClassComparer.cs
@@ -27,6 +27,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Xml.Linq;
namespace Xamarin.ApiDiff {
@@ -68,7 +69,10 @@ public void Compare (XElement source, XElement target)
public override void Added (XElement target)
{
- Output.WriteLine ("New Type {0}.{1}
", State.Namespace, target.Attribute ("name").Value);
+ string name = target.Attribute ("name").Value;
+ if (State.IgnoreNew.Any (re => re.IsMatch (name)))
+ return;
+ Output.WriteLine ("New Type {0}.{1}
", State.Namespace, name);
Output.WriteLine ("");
State.Indent = 0;
AddedInner (target);
diff --git a/mcs/tools/corcompare/mono-api-html/NamespaceComparer.cs b/mcs/tools/corcompare/mono-api-html/NamespaceComparer.cs
index 7239385870e..427df66e6eb 100644
--- a/mcs/tools/corcompare/mono-api-html/NamespaceComparer.cs
+++ b/mcs/tools/corcompare/mono-api-html/NamespaceComparer.cs
@@ -26,6 +26,7 @@
using System;
using System.IO;
+using System.Linq;
using System.Xml.Linq;
namespace Xamarin.ApiDiff {
@@ -55,7 +56,11 @@ public override void SetContext (XElement current)
public override void Added (XElement target)
{
- Output.WriteLine ("New Namespace {0}
", target.Attribute ("name").Value);
+ string name = target.Attribute ("name").Value;
+ if (State.IgnoreNew.Any (re => re.IsMatch (name)))
+ return;
+
+ Output.WriteLine ("New Namespace {0}
", name);
Output.WriteLine ();
// list all new types
foreach (var addedType in target.Element ("classes").Elements ("class"))
diff --git a/mcs/tools/corcompare/mono-api-info.cs b/mcs/tools/corcompare/mono-api-info.cs
index 2dc4bcebb3d..a689210b12b 100644
--- a/mcs/tools/corcompare/mono-api-info.cs
+++ b/mcs/tools/corcompare/mono-api-info.cs
@@ -545,6 +545,9 @@ static string GetClassType (TypeDefinition t)
if (TypeHelper.IsDelegate(t))
return "delegate";
+ if (t.IsPointer)
+ return "pointer";
+
return "class";
}
@@ -907,6 +910,8 @@ protected override void AddExtraData (XmlNode p, MemberReference memberDefenitio
AddAttribute (p, "abstract", "true");
if (mbase.IsVirtual)
AddAttribute (p, "virtual", "true");
+ if (mbase.IsFinal && mbase.IsVirtual && mbase.IsReuseSlot)
+ AddAttribute (p, "sealed", "true");
if (mbase.IsStatic)
AddAttribute (p, "static", "true");
diff --git a/mcs/tools/linker/Descriptors/System.xml b/mcs/tools/linker/Descriptors/System.xml
index 181a3ebc36c..f70c020412d 100644
--- a/mcs/tools/linker/Descriptors/System.xml
+++ b/mcs/tools/linker/Descriptors/System.xml
@@ -13,6 +13,7 @@
+
diff --git a/mcs/tools/mdoc/Makefile b/mcs/tools/mdoc/Makefile
index e4ff1eed87c..3b7e698d604 100644
--- a/mcs/tools/mdoc/Makefile
+++ b/mcs/tools/mdoc/Makefile
@@ -90,9 +90,23 @@ cleanup:
-rm -Rf Test/en.actual Test/html.actual
-rm -f monodocer1.exe*
+Test/DocTest-DropNS-classic-secondary.dll:
+ @echo $(value @)
+ $(CSCOMPILE) $(TEST_CSCFLAGS) -debug -unsafe -target:library -out:$@ Test/DocTest-DropNS-classic-secondary.cs
+
+Test/DocTest-DropNS-classic.dll:
+ @echo $(value @)
+ $(CSCOMPILE) $(TEST_CSCFLAGS) -debug -unsafe -target:library -out:$@ Test/DocTest-DropNS-classic.cs
+
+Test/DocTest-DropNS-unified.dll:
+ $(CSCOMPILE) $(TEST_CSCFLAGS) -debug -unsafe -target:library -out:$@ Test/DocTest-DropNS-unified.cs
+
Test/DocTest.dll:
$(CSCOMPILE) $(TEST_CSCFLAGS) -debug -unsafe -target:library -out:$@ Test/DocTest.cs
+Test/DocTest-InternalInterface.dll:
+ $(CSCOMPILE) $(TEST_CSCFLAGS) -debug -unsafe -target:library -out:$@ Test/DocTest-InternalInterface.cs
+
Test/DocTest.dll-v1:
-rm -f Test/DocTest.cs
cp Test/DocTest-v1.cs Test/DocTest.cs
@@ -106,6 +120,42 @@ Test/DocTest.dll-v2:
-rm -f Test/DocTest.dll
$(MAKE) TEST_CSCFLAGS=$(TEST_CSCFLAGS) Test/DocTest.dll
+check-monodocer-dropns-classic: $(PROGRAM)
+ # tests the simplest --dropns case, a single class where the root namespace was dropped.
+ -rm -Rf Test/en.actual
+ $(MAKE) Test/DocTest-DropNS-classic.dll
+ $(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual Test/DocTest-DropNS-classic.dll
+ $(MAKE) update-monodocer-dropns-unified
+ diff --exclude=.svn -rup Test/en.expected-dropns-classic-v1 Test/en.actual
+
+check-monodocer-dropns-classic-withsecondary: $(PROGRAM)
+ # tests case where a secondary assembly is included with a --dropns parameter
+ -rm -Rf Test/en.actual
+ $(MAKE) Test/DocTest-DropNS-classic.dll
+ $(MAKE) Test/DocTest-DropNS-classic-secondary.dll
+ $(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual Test/DocTest-DropNS-classic.dll Test/DocTest-DropNS-classic-secondary.dll
+ $(MAKE) update-monodocer-dropns-unified-withsecondary
+ diff --exclude=.svn -rup Test/en.expected-dropns-classic-withsecondary Test/en.actual
+
+update-monodocer-dropns-unified: $(PROGRAM)
+ $(MAKE) Test/DocTest-DropNS-unified.dll
+ $(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual Test/DocTest-DropNS-unified.dll --dropns Test/DocTest-DropNS-unified.dll=MyFramework
+
+update-monodocer-dropns-unified-withsecondary: $(PROGRAM)
+ $(MAKE) Test/DocTest-DropNS-unified.dll
+ $(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual Test/DocTest-DropNS-unified.dll Test/DocTest-DropNS-classic-secondary.dll --dropns Test/DocTest-DropNS-unified.dll=MyFramework
+
+update-monodocer-dropns-classic-secondary: $(PROGRAM)
+ $(MAKE) Test/DocTest-DropNS-classic-secondary.dll
+ $(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual Test/DocTest-DropNS-classic-secondary.dll
+
+check-monodocer-internal-interface: $(PROGRAM)
+ # Tests to make sure internal interfaces that are explicitly implemented are not documented
+ -rm -Rf Test/en.actual
+ $(MAKE) Test/DocTest-InternalInterface.dll
+ $(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual Test/DocTest-InternalInterface.dll
+ diff --exclude=.svn -rup Test/en.expected-internal-interface Test/en.actual
+
check-monodocer-update: $(PROGRAM)
find Test/en.expected -name \*.xml -exec rm "{}" \;
$(MAKE) Test/DocTest.dll-v1
@@ -262,8 +312,12 @@ check-doc-tools-update: check-monodocer-since-update \
check-monodocer-importecmadoc-update \
check-monodocer-importslashdoc-update \
check-monodocer-update \
+ check-monodocer-dropns-classic \
+ check-monodocer-dropns-classic-withsecondary \
+ check-monodocer-internal-interface \
check-monodocer-delete-update \
check-mdoc-export-html-update \
check-mdoc-export-msxdoc-update \
- check-mdoc-validate-update
+ check-mdoc-validate-update
+
diff --git a/mcs/tools/mdoc/Mono.Documentation/monodocer.cs b/mcs/tools/mdoc/Mono.Documentation/monodocer.cs
index 75a6d5ca63e..842a4ae439f 100644
--- a/mcs/tools/mdoc/Mono.Documentation/monodocer.cs
+++ b/mcs/tools/mdoc/Mono.Documentation/monodocer.cs
@@ -120,7 +120,7 @@ public static string GetTranslatedName(TypeReference t) {
string typename = t.FullName;
bool isInAssembly = MDocUpdater.IsInAssemblies (t.Module.Name);
- if (isInAssembly && MDocUpdater.HasDroppedNamespace () && !typename.StartsWith ("System")) {
+ if (isInAssembly && !typename.StartsWith ("System") && MDocUpdater.HasDroppedNamespace (t)) {
string nameWithDropped = string.Format ("{0}.{1}", MDocUpdater.droppedNamespace, typename);
return nameWithDropped;
}
@@ -166,9 +166,30 @@ class MDocUpdater : MDocCommand
HashSet forwardedTypes = new HashSet ();
public static string droppedNamespace = string.Empty;
- public static bool HasDroppedNamespace() {
- return !string.IsNullOrWhiteSpace (droppedNamespace);
+
+ public static bool HasDroppedNamespace(TypeDefinition forType)
+ {
+ return HasDroppedNamespace(forType.Module);
+ }
+
+ public static bool HasDroppedNamespace(MemberReference forMember)
+ {
+ return HasDroppedNamespace(forMember.Module);
+ }
+
+ public static bool HasDroppedNamespace(AssemblyDefinition forAssembly)
+ {
+ return HasDroppedNamespace(forAssembly.MainModule);
}
+
+ public static bool HasDroppedNamespace(ModuleDefinition forModule)
+ {
+ return !string.IsNullOrWhiteSpace (droppedNamespace) && droppedAssemblies.Any(da => da == forModule.Name);
+ }
+
+
+ static List droppedAssemblies = new List();
+
public string PreserveTag { get; set; }
public static MDocUpdater Instance { get; private set; }
public static bool SwitchingToMagicTypes { get; private set; }
@@ -236,8 +257,16 @@ public override void Run (IEnumerable args)
"Only update documentation for {TYPE}.",
v => types.Add (v) },
{ "dropns=",
- "Instructs the update process that {NAMESPACE} has been dropped, so that types and members will match existing documentation nodes.",
- v => droppedNamespace = v },
+ "When processing assembly {ASSEMBLY}, strip off leading namespace {PREFIX}:\n" +
+ " e.g. --dropns ASSEMBLY=PREFIX",
+ v => {
+ var parts = v.Split ('=');
+ if (parts.Length != 2) { Console.Error.WriteLine ("Invalid dropns input"); return; }
+ var assembly = Path.GetFileName (parts [0].Trim ());
+ var prefix = parts [1].Trim();
+ droppedAssemblies.Add (assembly);
+ droppedNamespace = prefix;
+ } },
{ "ntypes",
"If the new assembly is switching to 'magic types', then this switch should be defined.",
v => SwitchingToMagicTypes = true },
@@ -580,7 +609,7 @@ public string DoUpdateType (TypeDefinition type, string basepath, string dest)
nsname
};
- if (MDocUpdater.HasDroppedNamespace ()) {
+ if (MDocUpdater.HasDroppedNamespace (type)) {
// If dropping namespace, types may have moved into a couple of different places.
var newSearchLocations = searchLocations.Union (new string[] {
string.Format ("{0}.{1}", droppedNamespace, nsname),
@@ -847,10 +876,10 @@ private void DoUpdateAssembly (AssemblyDefinition assembly, XmlElement index_typ
// Add namespace and type nodes into the index file as needed
AddIndexType (type, index_types);
-
+
// Ensure the namespace index file exists
string namespaceToUse = type.Namespace;
- if (HasDroppedNamespace()) {
+ if (HasDroppedNamespace(assembly)) {
namespaceToUse = string.Format ("{0}.{1}", droppedNamespace, namespaceToUse);
}
string onsdoc = DocUtils.PathCombine (dest, namespaceToUse + ".xml");
@@ -951,7 +980,7 @@ private static string GetTypeKind (TypeDefinition type)
throw new ArgumentException ("Unknown kind for type: " + type.FullName);
}
- private static bool IsPublic (TypeDefinition type)
+ public static bool IsPublic (TypeDefinition type)
{
TypeDefinition decl = type;
while (decl != null) {
@@ -974,7 +1003,9 @@ private void CleanupFiles (string dest, HashSet goodfiles)
XmlDocument doc = new XmlDocument ();
doc.Load (typefile.FullName);
XmlElement e = doc.SelectSingleNode("/Type") as XmlElement;
- if (e != null && !no_assembly_versions && UpdateAssemblyVersions(e, GetAssemblyVersions(), false)) {
+ string assemblyName = doc.SelectSingleNode ("/Type/AssemblyInfo/AssemblyName").InnerText;
+ AssemblyDefinition assembly = assemblies.FirstOrDefault (a => a.Name.Name == assemblyName);
+ if (e != null && !no_assembly_versions && assembly != null && assemblyName != null && UpdateAssemblyVersions(e, assembly, GetAssemblyVersions(assemblyName), false)) {
using (TextWriter writer = OpenWrite (typefile.FullName, FileMode.Truncate))
WriteXml(doc.DocumentElement, writer);
goodfiles.Add (relTypeFile);
@@ -1002,9 +1033,11 @@ private static TextWriter OpenWrite (string path, FileMode mode)
return w;
}
- private string[] GetAssemblyVersions ()
+ private string[] GetAssemblyVersions (string assemblyName)
{
- return (from a in assemblies select GetAssemblyVersion (a)).ToArray ();
+ return (from a in assemblies
+ where a.Name.Name == assemblyName
+ select GetAssemblyVersion (a)).ToArray ();
}
private static void CleanupIndexTypes (XmlElement index_types, HashSet goodfiles)
@@ -1088,10 +1121,10 @@ public void DoUpdateType2 (string message, XmlDocument basefile, TypeDefinition
// Deleted (or signature changed)
if (oldmember2 == null) {
- if (!no_assembly_versions && UpdateAssemblyVersions (oldmember, new string[]{ GetAssemblyVersion (type.Module.Assembly) }, false))
+ if (!no_assembly_versions && UpdateAssemblyVersions (oldmember, type.Module.Assembly, new string[]{ GetAssemblyVersion (type.Module.Assembly) }, false))
continue;
- DeleteMember ("Member Removed", output, oldmember, todelete);
+ DeleteMember ("Member Removed", output, oldmember, todelete, type);
continue;
}
@@ -1101,7 +1134,7 @@ public void DoUpdateType2 (string message, XmlDocument basefile, TypeDefinition
// ignore, already seen
}
else if (DefaultMemberComparer.Compare (oldmember, seenmembers [sig]) == 0)
- DeleteMember ("Duplicate Member Found", output, oldmember, todelete);
+ DeleteMember ("Duplicate Member Found", output, oldmember, todelete, type);
else
Warning ("TODO: found a duplicate member '{0}', but it's not identical to the prior member found!", sig);
continue;
@@ -1131,6 +1164,27 @@ public void DoUpdateType2 (string message, XmlDocument basefile, TypeDefinition
string sig = memberFormatters [0].GetDeclaration (m);
if (sig == null) return false;
if (seenmembers.ContainsKey(sig)) return false;
+
+ // Verify that the member isn't an explicitly implemented
+ // member of an internal interface, in which case we shouldn't return true.
+ MethodDefinition methdef = null;
+ if (m is MethodDefinition)
+ methdef = m as MethodDefinition;
+ else if (m is PropertyDefinition) {
+ var prop = m as PropertyDefinition;
+ methdef = prop.GetMethod ?? prop.SetMethod;
+ }
+
+ if (methdef != null) {
+ TypeReference iface;
+ MethodReference imethod;
+
+ if (methdef.Overrides.Count == 1) {
+ DocUtils.GetInfoForExplicitlyImplementedMethod (methdef, out iface, out imethod);
+ if (!IsPublic (iface.Resolve ())) return false;
+ }
+ }
+
return true;
})
.ToArray();
@@ -1232,7 +1286,7 @@ private string GetCodeSource (string lang, string file)
return null;
}
- void DeleteMember (string reason, string output, XmlNode member, MyXmlNodeList todelete)
+ void DeleteMember (string reason, string output, XmlNode member, MyXmlNodeList todelete, TypeDefinition type)
{
string format = output != null
? "{0}: File='{1}'; Signature='{4}'"
@@ -1245,7 +1299,7 @@ void DeleteMember (string reason, string output, XmlNode member, MyXmlNodeList t
member.SelectSingleNode ("MemberSignature[@Language='C#']/@Value").Value);
if (!delete && MemberDocsHaveUserContent (member)) {
Warning ("Member deletions must be enabled with the --delete option.");
- } else if (HasDroppedNamespace ()) {
+ } else if (HasDroppedNamespace (type)) {
// if we're dropping the namespace, add the "classic style"
var existingAttribute = member.Attributes ["apistyle"];
if (existingAttribute != null) {
@@ -1258,7 +1312,7 @@ void DeleteMember (string reason, string output, XmlNode member, MyXmlNodeList t
member.Attributes.Append (apistyleAttr);
}
- } else if (!HasDroppedNamespace () && member.Attributes ["apistyle"] != null && member.Attributes ["apistyle"].Value == "unified") {
+ } else if (!HasDroppedNamespace (type) && member.Attributes ["apistyle"] != null && member.Attributes ["apistyle"].Value == "unified") {
// do nothing if there's an apistyle=new attribute and we haven't dropped the namespace
} else if (!string.IsNullOrWhiteSpace (PreserveTag)) {
// do nothing
@@ -1400,10 +1454,11 @@ public void UpdateType (XmlElement root, TypeDefinition type)
var node = WriteElementAttribute (root, element, "Language", f.Language, forceNewElement: true);
var newnode = WriteElementAttribute (root, node, "Value", valueToUse);
return newnode;
- });
+ },
+ type);
}
- string assemblyInfoNodeFilter = MDocUpdater.HasDroppedNamespace () ? "[@apistyle='unified']" : "[not(@apistyle) or @apistyle='classic']";
+ string assemblyInfoNodeFilter = MDocUpdater.HasDroppedNamespace (type) ? "[@apistyle='unified']" : "[not(@apistyle) or @apistyle='classic']";
AddXmlNode(
root.SelectNodes ("AssemblyInfo" + assemblyInfoNodeFilter).Cast ().ToArray (),
@@ -1412,12 +1467,13 @@ public void UpdateType (XmlElement root, TypeDefinition type)
() => {
XmlElement ass = WriteElement(root, "AssemblyInfo", forceNewElement:true);
- if (MDocUpdater.HasDroppedNamespace ()) ass.SetAttribute ("apistyle", "unified");
+ if (MDocUpdater.HasDroppedNamespace (type)) ass.SetAttribute ("apistyle", "unified");
return ass;
- });
+ },
+ type);
foreach(var ass in root.SelectNodes ("AssemblyInfo" + assemblyInfoNodeFilter).Cast ())
{
@@ -1448,7 +1504,7 @@ public void UpdateType (XmlElement root, TypeDefinition type)
}
if (type.IsGenericType ()) {
- MakeTypeParameters (root, type.GenericParameters, MDocUpdater.HasDroppedNamespace());
+ MakeTypeParameters (root, type.GenericParameters, type, MDocUpdater.HasDroppedNamespace(type));
} else {
ClearElement(root, "TypeParameters");
}
@@ -1505,9 +1561,10 @@ public void UpdateType (XmlElement root, TypeDefinition type)
MakeAttributes (root, GetCustomAttributes (type), type);
if (DocUtils.IsDelegate (type)) {
- MakeTypeParameters (root, type.GenericParameters, MDocUpdater.HasDroppedNamespace());
- MakeParameters(root, type.GetMethod("Invoke").Parameters);
- MakeReturnValue(root, type.GetMethod("Invoke"));
+ MakeTypeParameters (root, type.GenericParameters, type, MDocUpdater.HasDroppedNamespace(type));
+ var member = type.GetMethod ("Invoke");
+ MakeParameters(root, member, member.Parameters);
+ MakeReturnValue(root, member);
}
DocsNodeInfo typeInfo = new DocsNodeInfo (WriteElement(root, "Docs"), type);
@@ -1567,7 +1624,8 @@ private void UpdateMember (DocsNodeInfo info)
var node = WriteElementAttribute (me, element, "Language", f.Language, forceNewElement:true);
var newNode = WriteElementAttribute (me, node, "Value", valueToUse);
return newNode;
- });
+ },
+ mi);
}
@@ -1582,13 +1640,13 @@ private void UpdateMember (DocsNodeInfo info)
MakeAttributes (me, GetCustomAttributes (mi), mi.DeclaringType);
- MakeReturnValue(me, mi, MDocUpdater.HasDroppedNamespace());
+ MakeReturnValue(me, mi, MDocUpdater.HasDroppedNamespace(mi));
if (mi is MethodReference) {
MethodReference mb = (MethodReference) mi;
if (mb.IsGenericMethod ())
- MakeTypeParameters (me, mb.GenericParameters, MDocUpdater.HasDroppedNamespace());
+ MakeTypeParameters (me, mb.GenericParameters, mi, MDocUpdater.HasDroppedNamespace(mi));
}
- MakeParameters(me, mi, MDocUpdater.HasDroppedNamespace());
+ MakeParameters(me, mi, MDocUpdater.HasDroppedNamespace(mi));
string fieldValue;
if (mi is FieldDefinition && GetFieldConstValue ((FieldDefinition)mi, out fieldValue))
@@ -1600,14 +1658,22 @@ private void UpdateMember (DocsNodeInfo info)
UpdateExtensionMethods (me, info);
}
+ static void AddXmlNode (XmlElement[] relevant, Func valueMatches, Action setValue, Func makeNewNode, MemberReference member) {
+ AddXmlNode (relevant, valueMatches, setValue, makeNewNode, member.Module);
+ }
+
+ static void AddXmlNode (XmlElement[] relevant, Func valueMatches, Action setValue, Func makeNewNode, TypeDefinition type) {
+ AddXmlNode (relevant, valueMatches, setValue, makeNewNode, type.Module);
+ }
+
/// Adds an xml node, reusing the node if it's available
/// The existing set of nodes
/// Checks to see if the node's value matches what you're trying to write.
/// Sets the node's value
/// Creates a new node, if valueMatches returns false.
- static void AddXmlNode (XmlElement[] relevant, Func valueMatches, Action setValue, Func makeNewNode)
+ static void AddXmlNode (XmlElement[] relevant, Func valueMatches, Action setValue, Func makeNewNode, ModuleDefinition module)
{
- bool shouldDuplicate = MDocUpdater.HasDroppedNamespace ();
+ bool shouldDuplicate = MDocUpdater.HasDroppedNamespace (module);
var styleToUse = shouldDuplicate ? ApiStyle.Unified : ApiStyle.Classic;
var existing = relevant;
bool done = false;
@@ -2164,7 +2230,7 @@ private static bool UpdateAssemblyVersions (XmlElement root, MemberReference mem
TypeDefinition type = member as TypeDefinition;
if (type == null)
type = member.DeclaringType as TypeDefinition;
- return UpdateAssemblyVersions(root, new string[]{ GetAssemblyVersion (type.Module.Assembly) }, add);
+ return UpdateAssemblyVersions(root, type.Module.Assembly, new string[]{ GetAssemblyVersion (type.Module.Assembly) }, add);
}
private static string GetAssemblyVersion (AssemblyDefinition assembly)
@@ -2172,7 +2238,7 @@ private static string GetAssemblyVersion (AssemblyDefinition assembly)
return assembly.Name.Version.ToString();
}
- private static bool UpdateAssemblyVersions(XmlElement root, string[] assemblyVersions, bool add)
+ private static bool UpdateAssemblyVersions(XmlElement root, AssemblyDefinition assembly, string[] assemblyVersions, bool add)
{
XmlElement av = (XmlElement) root.SelectSingleNode ("AssemblyVersions");
if (av != null) {
@@ -2182,14 +2248,14 @@ private static bool UpdateAssemblyVersions(XmlElement root, string[] assemblyVer
string oldNodeFilter = "AssemblyInfo[not(@apistyle) or @apistyle='classic']";
string newNodeFilter = "AssemblyInfo[@apistyle='unified']";
- string thisNodeFilter = MDocUpdater.HasDroppedNamespace () ? newNodeFilter : oldNodeFilter;
- string thatNodeFilter = MDocUpdater.HasDroppedNamespace () ? oldNodeFilter : newNodeFilter;
+ string thisNodeFilter = MDocUpdater.HasDroppedNamespace (assembly) ? newNodeFilter : oldNodeFilter;
+ string thatNodeFilter = MDocUpdater.HasDroppedNamespace (assembly) ? oldNodeFilter : newNodeFilter;
XmlElement e = (XmlElement) root.SelectSingleNode (thisNodeFilter);
if (e == null) {
e = root.OwnerDocument.CreateElement("AssemblyInfo");
- if (MDocUpdater.HasDroppedNamespace ()) {
+ if (MDocUpdater.HasDroppedNamespace (assembly)) {
e.SetAttribute ("apistyle", "unified");
}
@@ -2197,7 +2263,7 @@ private static bool UpdateAssemblyVersions(XmlElement root, string[] assemblyVer
}
var thatNode = (XmlElement) root.SelectSingleNode (thatNodeFilter);
- if (MDocUpdater.HasDroppedNamespace () && thatNode != null) {
+ if (MDocUpdater.HasDroppedNamespace (assembly) && thatNode != null) {
// there's a classic node, we should add apistyles
e.SetAttribute ("apistyle", "unified");
thatNode.SetAttribute ("apistyle", "classic");
@@ -2333,7 +2399,7 @@ static long ToInt64 (object value)
return Convert.ToInt64 (value);
}
- private void MakeParameters (XmlElement root, IList parameters, bool shouldDuplicateWithNew=false)
+ private void MakeParameters (XmlElement root, MemberReference member, IList parameters, bool shouldDuplicateWithNew=false)
{
XmlElement e = WriteElement(root, "Parameters");
@@ -2382,13 +2448,14 @@ private void MakeParameters (XmlElement root, IList paramet
MakeAttributes (pe, GetCustomAttributes (p.CustomAttributes, ""));
return pe;
- });
+ },
+ member);
i++;
}
}
- private void MakeTypeParameters (XmlElement root, IList typeParams, bool shouldDuplicateWithNew)
+ private void MakeTypeParameters (XmlElement root, IList typeParams, MemberReference member, bool shouldDuplicateWithNew)
{
if (typeParams == null || typeParams.Count == 0) {
XmlElement f = (XmlElement) root.SelectSingleNode ("TypeParameters");
@@ -2450,18 +2517,19 @@ private void MakeTypeParameters (XmlElement root, IList typePa
}
return pe;
- });
+ },
+ member);
}
}
private void MakeParameters (XmlElement root, MemberReference mi, bool shouldDuplicateWithNew)
{
if (mi is MethodDefinition && ((MethodDefinition) mi).IsConstructor)
- MakeParameters (root, ((MethodDefinition)mi).Parameters, shouldDuplicateWithNew);
+ MakeParameters (root, mi, ((MethodDefinition)mi).Parameters, shouldDuplicateWithNew);
else if (mi is MethodDefinition) {
MethodDefinition mb = (MethodDefinition) mi;
IList parameters = mb.Parameters;
- MakeParameters(root, parameters, shouldDuplicateWithNew);
+ MakeParameters(root, mi, parameters, shouldDuplicateWithNew);
if (parameters.Count > 0 && DocUtils.IsExtensionMethod (mb)) {
XmlElement p = (XmlElement) root.SelectSingleNode ("Parameters/Parameter[position()=1]");
p.SetAttribute ("RefType", "this");
@@ -2470,7 +2538,7 @@ private void MakeParameters (XmlElement root, MemberReference mi, bool shouldDup
else if (mi is PropertyDefinition) {
IList parameters = ((PropertyDefinition)mi).Parameters;
if (parameters.Count > 0)
- MakeParameters(root, parameters, shouldDuplicateWithNew);
+ MakeParameters(root, mi, parameters, shouldDuplicateWithNew);
else
return;
}
@@ -2498,7 +2566,8 @@ private void MakeReturnValue (XmlElement root, TypeReference type, IList GetUserImplementedInterfaces (TypeDefin
if (!inheritedInterfaces.Contains (GetQualifiedTypeName (lookup)))
userInterfaces.Add (iface);
}
- return userInterfaces;
+ return userInterfaces.Where (i => MDocUpdater.IsPublic (i.Resolve ()));
}
private static string GetQualifiedTypeName (TypeReference type)
@@ -3217,7 +3286,7 @@ protected static MemberReference GetMember (TypeDefinition type, DocumentationMe
// did not match ... if we're dropping the namespace, and the paramType has the dropped
// namespace, we should see if it matches when added
bool stillDoesntMatch = true;
- if (MDocUpdater.HasDroppedNamespace() && paramType.StartsWith (MDocUpdater.droppedNamespace)) {
+ if (MDocUpdater.HasDroppedNamespace(type) && paramType.StartsWith (MDocUpdater.droppedNamespace)) {
string withDroppedNs = string.Format ("{0}.{1}", MDocUpdater.droppedNamespace, xmlMemberType);
stillDoesntMatch = withDroppedNs != paramType;
@@ -3270,7 +3339,7 @@ protected static IEnumerable GetReflectionMembers (TypeDefiniti
{
// In case of dropping the namespace, we have to remove the dropped NS
// so that docName will match what's in the assembly/type
- if (MDocUpdater.HasDroppedNamespace () && docName.StartsWith(MDocUpdater.droppedNamespace + ".")) {
+ if (MDocUpdater.HasDroppedNamespace (type) && docName.StartsWith(MDocUpdater.droppedNamespace + ".")) {
int droppedNsLength = MDocUpdater.droppedNamespace.Length;
docName = docName.Substring (droppedNsLength + 1, docName.Length - droppedNsLength - 1);
}
@@ -4303,7 +4372,7 @@ protected override string GetTypeDeclaration (TypeDefinition type)
buf.Append (full.GetName (type.BaseType).Substring ("class ".Length));
}
bool first = true;
- foreach (var name in type.Interfaces
+ foreach (var name in type.Interfaces.Where (i => MDocUpdater.IsPublic (i.Resolve ()))
.Select (i => full.GetName (i))
.OrderBy (n => n)) {
if (first) {
diff --git a/mcs/tools/mdoc/Test/DocTest-DropNS-classic-secondary.cs b/mcs/tools/mdoc/Test/DocTest-DropNS-classic-secondary.cs
new file mode 100644
index 00000000000..3f929d6a75c
--- /dev/null
+++ b/mcs/tools/mdoc/Test/DocTest-DropNS-classic-secondary.cs
@@ -0,0 +1,9 @@
+namespace MyFramework.MyOtherNamespace {
+ ///Make sure the namespace in this assembly doesn't get 'dropped'
+ public class MyOtherClass {
+ public string MyProperty {get;set;}
+ public float Hello(int value) {
+ return 0.0f;
+ }
+ }
+}
diff --git a/mcs/tools/mdoc/Test/DocTest-DropNS-classic.cs b/mcs/tools/mdoc/Test/DocTest-DropNS-classic.cs
new file mode 100644
index 00000000000..a279b0e85a7
--- /dev/null
+++ b/mcs/tools/mdoc/Test/DocTest-DropNS-classic.cs
@@ -0,0 +1,8 @@
+namespace MyFramework.MyNamespace {
+ public class MyClass {
+ public string MyProperty {get;set;}
+ public float Hello(int value) {
+ return 0.0f;
+ }
+ }
+}
diff --git a/mcs/tools/mdoc/Test/DocTest-DropNS-unified.cs b/mcs/tools/mdoc/Test/DocTest-DropNS-unified.cs
new file mode 100644
index 00000000000..8ee5e8a6ffd
--- /dev/null
+++ b/mcs/tools/mdoc/Test/DocTest-DropNS-unified.cs
@@ -0,0 +1,8 @@
+namespace MyNamespace {
+ public class MyClass {
+ public string MyProperty {get;set;}
+ public float Hello(int value) {
+ return 0.0f;
+ }
+ }
+}
diff --git a/mcs/tools/mdoc/Test/DocTest-InternalInterface.cs b/mcs/tools/mdoc/Test/DocTest-InternalInterface.cs
new file mode 100644
index 00000000000..5d65c34c82c
--- /dev/null
+++ b/mcs/tools/mdoc/Test/DocTest-InternalInterface.cs
@@ -0,0 +1,17 @@
+namespace MyNamespace {
+ internal interface MyInternalInterface {
+ bool Foo {get;set;}
+ string FooSet {set;}
+ void FooMeth ();
+ void BarMeth ();
+ }
+
+ public class MyClass : MyInternalInterface {
+ public string Bar {get;set;}
+ public void BarMeth () {} // part of the interface, but publicly implemented
+
+ string MyInternalInterface.FooSet {set {}}
+ bool MyInternalInterface.Foo {get;set;}
+ void MyInternalInterface.FooMeth () {}
+ }
+}
diff --git a/mcs/tools/mdoc/Test/en.expected-dropns-classic-v0/MyFramework.MyNamespace/MyClass.xml b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v0/MyFramework.MyNamespace/MyClass.xml
new file mode 100644
index 00000000000..1e0522f64f7
--- /dev/null
+++ b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v0/MyFramework.MyNamespace/MyClass.xml
@@ -0,0 +1,67 @@
+
+
+
+
+ DocTest-DropNS-classic
+ 0.0.0.0
+
+
+ System.Object
+
+
+
+ To be added.
+ To be added.
+
+
+
+
+
+ Constructor
+
+ 0.0.0.0
+
+
+
+ To be added.
+ To be added.
+
+
+
+
+
+ Method
+
+ 0.0.0.0
+
+
+ System.Single
+
+
+
+
+
+ To be added.
+ To be added.
+ To be added.
+ To be added.
+
+
+
+
+
+ Property
+
+ 0.0.0.0
+
+
+ System.String
+
+
+ To be added.
+ To be added.
+ To be added.
+
+
+
+
diff --git a/mcs/tools/mdoc/Test/en.expected-dropns-classic-v0/index.xml b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v0/index.xml
new file mode 100644
index 00000000000..4f7838baac6
--- /dev/null
+++ b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v0/index.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+ System.Diagnostics.Debuggable(System.Diagnostics.DebuggableAttribute+DebuggingModes.IgnoreSymbolStoreSequencePoints)
+
+
+ System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows=true)
+
+
+
+
+ To be added.
+ To be added.
+
+
+
+
+
+ DocTest-DropNS-classic
+
diff --git a/mcs/tools/mdoc/Test/en.expected-dropns-classic-v0/ns-MyFramework.MyNamespace.xml b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v0/ns-MyFramework.MyNamespace.xml
new file mode 100644
index 00000000000..74df75af20b
--- /dev/null
+++ b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v0/ns-MyFramework.MyNamespace.xml
@@ -0,0 +1,6 @@
+
+
+ To be added.
+ To be added.
+
+
diff --git a/mcs/tools/mdoc/Test/en.expected-dropns-classic-v1/MyFramework.MyNamespace/MyClass.xml b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v1/MyFramework.MyNamespace/MyClass.xml
new file mode 100644
index 00000000000..e3cda6d9d99
--- /dev/null
+++ b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v1/MyFramework.MyNamespace/MyClass.xml
@@ -0,0 +1,80 @@
+
+
+
+
+ DocTest-DropNS-classic
+ 0.0.0.0
+
+
+ DocTest-DropNS-unified
+ 0.0.0.0
+
+
+ System.Object
+
+
+
+ To be added.
+ To be added.
+
+
+
+
+
+ Constructor
+
+ 0.0.0.0
+
+
+ 0.0.0.0
+
+
+
+ To be added.
+ To be added.
+
+
+
+
+
+ Method
+
+ 0.0.0.0
+
+
+ 0.0.0.0
+
+
+ System.Single
+
+
+
+
+
+ To be added.
+ To be added.
+ To be added.
+ To be added.
+
+
+
+
+
+ Property
+
+ 0.0.0.0
+
+
+ 0.0.0.0
+
+
+ System.String
+
+
+ To be added.
+ To be added.
+ To be added.
+
+
+
+
diff --git a/mcs/tools/mdoc/Test/en.expected-dropns-classic-v1/index.xml b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v1/index.xml
new file mode 100644
index 00000000000..edacc723f54
--- /dev/null
+++ b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v1/index.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+ System.Diagnostics.Debuggable(System.Diagnostics.DebuggableAttribute+DebuggingModes.IgnoreSymbolStoreSequencePoints)
+
+
+ System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows=true)
+
+
+
+
+ To be added.
+ To be added.
+
+
+
+
+
+ DocTest-DropNS-classic
+
diff --git a/mcs/tools/mdoc/Test/en.expected-dropns-classic-v1/ns-MyFramework.MyNamespace.xml b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v1/ns-MyFramework.MyNamespace.xml
new file mode 100644
index 00000000000..74df75af20b
--- /dev/null
+++ b/mcs/tools/mdoc/Test/en.expected-dropns-classic-v1/ns-MyFramework.MyNamespace.xml
@@ -0,0 +1,6 @@
+
+
+ To be added.
+ To be added.
+
+
diff --git a/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/MyFramework.MyNamespace/MyClass.xml b/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/MyFramework.MyNamespace/MyClass.xml
new file mode 100644
index 00000000000..e3cda6d9d99
--- /dev/null
+++ b/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/MyFramework.MyNamespace/MyClass.xml
@@ -0,0 +1,80 @@
+
+
+
+
+ DocTest-DropNS-classic
+ 0.0.0.0
+
+
+ DocTest-DropNS-unified
+ 0.0.0.0
+
+
+ System.Object
+
+
+
+ To be added.
+ To be added.
+
+
+
+
+
+ Constructor
+
+ 0.0.0.0
+
+
+ 0.0.0.0
+
+
+
+ To be added.
+ To be added.
+
+
+
+
+
+ Method
+
+ 0.0.0.0
+
+
+ 0.0.0.0
+
+
+ System.Single
+
+
+
+
+
+ To be added.
+ To be added.
+ To be added.
+ To be added.
+
+
+
+
+
+ Property
+
+ 0.0.0.0
+
+
+ 0.0.0.0
+
+
+ System.String
+
+
+ To be added.
+ To be added.
+ To be added.
+
+
+
+
diff --git a/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/MyFramework.MyOtherNamespace/MyOtherClass.xml b/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/MyFramework.MyOtherNamespace/MyOtherClass.xml
new file mode 100644
index 00000000000..a178fc47d6e
--- /dev/null
+++ b/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/MyFramework.MyOtherNamespace/MyOtherClass.xml
@@ -0,0 +1,67 @@
+
+
+
+
+ DocTest-DropNS-classic-secondary
+ 0.0.0.0
+
+
+ System.Object
+
+
+
+ To be added.
+ To be added.
+
+
+
+
+
+ Constructor
+
+ 0.0.0.0
+
+
+
+ To be added.
+ To be added.
+
+
+
+
+
+ Method
+
+ 0.0.0.0
+
+
+ System.Single
+
+
+
+
+
+ To be added.
+ To be added.
+ To be added.
+ To be added.
+
+
+
+
+
+ Property
+
+ 0.0.0.0
+
+
+ System.String
+
+
+ To be added.
+ To be added.
+ To be added.
+
+
+
+
diff --git a/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/index.xml b/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/index.xml
new file mode 100644
index 00000000000..d0fb593627f
--- /dev/null
+++ b/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/index.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+ System.Diagnostics.Debuggable(System.Diagnostics.DebuggableAttribute+DebuggingModes.IgnoreSymbolStoreSequencePoints)
+
+
+ System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows=true)
+
+
+
+
+
+
+ System.Diagnostics.Debuggable(System.Diagnostics.DebuggableAttribute+DebuggingModes.IgnoreSymbolStoreSequencePoints)
+
+
+ System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows=true)
+
+
+
+
+ To be added.
+ To be added.
+
+
+
+
+
+
+
+
+ Untitled
+
diff --git a/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/ns-MyFramework.MyNamespace.xml b/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/ns-MyFramework.MyNamespace.xml
new file mode 100644
index 00000000000..74df75af20b
--- /dev/null
+++ b/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/ns-MyFramework.MyNamespace.xml
@@ -0,0 +1,6 @@
+
+
+ To be added.
+ To be added.
+
+
diff --git a/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/ns-MyFramework.MyOtherNamespace.xml b/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/ns-MyFramework.MyOtherNamespace.xml
new file mode 100644
index 00000000000..8bdef1c7778
--- /dev/null
+++ b/mcs/tools/mdoc/Test/en.expected-dropns-classic-withsecondary/ns-MyFramework.MyOtherNamespace.xml
@@ -0,0 +1,6 @@
+
+
+ To be added.
+ To be added.
+
+
diff --git a/mcs/tools/mdoc/Test/en.expected-internal-interface/MyNamespace/MyClass.xml b/mcs/tools/mdoc/Test/en.expected-internal-interface/MyNamespace/MyClass.xml
new file mode 100644
index 00000000000..614b7b7d59d
--- /dev/null
+++ b/mcs/tools/mdoc/Test/en.expected-internal-interface/MyNamespace/MyClass.xml
@@ -0,0 +1,63 @@
+
+
+
+
+ DocTest-InternalInterface
+ 0.0.0.0
+
+
+ System.Object
+
+
+
+ To be added.
+ To be added.
+
+
+
+
+
+ Constructor
+
+ 0.0.0.0
+
+
+
+ To be added.
+ To be added.
+
+
+
+
+
+ Property
+
+ 0.0.0.0
+
+
+ System.String
+
+
+ To be added.
+ To be added.
+ To be added.
+
+
+
+
+
+ Method
+
+ 0.0.0.0
+
+
+ System.Void
+
+
+
+ To be added.
+ To be added.
+
+
+
+
diff --git a/mcs/tools/mdoc/Test/en.expected-internal-interface/index.xml b/mcs/tools/mdoc/Test/en.expected-internal-interface/index.xml
new file mode 100644
index 00000000000..5b49f3c71d2
--- /dev/null
+++ b/mcs/tools/mdoc/Test/en.expected-internal-interface/index.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+ System.Diagnostics.Debuggable(System.Diagnostics.DebuggableAttribute+DebuggingModes.IgnoreSymbolStoreSequencePoints)
+
+
+ System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows=true)
+
+
+
+
+ To be added.
+ To be added.
+
+
+
+
+
+ DocTest-InternalInterface
+
diff --git a/mcs/tools/mdoc/Test/en.expected-internal-interface/ns-MyNamespace.xml b/mcs/tools/mdoc/Test/en.expected-internal-interface/ns-MyNamespace.xml
new file mode 100644
index 00000000000..bd8d43168a3
--- /dev/null
+++ b/mcs/tools/mdoc/Test/en.expected-internal-interface/ns-MyNamespace.xml
@@ -0,0 +1,6 @@
+
+
+ To be added.
+ To be added.
+
+
diff --git a/mcs/tools/mkbundle/mkbundle.cs b/mcs/tools/mkbundle/mkbundle.cs
index f13ce63d029..6e118995377 100755
--- a/mcs/tools/mkbundle/mkbundle.cs
+++ b/mcs/tools/mkbundle/mkbundle.cs
@@ -715,9 +715,14 @@ static int Execute (string cmdLine)
if (use_dos2unix == null) {
use_dos2unix = false;
try {
- var dos2unix = Process.Start ("dos2unix");
+ var info = new ProcessStartInfo ("dos2unix");
+ info.CreateNoWindow = true;
+ info.RedirectStandardInput = true;
+ info.UseShellExecute = false;
+ var dos2unix = Process.Start (info);
dos2unix.StandardInput.WriteLine ("aaa");
dos2unix.StandardInput.WriteLine ("\u0004");
+ dos2unix.StandardInput.Close ();
dos2unix.WaitForExit ();
if (dos2unix.ExitCode == 0)
use_dos2unix = true;
diff --git a/mcs/tools/security/Makefile b/mcs/tools/security/Makefile
index c9baa67ccfe..ba771b51660 100644
--- a/mcs/tools/security/Makefile
+++ b/mcs/tools/security/Makefile
@@ -6,7 +6,7 @@ include ../../build/rules.make
LOCAL_MCS_FLAGS = /lib:$(topdir)/class/lib/$(PROFILE) -r:Mono.Security.dll
SECURITY_PROGRAMS = secutil.exe cert2spc.exe sn.exe makecert.exe chktrust.exe crlupdate.exe \
- signcode.exe setreg.exe certmgr.exe caspol.exe permview.exe mozroots.exe
+ signcode.exe setreg.exe certmgr.exe caspol.exe permview.exe mozroots.exe cert-sync.exe
SECURITY_PROGRAMS_2_0 = httpcfg.exe
HELPER_SOURCES = AssemblyInfo.cs $(topdir)/build/common/Consts.cs
diff --git a/mcs/tools/security/cert-sync.cs b/mcs/tools/security/cert-sync.cs
new file mode 100644
index 00000000000..44280675dd1
--- /dev/null
+++ b/mcs/tools/security/cert-sync.cs
@@ -0,0 +1,226 @@
+//
+// cert-sync.cs: Import the root certificates from Linux SSL store into Mono
+//
+// Authors:
+// Sebastien Pouliot
+// Jo Shields
+//
+// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2014 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.Collections;
+using System.IO;
+using System.Net;
+using System.Reflection;
+using System.Security.Cryptography;
+using System.Text;
+
+using Mono.Security.X509;
+
+[assembly: AssemblyTitle ("Linux Cert Store Sync")]
+[assembly: AssemblyDescription ("Synchronize local certs with certs from local Linux trust store.")]
+
+namespace Mono.Tools
+{
+
+ class CertSync
+ {
+
+ static string inputFile;
+ static bool quiet;
+
+ static X509Certificate DecodeCertificate (string s)
+ {
+ byte[] rawdata = Convert.FromBase64String (s);
+ return new X509Certificate (rawdata);
+ }
+
+ static Stream GetFile ()
+ {
+ try {
+ if (inputFile != null) {
+ return File.OpenRead (inputFile);
+ } else {
+ return null;
+ }
+ } catch {
+ return null;
+ }
+ }
+
+ static X509CertificateCollection DecodeCollection ()
+ {
+ X509CertificateCollection roots = new X509CertificateCollection ();
+ StringBuilder sb = new StringBuilder ();
+ bool processing = false;
+
+ using (Stream s = GetFile ()) {
+ if (s == null) {
+ WriteLine ("Couldn't retrieve the file using the supplied information.");
+ return null;
+ }
+
+ StreamReader sr = new StreamReader (s);
+ while (true) {
+ string line = sr.ReadLine ();
+ if (line == null)
+ break;
+
+ if (processing) {
+ if (line.StartsWith ("-----END CERTIFICATE-----")) {
+ processing = false;
+ X509Certificate root = DecodeCertificate (sb.ToString ());
+ roots.Add (root);
+
+ sb = new StringBuilder ();
+ continue;
+ }
+ sb.Append (line);
+ } else {
+ processing = line.StartsWith ("-----BEGIN CERTIFICATE-----");
+ }
+ }
+ return roots;
+ }
+ }
+
+ static int Process ()
+ {
+ X509CertificateCollection roots = DecodeCollection ();
+ if (roots == null) {
+ return 1;
+ } else if (roots.Count == 0) {
+ WriteLine ("No certificates were found.");
+ return 0;
+ }
+
+ X509Stores stores = (X509StoreManager.LocalMachine);
+ X509CertificateCollection trusted = stores.TrustedRoot.Certificates;
+ int additions = 0;
+ WriteLine ("I already trust {0}, your new list has {1}", trusted.Count, roots.Count);
+ foreach (X509Certificate root in roots) {
+ if (!trusted.Contains (root)) {
+ try {
+ stores.TrustedRoot.Import (root);
+ WriteLine ("Certificate added: {0}", root.SubjectName);
+ } catch {
+ WriteLine ("Warning: Could not import {0}");
+ }
+ additions++;
+ }
+ }
+ if (additions > 0)
+ WriteLine ("{0} new root certificates were added to your trust store.", additions);
+
+ X509CertificateCollection removed = new X509CertificateCollection ();
+ foreach (X509Certificate trust in trusted) {
+ if (!roots.Contains (trust)) {
+ removed.Add (trust);
+ }
+ }
+ if (removed.Count > 0) {
+ WriteLine ("{0} previously trusted certificates were removed.", removed.Count);
+
+ foreach (X509Certificate old in removed) {
+ stores.TrustedRoot.Remove (old);
+ WriteLine ("Certificate removed: {0}", old.SubjectName);
+ }
+ }
+ WriteLine ("Import process completed.");
+ return 0;
+ }
+
+ static string Thumbprint (string algorithm, X509Certificate certificate)
+ {
+ HashAlgorithm hash = HashAlgorithm.Create (algorithm);
+ byte[] digest = hash.ComputeHash (certificate.RawData);
+ return BitConverter.ToString (digest);
+ }
+
+ static bool ParseOptions (string[] args)
+ {
+ if (args.Length < 1)
+ return false;
+
+ for (int i = 0; i < args.Length - 1; i++) {
+ switch (args [i]) {
+ case "--quiet":
+ quiet = true;
+ break;
+ default:
+ WriteLine ("Unknown option '{0}'.");
+ return false;
+ }
+ }
+ inputFile = args [args.Length - 1];
+ if (!File.Exists (inputFile)) {
+ WriteLine ("Unknown option or file not found '{0}'.");
+ return false;
+ }
+ return true;
+ }
+
+ static void Header ()
+ {
+ Console.WriteLine (new AssemblyInfo ().ToString ());
+ }
+
+ static void Help ()
+ {
+ Console.WriteLine ("Usage: cert-sync [--quiet] system-ca-bundle.crt");
+ Console.WriteLine ("Where system-ca-bundle.crt is in PEM format");
+ }
+
+ static void WriteLine (string str)
+ {
+ if (!quiet)
+ Console.WriteLine (str);
+ }
+
+ static void WriteLine (string format, params object[] args)
+ {
+ if (!quiet)
+ Console.WriteLine (format, args);
+ }
+
+ static int Main (string[] args)
+ {
+ try {
+ if (!ParseOptions (args)) {
+ Header ();
+ Help ();
+ return 1;
+ }
+ if (!quiet) {
+ Header ();
+ }
+ return Process ();
+ } catch (Exception e) {
+ // ignore quiet on exception
+ Console.WriteLine ("Error: {0}", e);
+ return 1;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/mono-core.spec.in b/mono-core.spec.in
index 0b7337d05d5..90d0b581219 100644
--- a/mono-core.spec.in
+++ b/mono-core.spec.in
@@ -4,6 +4,9 @@
%ifnarch %ix86 x86_64
%define llvm no
+%endif
+
+%ifnarch %ix86 x86_64 s390x
%define sgen no
%endif
@@ -16,10 +19,14 @@ Version: @VERSION@
Release: 0
Source0: mono-%{version}.tar.bz2
BuildRequires: bison
+%if 0%{?suse_version}
BuildRequires: fdupes
+BuildRequires: xorg-x11-libX11-devel
+%else
+BuildRequires: libX11-devel
+%endif
BuildRequires: gcc-c++
BuildRequires: pkgconfig
-BuildRequires: xorg-x11-libX11-devel
BuildRequires: zlib-devel
%ifnarch ia64
BuildRequires: valgrind-devel
@@ -48,7 +55,9 @@ Conflicts: banshee < 1.0
Conflicts: f-spot < 0.4
Conflicts: helix-banshee < 1.0
Conflicts: mono-addins < 0.3.1
+%if 0%{?suse_version}
Recommends: libgdiplus0 >= 2.6
+%endif
%if %llvm == yes
Recommends: libmono-llvm0 = %{version}-%{release}
%endif
@@ -92,6 +101,7 @@ export CFLAGS=" $RPM_OPT_FLAGS -fno-strict-aliasing"
export PATH=/opt/novell/llvm-mono/bin:$PATH
%endif
%configure \
+ --target=%{_host} \
--with-sgen=%{sgen} \
%if %llvm == yes
--enable-loadedllvm \
@@ -104,6 +114,7 @@ export PATH=/opt/novell/llvm-mono/bin:$PATH
--with-moonlight=no
#make # We are not -jN safe! %{?jobs:-j%jobs}
# We are now !
+make get-monolite-latest
make %{?_smp_mflags}
%install
@@ -130,7 +141,9 @@ rm -f %buildroot%_prefix/lib/mono/2.0/cilc.exe*
ln -s . %buildroot%_prefix%_prefix
RPM_BUILD_ROOT=%buildroot%_prefix /usr/lib/rpm/brp-compress
rm %buildroot%_prefix%_prefix
+%if 0%{?suse_version}
%fdupes %buildroot%_prefix
+%endif
%find_lang mcs
%clean
diff --git a/mono/arch/amd64/Makefile.am b/mono/arch/amd64/Makefile.am
index 3c728263190..47daaaff699 100644
--- a/mono/arch/amd64/Makefile.am
+++ b/mono/arch/amd64/Makefile.am
@@ -1,7 +1,2 @@
-
-AM_CPPFLAGS = $(GLIB_CFLAGS) -I$(top_srcdir)
-
-noinst_LTLIBRARIES = libmonoarch-amd64.la
-
-libmonoarch_amd64_la_SOURCES = tramp.c amd64-codegen.h
+EXTRA_DIST = amd64-codegen.h
diff --git a/mono/arch/amd64/tramp.c b/mono/arch/amd64/tramp.c
deleted file mode 100644
index 6dbec93e859..00000000000
--- a/mono/arch/amd64/tramp.c
+++ /dev/null
@@ -1,1054 +0,0 @@
-/*
- * Create trampolines to invoke arbitrary functions.
- *
- * Copyright (C) Ximian Inc.
- *
- * Author:
- * Zalman Stern
- * Based on code by:
- * Paolo Molaro (lupus@ximian.com)
- * Dietmar Maurer (dietmar@ximian.com)
- *
- * To understand this code, one will want to the calling convention section of the ABI sepc at:
- * http://x86-64.org/abi.pdf
- * and the AMD64 architecture docs found at amd.com .
- */
-
-#include "config.h"
-#include
-#include
-#include "amd64-codegen.h"
-#include "mono/metadata/class.h"
-#include "mono/metadata/tabledefs.h"
-#include "mono/interpreter/interp.h"
-#include "mono/metadata/appdomain.h"
-#include "mono/metadata/marshal.h"
-
-/*
- * The resulting function takes the form:
- * void func (void (*callme)(), void *retval, void *this_obj, stackval *arguments);
- */
-#define FUNC_ADDR_POS 8
-#define RETVAL_POS 12
-#define THIS_POS 16
-#define ARGP_POS 20
-#define LOC_POS -4
-
-#define ARG_SIZE sizeof (stackval)
-
-#define MAX_INT_ARG_REGS 6
-#define MAX_FLOAT_ARG_REGS 8
-
-// TODO get these right. They are upper bounds anyway, so it doesn't much matter.
-#define PUSH_INT_STACK_ARG_SIZE 16
-#define MOVE_INT_REG_ARG_SIZE 16
-#define PUSH_FLOAT_STACK_ARG_SIZE 16
-#define MOVE_FLOAT_REG_ARG_SIZE 16
-#define COPY_STRUCT_STACK_ARG_SIZE 16
-
-/* Maps an argument number (starting at 0) to the register it is passed in (if it fits).
- * E.g. int foo(int bar, int quux) has the foo arg in RDI and the quux arg in RSI
- * There is no such map for floating point args as they go in XMM0-XMM7 in order and thus the
- * index is the register number.
- */
-static int int_arg_regs[] = { AMD64_RDI, AMD64_RSI, AMD64_RDX, AMD64_RCX, AMD64_R8, AMD64_R9 };
-
-/* This next block of code resolves the ABI rules for passing structures in the argument registers.
- * These basically amount to "Use up to two registers if they are all integer or all floating point.
- * If the structure is bigger than two registers or would be in one integer register and one floating point,
- * it is passed in memory instead.
- *
- * It is possible this code needs to be recursive to be correct in the case when one of the structure members
- * is itself a structure.
- *
- * The 80-bit floating point stuff is ignored.
- */
-typedef enum {
- ARG_IN_MEMORY,
- ARG_IN_INT_REGS,
- ARG_IN_FLOAT_REGS
-} struct_arg_type;
-
-static struct_arg_type compute_arg_type(MonoType *type)
-{
- guint32 simpletype = type->type;
-
- switch (simpletype) {
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_CHAR:
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_PTR:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_STRING:
- case MONO_TYPE_I8:
- return ARG_IN_INT_REGS;
- break;
- case MONO_TYPE_VALUETYPE: {
- if (type->data.klass->enumtype)
- return ARG_IN_INT_REGS;
- return ARG_IN_MEMORY;
- break;
- }
- case MONO_TYPE_R4:
- case MONO_TYPE_R8:
- return ARG_IN_FLOAT_REGS;
- break;
- default:
- g_error ("Can't trampoline 0x%x", type->type);
- }
-
- return ARG_IN_MEMORY;
-}
-
-static struct_arg_type value_type_info(MonoClass *klass, int *native_size, int *regs_used, int *offset1, int *size1, int *offset2, int *size2)
-{
- MonoMarshalType *info = mono_marshal_load_type_info (klass);
-
- *native_size = info->native_size;
-
- if (info->native_size > 8 || info->num_fields > 2)
- {
- *regs_used = 0;
- *offset1 = -1;
- *offset2 = -1;
- return ARG_IN_MEMORY;
- }
-
- if (info->num_fields == 1)
- {
- struct_arg_type result = compute_arg_type(info->fields[0].field->type);
- if (result != ARG_IN_MEMORY)
- {
- *regs_used = 1;
- *offset1 = info->fields[0].offset;
- *size1 = mono_marshal_type_size (info->fields[0].field->type, info->fields[0].mspec, NULL, 1, 1);
- }
- else
- {
- *regs_used = 0;
- *offset1 = -1;
- }
-
- *offset2 = -1;
- return result;
- }
-
- struct_arg_type result1 = compute_arg_type(info->fields[0].field->type);
- struct_arg_type result2 = compute_arg_type(info->fields[0].field->type);
-
- if (result1 == result2 && result1 != ARG_IN_MEMORY)
- {
- *regs_used = 2;
- *offset1 = info->fields[0].offset;
- *size1 = mono_marshal_type_size (info->fields[0].field->type, info->fields[0].mspec, NULL, 1, 1);
- *offset2 = info->fields[1].offset;
- *size2 = mono_marshal_type_size (info->fields[1].field->type, info->fields[1].mspec, NULL, 1, 1);
- return result1;
- }
-
- return ARG_IN_MEMORY;
-}
-
-MonoPIFunc
-mono_arch_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
-{
- unsigned char *p, *code_buffer;
- guint32 stack_size = 0, code_size = 50;
- guint32 arg_pos, simpletype;
- int i;
- static GHashTable *cache = NULL;
- MonoPIFunc res;
-
- guint32 int_arg_regs_used = 0;
- guint32 float_arg_regs_used = 0;
- guint32 next_int_arg_reg = 0;
- guint32 next_float_arg_reg = 0;
- /* Indicates that the return value is filled in inside the called function. */
- int retval_implicit = 0;
- char *arg_in_reg_bitvector; /* A set index by argument number saying if it is in a register
- (integer or floating point according to type) */
-
- if (!cache)
- cache = g_hash_table_new ((GHashFunc)mono_signature_hash,
- (GCompareFunc)mono_metadata_signature_equal);
-
- if ((res = (MonoPIFunc)g_hash_table_lookup (cache, sig)))
- return res;
-
- if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref && !sig->ret->data.klass->enumtype) {
- int_arg_regs_used++;
- code_size += MOVE_INT_REG_ARG_SIZE;
- }
-
- if (sig->hasthis) {
- int_arg_regs_used++;
- code_size += MOVE_INT_REG_ARG_SIZE;
- }
-
- /* Run through stuff to calculate code size and argument bytes that will be pushed on stack (stack_size). */
- for (i = 0; i < sig->param_count; ++i) {
- if (sig->params [i]->byref)
- simpletype = MONO_TYPE_PTR;
- else
- simpletype = sig->params [i]->type;
-enum_calc_size:
- switch (simpletype) {
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_CHAR:
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_PTR:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_STRING:
- case MONO_TYPE_I8:
- if (int_arg_regs_used++ > MAX_INT_ARG_REGS) {
- stack_size += 8;
- code_size += PUSH_INT_STACK_ARG_SIZE;
- }
- else
- code_size += MOVE_INT_REG_ARG_SIZE;
- break;
- case MONO_TYPE_VALUETYPE: {
- int size;
- int arg_type;
- int regs_used;
- int offset1;
- int size1;
- int offset2;
- int size2;
-
- if (sig->params [i]->data.klass->enumtype) {
- simpletype = sig->params [i]->data.klass->enum_basetype->type;
- goto enum_calc_size;
- }
-
- arg_type = value_type_info(sig->params [i]->data.klass, &size, ®s_used, &offset1, &size1, &offset2, &size2);
- if (arg_type == ARG_IN_INT_REGS &&
- (int_arg_regs_used + regs_used) <= MAX_INT_ARG_REGS)
- {
- code_size += MOVE_INT_REG_ARG_SIZE;
- int_arg_regs_used += regs_used;
- break;
- }
-
- if (arg_type == ARG_IN_FLOAT_REGS &&
- (float_arg_regs_used + regs_used) <= MAX_FLOAT_ARG_REGS)
- {
- code_size += MOVE_FLOAT_REG_ARG_SIZE;
- float_arg_regs_used += regs_used;
- break;
- }
-
- /* Else item is in memory. */
-
- stack_size += size + 7;
- stack_size &= ~7;
- code_size += COPY_STRUCT_STACK_ARG_SIZE;
-
- break;
- }
- case MONO_TYPE_R4:
- case MONO_TYPE_R8:
- if (float_arg_regs_used++ > MAX_FLOAT_ARG_REGS) {
- stack_size += 8;
- code_size += PUSH_FLOAT_STACK_ARG_SIZE;
- }
- else
- code_size += MOVE_FLOAT_REG_ARG_SIZE;
- break;
- default:
- g_error ("Can't trampoline 0x%x", sig->params [i]->type);
- }
- }
- /*
- * FIXME: take into account large return values.
- * (Comment carried over from IA32 code. Not sure what it means :-)
- */
-
- code_buffer = p = alloca (code_size);
-
- /*
- * Standard function prolog.
- */
- amd64_push_reg (p, AMD64_RBP);
- amd64_mov_reg_reg (p, AMD64_RBP, AMD64_RSP, 8);
- /*
- * and align to 16 byte boundary...
- */
-
- if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) {
- MonoClass *klass = sig->ret->data.klass;
- if (!klass->enumtype) {
- retval_implicit = 1;
- }
- }
-
- if (sig->ret->byref || string_ctor || !(retval_implicit || sig->ret->type == MONO_TYPE_VOID)) {
- /* Push the retval register so it is saved across the call. It will be addressed via RBP later. */
- amd64_push_reg (p, AMD64_RSI);
- stack_size += 8;
- }
-
- /* Ensure stack is 16 byte aligned when entering called function as required by calling convention.
- * Getting this wrong results in a general protection fault on an SSE load or store somewhere in the
- * code called under the trampoline.
- */
- if ((stack_size & 15) != 0)
- amd64_alu_reg_imm (p, X86_SUB, AMD64_RSP, 16 - (stack_size & 15));
-
- /*
- * On entry to generated function:
- * RDI has target function address
- * RSI has return value location address
- * RDX has this pointer address
- * RCX has the pointer to the args array.
- *
- * Inside the stub function:
- * R10 holds the pointer to the args
- * R11 holds the target function address.
- * The return value address is pushed on the stack.
- * The this pointer is moved into the first arg register at the start.
- *
- * Optimization note: we could keep the args pointer in RCX and then
- * load over itself at the end. Ditto the callee addres could be left in RDI in some cases.
- */
-
- /* Move args pointer to temp register. */
- amd64_mov_reg_reg (p, AMD64_R10, AMD64_RCX, 8);
- amd64_mov_reg_reg (p, AMD64_R11, AMD64_RDI, 8);
-
- /* First args register gets return value pointer, if need be.
- * Note that "byref" equal true means the called function returns a pointer.
- */
- if (retval_implicit) {
- amd64_mov_reg_reg (p, int_arg_regs[next_int_arg_reg], AMD64_RSI, 8);
- next_int_arg_reg++;
- }
-
- /* this pointer goes in next args register. */
- if (sig->hasthis) {
- amd64_mov_reg_reg (p, int_arg_regs[next_int_arg_reg], AMD64_RDX, 8);
- next_int_arg_reg++;
- }
-
- /*
- * Generate code to handle arguments in registers. Stack arguments will happen in a loop after this.
- */
- arg_in_reg_bitvector = (char *)alloca((sig->param_count + 7) / 8);
- memset(arg_in_reg_bitvector, 0, (sig->param_count + 7) / 8);
-
- /* First, load all the arguments that are passed in registers into the appropriate registers.
- * Below there is another loop to handle arguments passed on the stack.
- */
- for (i = 0; i < sig->param_count; i++) {
- arg_pos = ARG_SIZE * i;
-
- if (sig->params [i]->byref)
- simpletype = MONO_TYPE_PTR;
- else
- simpletype = sig->params [i]->type;
-enum_marshal:
- switch (simpletype) {
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- case MONO_TYPE_CHAR:
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_PTR:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_STRING:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- case MONO_TYPE_CLASS:
- if (next_int_arg_reg < MAX_INT_ARG_REGS) {
- amd64_mov_reg_membase (p, int_arg_regs[next_int_arg_reg], AMD64_R10, arg_pos, 8);
- next_int_arg_reg++;
- arg_in_reg_bitvector[i >> 3] |= (1 << (i & 7));
- }
- break;
- case MONO_TYPE_R4:
- if (next_float_arg_reg < MAX_FLOAT_ARG_REGS) {
- amd64_movss_reg_membase (p, next_float_arg_reg, AMD64_R10, arg_pos);
- next_float_arg_reg++;
- arg_in_reg_bitvector[i >> 3] |= (1 << (i & 7));
- }
- break;
- case MONO_TYPE_R8:
- if (next_float_arg_reg < MAX_FLOAT_ARG_REGS) {
- amd64_movsd_reg_membase (p, next_float_arg_reg, AMD64_R10, arg_pos);
- next_float_arg_reg++;
- arg_in_reg_bitvector[i >> 3] |= (1 << (i & 7));
- }
- break;
- case MONO_TYPE_VALUETYPE: {
- if (!sig->params [i]->data.klass->enumtype) {
- int size;
- int arg_type;
- int regs_used;
- int offset1;
- int size1;
- int offset2;
- int size2;
-
- arg_type = value_type_info(sig->params [i]->data.klass, &size, ®s_used, &offset1, &size1, &offset2, &size2);
-
- if (arg_type == ARG_IN_INT_REGS &&
- (next_int_arg_reg + regs_used) <= MAX_INT_ARG_REGS)
- {
- amd64_mov_reg_membase (p, int_arg_regs[next_int_arg_reg], AMD64_R10, arg_pos + offset1, size1);
- next_int_arg_reg++;
- if (regs_used > 1)
- {
- amd64_mov_reg_membase (p, int_arg_regs[next_int_arg_reg], AMD64_R10, arg_pos + offset2, size2);
- next_int_arg_reg++;
- }
- arg_in_reg_bitvector[i >> 3] |= (1 << (i & 7));
- break;
- }
-
- if (arg_type == ARG_IN_FLOAT_REGS &&
- (next_float_arg_reg + regs_used) <= MAX_FLOAT_ARG_REGS)
- {
- if (size1 == 4)
- amd64_movss_reg_membase (p, next_float_arg_reg, AMD64_R10, arg_pos + offset1);
- else
- amd64_movsd_reg_membase (p, next_float_arg_reg, AMD64_R10, arg_pos + offset1);
- next_float_arg_reg++;
-
- if (regs_used > 1)
- {
- if (size2 == 4)
- amd64_movss_reg_membase (p, next_float_arg_reg, AMD64_R10, arg_pos + offset2);
- else
- amd64_movsd_reg_membase (p, next_float_arg_reg, AMD64_R10, arg_pos + offset2);
- next_float_arg_reg++;
- }
- arg_in_reg_bitvector[i >> 3] |= (1 << (i & 7));
- break;
- }
-
- /* Structs in memory are handled in the next loop. */
- } else {
- /* it's an enum value */
- simpletype = sig->params [i]->data.klass->enum_basetype->type;
- goto enum_marshal;
- }
- break;
- }
- default:
- g_error ("Can't trampoline 0x%x", sig->params [i]->type);
- }
- }
-
- /* Handle stack arguments, pushing the rightmost argument first. */
- for (i = sig->param_count; i > 0; --i) {
- arg_pos = ARG_SIZE * (i - 1);
- if (sig->params [i - 1]->byref)
- simpletype = MONO_TYPE_PTR;
- else
- simpletype = sig->params [i - 1]->type;
-enum_marshal2:
- switch (simpletype) {
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- case MONO_TYPE_CHAR:
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_PTR:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_STRING:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- case MONO_TYPE_CLASS:
- if ((arg_in_reg_bitvector[(i - 1) >> 3] & (1 << ((i - 1) & 7))) == 0) {
- amd64_push_membase (p, AMD64_R10, arg_pos);
- }
- break;
- case MONO_TYPE_R4:
- if ((arg_in_reg_bitvector[(i - 1) >> 3] & (1 << ((i - 1) & 7))) == 0) {
- amd64_push_membase (p, AMD64_R10, arg_pos);
- }
- break;
- case MONO_TYPE_R8:
- if ((arg_in_reg_bitvector[(i - 1) >> 3] & (1 << ((i - 1) & 7))) == 0) {
- amd64_push_membase (p, AMD64_R10, arg_pos);
- }
- break;
- case MONO_TYPE_VALUETYPE:
- if (!sig->params [i - 1]->data.klass->enumtype) {
- if ((arg_in_reg_bitvector[(i - 1) >> 3] & (1 << ((i - 1) & 7))) == 0)
- {
- int ss = mono_class_native_size (sig->params [i - 1]->data.klass, NULL);
- ss += 7;
- ss &= ~7;
-
- amd64_alu_reg_imm(p, X86_SUB, AMD64_RSP, ss);
- /* Count register */
- amd64_mov_reg_imm(p, AMD64_RCX, ss);
- /* Source register */
- amd64_lea_membase(p, AMD64_RSI, AMD64_R10, arg_pos);
- /* Dest register */
- amd64_mov_reg_reg(p, AMD64_RDI, AMD64_RSP, 8);
-
- /* AMD64 calling convention guarantees direction flag is clear at call boundary. */
- x86_prefix(p, AMD64_REX(AMD64_REX_W));
- x86_prefix(p, X86_REP_PREFIX);
- x86_movsb(p);
- }
- } else {
- /* it's an enum value */
- simpletype = sig->params [i - 1]->data.klass->enum_basetype->type;
- goto enum_marshal2;
- }
- break;
- default:
- g_error ("Can't trampoline 0x%x", sig->params [i - 1]->type);
- }
- }
-
- /* TODO: Set RAL to number of XMM registers used in case this is a varags function? */
-
- /*
- * Insert call to function
- */
- amd64_call_reg (p, AMD64_R11);
-
- if (sig->ret->byref || string_ctor || !(retval_implicit || sig->ret->type == MONO_TYPE_VOID)) {
- amd64_mov_reg_membase(p, AMD64_RSI, AMD64_RBP, -8, SIZEOF_VOID_P);
- }
- /*
- * Handle retval.
- * Small integer and pointer values are in EAX.
- * Long integers are in EAX:EDX.
- * FP values are on the FP stack.
- */
-
- if (sig->ret->byref || string_ctor) {
- simpletype = MONO_TYPE_PTR;
- } else {
- simpletype = sig->ret->type;
- }
- enum_retvalue:
- switch (simpletype) {
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- amd64_mov_regp_reg (p, AMD64_RSI, X86_EAX, 1);
- break;
- case MONO_TYPE_CHAR:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- amd64_mov_regp_reg (p, AMD64_RSI, X86_EAX, 2);
- break;
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_STRING:
- case MONO_TYPE_PTR:
- amd64_mov_regp_reg (p, AMD64_RSI, X86_EAX, 8);
- break;
- case MONO_TYPE_R4:
- amd64_movss_regp_reg (p, AMD64_RSI, AMD64_XMM0);
- break;
- case MONO_TYPE_R8:
- amd64_movsd_regp_reg (p, AMD64_RSI, AMD64_XMM0);
- break;
- case MONO_TYPE_I8:
- amd64_mov_regp_reg (p, AMD64_RSI, X86_EAX, 8);
- break;
- case MONO_TYPE_VALUETYPE: {
- int size;
- int arg_type;
- int regs_used;
- int offset1;
- int size1;
- int offset2;
- int size2;
-
- if (sig->ret->data.klass->enumtype) {
- simpletype = sig->ret->data.klass->enum_basetype->type;
- goto enum_retvalue;
- }
-
- arg_type = value_type_info(sig->params [i]->data.klass, &size, ®s_used, &offset1, &size1, &offset2, &size2);
-
- if (arg_type == ARG_IN_INT_REGS)
- {
- amd64_mov_membase_reg (p, AMD64_RSI, offset1, AMD64_RAX, size1);
- if (regs_used > 1)
- amd64_mov_membase_reg (p, AMD64_RSI, offset2, AMD64_RDX, size2);
- break;
- }
-
- if (arg_type == ARG_IN_FLOAT_REGS)
- {
- if (size1 == 4)
- amd64_movss_membase_reg (p, AMD64_RSI, offset1, AMD64_XMM0);
- else
- amd64_movsd_membase_reg (p, AMD64_RSI, offset1, AMD64_XMM0);
-
- if (regs_used > 1)
- {
- if (size2 == 4)
- amd64_movss_membase_reg (p, AMD64_RSI, offset2, AMD64_XMM1);
- else
- amd64_movsd_membase_reg (p, AMD64_RSI, offset2, AMD64_XMM1);
- }
- break;
- }
-
- /* Else result should have been stored in place already. */
- break;
- }
- case MONO_TYPE_VOID:
- break;
- default:
- g_error ("Can't handle as return value 0x%x", sig->ret->type);
- }
-
- /*
- * Standard epilog.
- */
- amd64_leave (p);
- amd64_ret (p);
-
- g_assert (p - code_buffer < code_size);
- res = (MonoPIFunc)g_memdup (code_buffer, p - code_buffer);
-
- g_hash_table_insert (cache, sig, res);
-
- return res;
-}
-
-/*
- * Returns a pointer to a native function that can be used to
- * call the specified method.
- * The function created will receive the arguments according
- * to the call convention specified in the method.
- * This function works by creating a MonoInvocation structure,
- * filling the fields in and calling ves_exec_method on it.
- * Still need to figure out how to handle the exception stuff
- * across the managed/unmanaged boundary.
- */
-void *
-mono_arch_create_method_pointer (MonoMethod *method)
-{
- MonoMethodSignature *sig;
- MonoJitInfo *ji;
- unsigned char *p, *code_buffer;
- guint32 simpletype;
- gint32 local_size;
- gint32 stackval_pos;
- gint32 mono_invocation_pos;
- int i, cpos;
- int *vtbuf;
- int *rbpoffsets;
- int int_arg_regs_used = 0;
- int float_arg_regs_used = 0;
- int stacked_args_size = 0; /* bytes of register passed arguments pushed on stack for safe keeping. Used to get alignment right. */
- int next_stack_arg_rbp_offset = 16;
- int retval_ptr_rbp_offset = 0;
- int this_reg = -1; /* Remember register this ptr is in. */
-
- /*
- * If it is a static P/Invoke method, we can just return the pointer
- * to the method implementation.
- */
- if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL && ((MonoMethodPInvoke*) method)->addr) {
- ji = g_new0 (MonoJitInfo, 1);
- ji->method = method;
- ji->code_size = 1;
- ji->code_start = ((MonoMethodPInvoke*) method)->addr;
-
- mono_jit_info_table_add (mono_get_root_domain (), ji);
- return ((MonoMethodPInvoke*) method)->addr;
- }
-
- sig = method->signature;
-
- code_buffer = p = alloca (512); /* FIXME: check for overflows... */
- vtbuf = alloca (sizeof(int)*sig->param_count);
- rbpoffsets = alloca (sizeof(int)*sig->param_count);
-
-
- /*
- * Standard function prolog.
- */
- amd64_push_reg (p, AMD64_RBP);
- amd64_mov_reg_reg (p, AMD64_RBP, AMD64_RSP, 8);
-
- /* If there is an implicit return value pointer in the first args reg, save it now so
- * the result can be stored through the pointer at the end.
- */
- if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref && !sig->ret->data.klass->enumtype)
- {
- amd64_push_reg (p, int_arg_regs[int_arg_regs_used]);
- int_arg_regs_used++;
- stacked_args_size += 8;
- retval_ptr_rbp_offset = -stacked_args_size;
- }
-
- /*
- * If there is a this pointer, remember the number of the register it is in.
- */
- if (sig->hasthis) {
- this_reg = int_arg_regs[int_arg_regs_used++];
- }
-
- /* Put all arguments passed in registers on the stack.
- * Record offsets from RBP to each argument.
- */
- cpos = 0;
-
- for (i = 0; i < sig->param_count; i++) {
- if (sig->params [i]->byref)
- simpletype = MONO_TYPE_PTR;
- else
- simpletype = sig->params [i]->type;
-enum_calc_size:
- switch (simpletype) {
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_CHAR:
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_PTR:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_STRING:
- case MONO_TYPE_I8:
- if (int_arg_regs_used < MAX_INT_ARG_REGS) {
- amd64_push_reg (p, int_arg_regs[int_arg_regs_used]);
- int_arg_regs_used++;
- stacked_args_size += 8;
- rbpoffsets[i] = -stacked_args_size;
- }
- else
- {
- rbpoffsets[i] = next_stack_arg_rbp_offset;
- next_stack_arg_rbp_offset += 8;
- }
- break;
- case MONO_TYPE_VALUETYPE: {
- if (sig->params [i]->data.klass->enumtype) {
- simpletype = sig->params [i]->data.klass->enum_basetype->type;
- goto enum_calc_size;
- }
- else
- {
- int size;
- int arg_type;
- int regs_used;
- int offset1;
- int size1;
- int offset2;
- int size2;
-
- arg_type = value_type_info(sig->params [i]->data.klass, &size, ®s_used, &offset1, &size1, &offset2, &size2);
-
- if (arg_type == ARG_IN_INT_REGS &&
- (int_arg_regs_used + regs_used) <= MAX_INT_ARG_REGS)
- {
- amd64_alu_reg_imm (p, X86_SUB, AMD64_RSP, size);
- stacked_args_size += size;
- rbpoffsets[i] = stacked_args_size;
-
- amd64_mov_reg_membase (p, int_arg_regs[int_arg_regs_used], AMD64_RSP, offset1, size1);
- int_arg_regs_used++;
- if (regs_used > 1)
- {
- amd64_mov_reg_membase (p, int_arg_regs[int_arg_regs_used], AMD64_RSP, offset2, size2);
- int_arg_regs_used++;
- }
- break;
- }
-
- if (arg_type == ARG_IN_FLOAT_REGS &&
- (float_arg_regs_used + regs_used) <= MAX_FLOAT_ARG_REGS)
- {
- amd64_alu_reg_imm (p, X86_SUB, AMD64_RSP, size);
- stacked_args_size += size;
- rbpoffsets[i] = stacked_args_size;
-
- if (size1 == 4)
- amd64_movss_reg_membase (p, float_arg_regs_used, AMD64_RSP, offset1);
- else
- amd64_movsd_reg_membase (p, float_arg_regs_used, AMD64_RSP, offset1);
- float_arg_regs_used++;
-
- if (regs_used > 1)
- {
- if (size2 == 4)
- amd64_movss_reg_membase (p, float_arg_regs_used, AMD64_RSP, offset2);
- else
- amd64_movsd_reg_membase (p, float_arg_regs_used, AMD64_RSP, offset2);
- float_arg_regs_used++;
- }
- break;
- }
-
- rbpoffsets[i] = next_stack_arg_rbp_offset;
- next_stack_arg_rbp_offset += size;
- }
- break;
- }
- case MONO_TYPE_R4:
- if (float_arg_regs_used < MAX_FLOAT_ARG_REGS) {
- amd64_alu_reg_imm (p, X86_SUB, AMD64_RSP, 8);
- amd64_movss_regp_reg (p, AMD64_RSP, float_arg_regs_used);
- float_arg_regs_used++;
- stacked_args_size += 8;
- rbpoffsets[i] = -stacked_args_size;
- }
- else
- {
- rbpoffsets[i] = next_stack_arg_rbp_offset;
- next_stack_arg_rbp_offset += 8;
- }
- break;
- case MONO_TYPE_R8:
- stacked_args_size += 8;
- if (float_arg_regs_used < MAX_FLOAT_ARG_REGS) {
- amd64_alu_reg_imm (p, X86_SUB, AMD64_RSP, 8);
- amd64_movsd_regp_reg (p, AMD64_RSP, float_arg_regs_used);
- float_arg_regs_used++;
- stacked_args_size += 8;
- rbpoffsets[i] = -stacked_args_size;
- }
- else
- {
- rbpoffsets[i] = next_stack_arg_rbp_offset;
- next_stack_arg_rbp_offset += 8;
- }
- break;
- default:
- g_error ("Can't trampoline 0x%x", sig->params [i]->type);
- }
- }
-
- local_size = sizeof (MonoInvocation) + sizeof (stackval) * (sig->param_count + 1) + stacked_args_size;
-
- local_size += 15;
- local_size &= ~15;
-
- stackval_pos = -local_size;
- mono_invocation_pos = stackval_pos + sizeof (stackval) * (sig->param_count + 1);
-
- /* stacked_args_size has already been pushed onto the stack. Make room for the rest of it. */
- amd64_alu_reg_imm (p, X86_SUB, AMD64_RSP, local_size - stacked_args_size);
-
- /* Be careful not to trash any arg regs before saving this_reg to MonoInvocation structure below. */
-
- /*
- * Initialize MonoInvocation fields, first the ones known now.
- */
- amd64_alu_reg_reg (p, X86_XOR, AMD64_RAX, AMD64_RAX);
- amd64_mov_membase_reg (p, AMD64_RBP, (mono_invocation_pos + G_STRUCT_OFFSET (MonoInvocation, ex)), AMD64_RAX, SIZEOF_VOID_P);
- amd64_mov_membase_reg (p, AMD64_RBP, (mono_invocation_pos + G_STRUCT_OFFSET (MonoInvocation, ex_handler)), AMD64_RAX, SIZEOF_VOID_P);
- amd64_mov_membase_reg (p, AMD64_RBP, (mono_invocation_pos + G_STRUCT_OFFSET (MonoInvocation, parent)), AMD64_RAX, SIZEOF_VOID_P);
- /*
- * Set the method pointer.
- */
- amd64_mov_membase_imm (p, AMD64_RBP, (mono_invocation_pos + G_STRUCT_OFFSET (MonoInvocation, method)), (long)method, SIZEOF_VOID_P);
-
- /*
- * Handle this.
- */
- if (sig->hasthis)
- amd64_mov_membase_reg(p, AMD64_RBP, (mono_invocation_pos + G_STRUCT_OFFSET (MonoInvocation, obj)), this_reg, SIZEOF_VOID_P);
-
- /*
- * Handle the arguments. stackval_pos is the offset from RBP of the stackval in the MonoInvocation args array .
- * arg_pos is the offset from RBP to the incoming arg on the stack.
- * We just call stackval_from_data to handle all the (nasty) issues....
- */
- amd64_lea_membase (p, AMD64_RAX, AMD64_RBP, stackval_pos);
- amd64_mov_membase_reg (p, AMD64_RBP, (mono_invocation_pos + G_STRUCT_OFFSET (MonoInvocation, stack_args)), AMD64_RAX, SIZEOF_VOID_P);
- for (i = 0; i < sig->param_count; ++i) {
-/* Need to call stackval_from_data (MonoType *type, stackval *result, char *data, gboolean pinvoke); */
- amd64_mov_reg_imm (p, AMD64_R11, stackval_from_data);
- amd64_mov_reg_imm (p, int_arg_regs[0], sig->params[i]);
- amd64_lea_membase (p, int_arg_regs[1], AMD64_RBP, stackval_pos);
- amd64_lea_membase (p, int_arg_regs[2], AMD64_RBP, rbpoffsets[i]);
- amd64_mov_reg_imm (p, int_arg_regs[3], sig->pinvoke);
- amd64_call_reg (p, AMD64_R11);
- stackval_pos += sizeof (stackval);
-#if 0
- /* fixme: alignment */
- if (sig->pinvoke)
- arg_pos += mono_type_native_stack_size (sig->params [i], &align);
- else
- arg_pos += mono_type_stack_size (sig->params [i], &align);
-#endif
- }
-
- /*
- * Handle the return value storage area.
- */
- amd64_lea_membase (p, AMD64_RAX, AMD64_RBP, stackval_pos);
- amd64_mov_membase_reg (p, AMD64_RBP, (mono_invocation_pos + G_STRUCT_OFFSET (MonoInvocation, retval)), AMD64_RAX, SIZEOF_VOID_P);
- if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) {
- MonoClass *klass = sig->ret->data.klass;
- if (!klass->enumtype) {
- amd64_mov_reg_membase (p, AMD64_RCX, AMD64_RBP, retval_ptr_rbp_offset, SIZEOF_VOID_P);
- amd64_mov_membase_reg (p, AMD64_RBP, stackval_pos, AMD64_RCX, SIZEOF_VOID_P);
- }
- }
-
- /*
- * Call the method.
- */
- amd64_lea_membase (p, int_arg_regs[0], AMD64_RBP, mono_invocation_pos);
- amd64_mov_reg_imm (p, AMD64_R11, ves_exec_method);
- amd64_call_reg (p, AMD64_R11);
-
- /*
- * Move the return value to the proper place.
- */
- amd64_lea_membase (p, AMD64_RAX, AMD64_RBP, stackval_pos);
- if (sig->ret->byref) {
- amd64_mov_reg_membase (p, AMD64_RAX, AMD64_RAX, 0, SIZEOF_VOID_P);
- } else {
- int simpletype = sig->ret->type;
- enum_retvalue:
- switch (sig->ret->type) {
- case MONO_TYPE_VOID:
- break;
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- amd64_movzx_reg_membase (p, AMD64_RAX, AMD64_RAX, 0, 1);
- break;
- case MONO_TYPE_CHAR:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- amd64_movzx_reg_membase (p, AMD64_RAX, AMD64_RAX, 0, 2);
- break;
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_STRING:
- case MONO_TYPE_CLASS:
- amd64_movzx_reg_membase (p, AMD64_RAX, AMD64_RAX, 0, 4);
- break;
- case MONO_TYPE_I8:
- amd64_movzx_reg_membase (p, AMD64_RAX, AMD64_RAX, 0, 8);
- break;
- case MONO_TYPE_R4:
- amd64_movss_regp_reg (p, AMD64_RAX, AMD64_XMM0);
- break;
- case MONO_TYPE_R8:
- amd64_movsd_regp_reg (p, AMD64_RAX, AMD64_XMM0);
- break;
- case MONO_TYPE_VALUETYPE: {
- int size;
- int arg_type;
- int regs_used;
- int offset1;
- int size1;
- int offset2;
- int size2;
-
- if (sig->ret->data.klass->enumtype) {
- simpletype = sig->ret->data.klass->enum_basetype->type;
- goto enum_retvalue;
- }
-
- arg_type = value_type_info(sig->params [i]->data.klass, &size, ®s_used, &offset1, &size1, &offset2, &size2);
-
- if (arg_type == ARG_IN_INT_REGS)
- {
- if (regs_used > 1)
- amd64_mov_membase_reg (p, AMD64_RAX, offset2, AMD64_RDX, size2);
- amd64_mov_membase_reg (p, AMD64_RAX, offset1, AMD64_RAX, size1);
- break;
- }
-
- if (arg_type == ARG_IN_FLOAT_REGS)
- {
- if (size1 == 4)
- amd64_movss_membase_reg (p, AMD64_RAX, offset1, AMD64_XMM0);
- else
- amd64_movsd_membase_reg (p, AMD64_RAX, offset1, AMD64_XMM0);
-
- if (regs_used > 1)
- {
- if (size2 == 4)
- amd64_movss_membase_reg (p, AMD64_RAX, offset2, AMD64_XMM1);
- else
- amd64_movsd_membase_reg (p, AMD64_RAX, offset2, AMD64_XMM1);
- }
- break;
- }
-
- /* Else result should have been stored in place already. IA32 code has a stackval_to_data call here, which
- * looks wrong to me as the pointer in the stack val being converted is setup to point to the output area anyway.
- * It all looks a bit suspect anyway.
- */
- break;
- }
- default:
- g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type);
- break;
- }
- }
-
- /*
- * Standard epilog.
- */
- amd64_leave (p);
- amd64_ret (p);
-
- g_assert (p - code_buffer < 512);
-
- ji = g_new0 (MonoJitInfo, 1);
- ji->method = method;
- ji->code_size = p - code_buffer;
- ji->code_start = g_memdup (code_buffer, p - code_buffer);
-
- mono_jit_info_table_add (mono_get_root_domain (), ji);
-
- return ji->code_start;
-}
diff --git a/mono/arch/ppc/Makefile.am b/mono/arch/ppc/Makefile.am
index 667ad258d73..9b209ef9400 100644
--- a/mono/arch/ppc/Makefile.am
+++ b/mono/arch/ppc/Makefile.am
@@ -1,7 +1 @@
-AM_CPPFLAGS = $(GLIB_CFLAGS) -I$(top_srcdir)
-
-noinst_LTLIBRARIES = libmonoarch-ppc.la
-
-libmonoarch_ppc_la_SOURCES = tramp.c ppc-codegen.h
-
-noinst_PROGRAMS = test
+EXTRA_DIST = ppc-codegen.h
\ No newline at end of file
diff --git a/mono/arch/ppc/test.c b/mono/arch/ppc/test.c
deleted file mode 100644
index c19358dcab0..00000000000
--- a/mono/arch/ppc/test.c
+++ /dev/null
@@ -1,35 +0,0 @@
-#include "ppc-codegen.h"
-#include
-
-/* don't run the resulting program, it will destroy your computer,
- * just objdump -d it to inspect we generated the correct assembler.
- * On Mac OS X use otool[64] -v -t
- */
-
-int main() {
- guint8 code [16000];
- guint8 *p = code;
- guint8 *cp;
-
- printf (".text\n.align 4\n.globl main\n");
-#ifndef __APPLE__
- printf (".type main,@function\n");
-#endif
- printf ("main:\n");
-
- ppc_stwu (p, ppc_r1, -32, ppc_r1);
- ppc_mflr (p, ppc_r0);
- ppc_stw (p, ppc_r31, 28, ppc_r1);
- ppc_or (p, ppc_r1, ppc_r2, ppc_r3);
- ppc_mr (p, ppc_r31, ppc_r1);
- ppc_lwz (p, ppc_r11, 0, ppc_r1);
- ppc_mtlr (p, ppc_r0);
- ppc_blr (p);
- ppc_addi (p, ppc_r6, ppc_r6, 16);
-
- for (cp = code; cp < p; cp++) {
- printf (".byte 0x%x\n", *cp);
- }
-
- return 0;
-}
diff --git a/mono/arch/ppc/tramp.c b/mono/arch/ppc/tramp.c
deleted file mode 100644
index 6bb1896255f..00000000000
--- a/mono/arch/ppc/tramp.c
+++ /dev/null
@@ -1,895 +0,0 @@
-/*
- * Create trampolines to invoke arbitrary functions.
- *
- * Copyright (C) Radek Doulik
- *
- */
-
-#include "config.h"
-#include
-#include
-#include "ppc-codegen.h"
-#include "mono/metadata/class.h"
-#include "mono/metadata/tabledefs.h"
-#include "mono/interpreter/interp.h"
-#include "mono/metadata/appdomain.h"
-
-#ifdef NEED_MPROTECT
-#include
-#include /* for PAGESIZE */
-#ifndef PAGESIZE
-#define PAGESIZE 4096
-#endif
-#endif
-
-#define DEBUG(x)
-
-/* gpointer
-fake_func (gpointer (*callme)(gpointer), stackval *retval, void *this_obj, stackval *arguments)
-{
- guint32 i = 0xc002becd;
-
- callme = (gpointer) 0x100fabcd;
-
- *(gpointer*)retval = (gpointer)(*callme) (arguments [0].data.p, arguments [1].data.p, arguments [2].data.p);
- *(gdouble*) retval = (gdouble)(*callme) (arguments [0].data.f);
-
- return (gpointer) (*callme) (((MonoType *)arguments [0]. data.p)->data.klass);
-} */
-
-#define MIN_CACHE_LINE 8
-
-static void inline
-flush_icache (guint8 *code, guint size)
-{
- guint i;
- guint8 *p;
-
- p = code;
- for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
- asm ("dcbst 0,%0;" : : "r"(p) : "memory");
- }
- asm ("sync");
- p = code;
- for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
- asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
- }
- asm ("sync");
- asm ("isync");
-}
-
-static void
-disassemble (guint8 *code, int size)
-{
- int i;
- FILE *ofd;
- const char *tmp = g_getenv("TMP");
- char *as_file;
- char *o_file;
- char *cmd;
-
- if (tmp == NULL)
- tmp = "/tmp";
- as_file = g_strdup_printf ("%s/test.s", tmp);
-
- if (!(ofd = fopen (as_file, "w")))
- g_assert_not_reached ();
-
- fprintf (ofd, "tmp:\n");
-
- for (i = 0; i < size; ++i)
- fprintf (ofd, ".byte %d\n", (unsigned int) code [i]);
-
- fclose (ofd);
-#ifdef __APPLE__
-#define DIS_CMD "otool -V -v -t"
-#else
-#define DIS_CMD "objdump -d"
-#endif
- o_file = g_strdup_printf ("%s/test.o", tmp);
- cmd = g_strdup_printf ("as %s -o %s", as_file, o_file);
- system (cmd);
- g_free (cmd);
- cmd = g_strdup_printf (DIS_CMD " %s", o_file);
- system (cmd);
- g_free (cmd);
- g_free (o_file);
- g_free (as_file);
-}
-
-
-#define NOT_IMPLEMENTED(x) \
- g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
-
-#define PROLOG_INS 8
-#define CALL_INS 2
-#define EPILOG_INS 6
-#define FLOAT_REGS 8
-#define GENERAL_REGS 8
-#ifdef __APPLE__
-#define MINIMAL_STACK_SIZE 10
-#define ALWAYS_ON_STACK(s) s
-#define FP_ALSO_IN_REG(s) s
-#define RET_ADDR_OFFSET 8
-#define STACK_PARAM_OFFSET 24
-#else
-#define MINIMAL_STACK_SIZE 5
-#define ALWAYS_ON_STACK(s)
-#define FP_ALSO_IN_REG(s) s
-#define ALIGN_DOUBLES
-#define RET_ADDR_OFFSET 4
-#define STACK_PARAM_OFFSET 8
-#endif
-
-static void inline
-add_general (guint *gr, guint *stack_size, guint *code_size, gboolean simple)
-{
- if (simple) {
- if (*gr >= GENERAL_REGS) {
- *stack_size += 4;
- *code_size += 8; /* load from stack, save on stack */
- } else {
- ALWAYS_ON_STACK (*stack_size += 4);
- *code_size += 4; /* load from stack */
- }
- } else {
- if (*gr >= GENERAL_REGS - 1) {
- *stack_size += 8;
-#ifdef ALIGN_DOUBLES
- *stack_size += (*stack_size % 8);
-#endif
- *code_size += 16; /* 2x load from stack, 2x save to stack */
- } else {
- ALWAYS_ON_STACK (*stack_size += 8);
- *code_size += 8; /* 2x load from stack */
- }
-#ifdef ALIGN_DOUBLES
- if ((*gr) & 1)
- (*gr) ++;
-#endif
- (*gr) ++;
- }
- (*gr) ++;
-}
-
-static void inline
-calculate_sizes (MonoMethodSignature *sig, guint *stack_size, guint *code_size, gboolean string_ctor, gboolean *use_memcpy)
-{
- guint i, fr, gr;
- guint32 simpletype;
-
- fr = gr = 0;
- *stack_size = MINIMAL_STACK_SIZE*4;
- *code_size = (PROLOG_INS + CALL_INS + EPILOG_INS)*4;
-
- if (sig->hasthis) {
- add_general (&gr, stack_size, code_size, TRUE);
- }
- DEBUG(printf("params: %d\n", sig->param_count));
- for (i = 0; i < sig->param_count; ++i) {
- DEBUG(printf("param %d: ", i));
- if (sig->params [i]->byref) {
- DEBUG(printf("byref\n"));
- add_general (&gr, stack_size, code_size, TRUE);
- continue;
- }
- simpletype = sig->params [i]->type;
- enum_calc_size:
- switch (simpletype) {
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_CHAR:
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_PTR:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_STRING:
- add_general (&gr, stack_size, code_size, TRUE);
- break;
- case MONO_TYPE_SZARRAY:
- add_general (&gr, stack_size, code_size, TRUE);
- *code_size += 4;
- break;
- case MONO_TYPE_VALUETYPE: {
- gint size;
- if (sig->params [i]->data.klass->enumtype) {
- simpletype = sig->params [i]->data.klass->enum_basetype->type;
- goto enum_calc_size;
- }
- size = mono_class_value_size (sig->params [i]->data.klass, NULL);
- if (size != 4) {
- DEBUG(printf ("copy %d bytes struct on stack\n",
- mono_class_value_size (sig->params [i]->data.klass, NULL)));
- *use_memcpy = TRUE;
- *code_size += 8*4;
- *stack_size += (size + 3) & (~3);
- if (gr > GENERAL_REGS) {
- *code_size += 4;
- *stack_size += 4;
- }
- } else {
- DEBUG(printf ("load %d bytes struct\n",
- mono_class_value_size (sig->params [i]->data.klass, NULL)));
- add_general (&gr, stack_size, code_size, TRUE);
- *code_size += 4;
- }
- break;
- }
- case MONO_TYPE_I8:
- add_general (&gr, stack_size, code_size, FALSE);
- break;
- case MONO_TYPE_R4:
- if (fr < 7) {
- *code_size += 4;
- fr ++;
- FP_ALSO_IN_REG (gr ++);
- ALWAYS_ON_STACK (*stack_size += 4);
- } else {
- NOT_IMPLEMENTED ("R4 arg");
- }
- break;
- case MONO_TYPE_R8:
- if (fr < 7) {
- *code_size += 4;
- fr ++;
- FP_ALSO_IN_REG (gr += 2);
- ALWAYS_ON_STACK (*stack_size += 8);
- } else {
- NOT_IMPLEMENTED ("R8 arg");
- }
- break;
- default:
- g_error ("Can't trampoline 0x%x", sig->params [i]->type);
- }
- }
-
- if (sig->ret->byref || string_ctor) {
- *code_size += 8;
- } else {
- simpletype = sig->ret->type;
-enum_retvalue:
- switch (simpletype) {
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- case MONO_TYPE_CHAR:
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_R4:
- case MONO_TYPE_R8:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_STRING:
- *code_size += 8;
- break;
- case MONO_TYPE_I8:
- *code_size += 12;
- break;
- case MONO_TYPE_VALUETYPE:
- if (sig->ret->data.klass->enumtype) {
- simpletype = sig->ret->data.klass->enum_basetype->type;
- goto enum_retvalue;
- }
- *code_size += 2*4;
- break;
- case MONO_TYPE_VOID:
- break;
- default:
- g_error ("Can't handle as return value 0x%x", sig->ret->type);
- }
- }
-
- if (*use_memcpy) {
- *stack_size += 2*4; /* for r14, r15 */
- *code_size += 6*4;
- if (sig->hasthis) {
- *stack_size += 4; /* for r16 */
- *code_size += 4;
- }
- }
-
- /* align stack size to 16 */
- DEBUG (printf (" stack size: %d (%d)\n code size: %d\n", (*stack_size + 15) & ~15, *stack_size, *code_size));
- *stack_size = (*stack_size + 15) & ~15;
-}
-
-static inline guint8 *
-emit_prolog (guint8 *p, MonoMethodSignature *sig, guint stack_size)
-{
- /* function prolog */
- ppc_stwu (p, ppc_r1, -stack_size, ppc_r1); /* sp <--- sp - stack_size, sp[0] <---- sp save sp, alloc stack */
- ppc_mflr (p, ppc_r0); /* r0 <--- LR */
- ppc_stw (p, ppc_r31, stack_size - 4, ppc_r1); /* sp[+4] <--- r31 save r31 */
- ppc_stw (p, ppc_r0, stack_size + RET_ADDR_OFFSET, ppc_r1); /* sp[-4] <--- LR save return address for "callme" */
- ppc_mr (p, ppc_r31, ppc_r1); /* r31 <--- sp */
-
- return p;
-}
-
-#define ARG_BASE ppc_r12
-#define ARG_SIZE sizeof (stackval)
-#define SAVE_4_IN_GENERIC_REGISTER \
- if (gr < GENERAL_REGS) { \
- ppc_lwz (p, ppc_r3 + gr, i*ARG_SIZE, ARG_BASE); \
- gr ++; \
- ALWAYS_ON_STACK (stack_par_pos += 4); \
- } else { \
- ppc_lwz (p, ppc_r11, i*ARG_SIZE, ARG_BASE); \
- ppc_stw (p, ppc_r11, stack_par_pos, ppc_r1); \
- stack_par_pos += 4; \
- }
-#define SAVE_4_VAL_IN_GENERIC_REGISTER \
- if (gr < GENERAL_REGS) { \
- ppc_lwz (p, ppc_r3 + gr, i*ARG_SIZE, ARG_BASE); \
- ppc_lwz (p, ppc_r3 + gr, 0, ppc_r3 + gr); \
- gr ++; \
- ALWAYS_ON_STACK (stack_par_pos += 4); \
- } else { \
- ppc_lwz (p, ppc_r11, i*ARG_SIZE, ARG_BASE); \
- ppc_lwz (p, ppc_r11, 0, ppc_r11); \
- ppc_stw (p, ppc_r11, stack_par_pos, ppc_r1); \
- stack_par_pos += 4; \
- }
-
-inline static guint8*
-emit_save_parameters (guint8 *p, MonoMethodSignature *sig, guint stack_size, gboolean use_memcpy)
-{
- guint i, fr, gr, stack_par_pos, struct_pos, cur_struct_pos;
- guint32 simpletype;
-
- fr = gr = 0;
- stack_par_pos = STACK_PARAM_OFFSET;
-
- ppc_stw (p, ppc_r4, stack_size - 12, ppc_r31); /* preserve "retval", sp[+8] */
-
- if (use_memcpy) {
- ppc_stw (p, ppc_r14, stack_size - 16, ppc_r31); /* save r14 */
- ppc_stw (p, ppc_r15, stack_size - 20, ppc_r31); /* save r15 */
- ppc_mr (p, ppc_r14, ppc_r3); /* keep "callme" in register */
- ppc_mr (p, ppc_r15, ppc_r6); /* keep "arguments" in register */
- } else {
- ppc_mr (p, ppc_r12, ppc_r6); /* keep "arguments" in register */
- ppc_mr (p, ppc_r0, ppc_r3); /* keep "callme" in register */
- }
-
- if (sig->hasthis) {
- if (use_memcpy) {
- ppc_stw (p, ppc_r16, stack_size - 24, ppc_r31); /* save r16 */
- ppc_mr (p, ppc_r16, ppc_r5);
- } else
- ppc_mr (p, ppc_r3, ppc_r5);
- gr ++;
- ALWAYS_ON_STACK (stack_par_pos += 4);
- }
-
- if (use_memcpy) {
- cur_struct_pos = struct_pos = stack_par_pos;
- for (i = 0; i < sig->param_count; ++i) {
- if (sig->params [i]->byref)
- continue;
- if (sig->params [i]->type == MONO_TYPE_VALUETYPE && !sig->params [i]->data.klass->enumtype) {
- gint size;
-
- size = mono_class_value_size (sig->params [i]->data.klass, NULL);
- if (size != 4) {
- /* call memcpy */
- ppc_addi (p, ppc_r3, ppc_r1, stack_par_pos);
- ppc_lwz (p, ppc_r4, i*16, ppc_r15);
- /* FIXME check if size > 0xffff */
- ppc_li (p, ppc_r5, size & 0xffff);
- ppc_lis (p, ppc_r0, (guint32) memcpy >> 16);
- ppc_ori (p, ppc_r0, ppc_r0, (guint32) memcpy & 0xffff);
- ppc_mtlr (p, ppc_r0);
- ppc_blrl (p);
- stack_par_pos += (size + 3) & (~3);
- }
- }
- }
-
- if (sig->hasthis) {
- ppc_mr (p, ppc_r3, ppc_r16);
- ppc_lwz (p, ppc_r16, stack_size - 24, ppc_r31); /* restore r16 */
- }
- ppc_mr (p, ppc_r0, ppc_r14);
- ppc_mr (p, ppc_r12, ppc_r15);
- ppc_lwz (p, ppc_r14, stack_size - 16, ppc_r31); /* restore r14 */
- ppc_lwz (p, ppc_r15, stack_size - 20, ppc_r31); /* restore r15 */
- }
-
- if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) {
- MonoClass *klass = sig->ret->data.klass;
- if (!klass->enumtype) {
- gint size = mono_class_native_size (klass, NULL);
-
- DEBUG(printf ("retval value type size: %d\n", size));
- if (size > 8) {
- ppc_lwz (p, ppc_r3, stack_size - 12, ppc_r31);
- ppc_lwz (p, ppc_r3, 0, ppc_r3);
- gr ++;
- ALWAYS_ON_STACK (stack_par_pos += 4);
- } else {
- NOT_IMPLEMENTED ("retval valuetype <= 8 bytes");
- }
- }
- }
-
- for (i = 0; i < sig->param_count; ++i) {
- if (sig->params [i]->byref) {
- SAVE_4_IN_GENERIC_REGISTER;
- continue;
- }
- simpletype = sig->params [i]->type;
- enum_calc_size:
- switch (simpletype) {
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- case MONO_TYPE_CHAR:
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_PTR:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_STRING:
- case MONO_TYPE_SZARRAY:
- SAVE_4_IN_GENERIC_REGISTER;
- break;
- case MONO_TYPE_VALUETYPE: {
- gint size;
- if (sig->params [i]->data.klass->enumtype) {
- simpletype = sig->params [i]->data.klass->enum_basetype->type;
- goto enum_calc_size;
- }
- size = mono_class_value_size (sig->params [i]->data.klass, NULL);
- if (size == 4) {
- SAVE_4_VAL_IN_GENERIC_REGISTER;
- } else {
- if (gr < GENERAL_REGS) {
- ppc_addi (p, ppc_r3 + gr, ppc_r1, cur_struct_pos);
- gr ++;
- } else {
- ppc_lwz (p, ppc_r11, cur_struct_pos, ppc_r1);
- ppc_stw (p, ppc_r11, stack_par_pos, ppc_r1);
- stack_par_pos += 4;
- }
- cur_struct_pos += (size + 3) & (~3);
- }
- break;
- }
- case MONO_TYPE_I8:
-DEBUG(printf("Mono_Type_i8. gr = %d, arg_base = %d\n", gr, ARG_BASE));
-#ifdef ALIGN_DOUBLES
- if (gr & 1)
- gr++;
-#endif
- if (gr < 7) {
- ppc_lwz (p, ppc_r3 + gr, i*ARG_SIZE, ARG_BASE);
- ppc_lwz (p, ppc_r3 + gr + 1, i*ARG_SIZE + 4, ARG_BASE);
- ALWAYS_ON_STACK (stack_par_pos += 8);
- } else if (gr == 7) {
- ppc_lwz (p, ppc_r3 + gr, i*ARG_SIZE, ARG_BASE);
- ppc_lwz (p, ppc_r11, i*ARG_SIZE + 4, ARG_BASE);
- ppc_stw (p, ppc_r11, stack_par_pos + 4, ppc_r1);
- stack_par_pos += 8;
- } else {
- ppc_lwz (p, ppc_r11, i*ARG_SIZE, ARG_BASE);
- ppc_stw (p, ppc_r11, stack_par_pos, ppc_r1);
- ppc_lwz (p, ppc_r11, i*ARG_SIZE + 4, ARG_BASE);
- ppc_stw (p, ppc_r11, stack_par_pos + 4, ppc_r1);
- stack_par_pos += 8;
- }
- gr += 2;
- break;
- case MONO_TYPE_R4:
- if (fr < 7) {
- ppc_lfs (p, ppc_f1 + fr, i*ARG_SIZE, ARG_BASE);
- fr ++;
- FP_ALSO_IN_REG (gr ++);
- ALWAYS_ON_STACK (stack_par_pos += 4);
- } else {
- NOT_IMPLEMENTED ("r4 on stack");
- }
- break;
- case MONO_TYPE_R8:
- if (fr < 7) {
- ppc_lfd (p, ppc_f1 + fr, i*ARG_SIZE, ARG_BASE);
- fr ++;
- FP_ALSO_IN_REG (gr += 2);
- ALWAYS_ON_STACK (stack_par_pos += 8);
- } else {
- NOT_IMPLEMENTED ("r8 on stack");
- }
- break;
- default:
- g_error ("Can't trampoline 0x%x", sig->params [i]->type);
- }
- }
-
- return p;
-}
-
-static inline guint8 *
-alloc_code_memory (guint code_size)
-{
- guint8 *p;
-
-#ifdef NEED_MPROTECT
- p = g_malloc (code_size + PAGESIZE - 1);
-
- /* Align to a multiple of PAGESIZE, assumed to be a power of two */
- p = (char *)(((int) p + PAGESIZE-1) & ~(PAGESIZE-1));
-#else
- p = g_malloc (code_size);
-#endif
- DEBUG (printf (" align: %p (%d)\n", p, (guint)p % 4));
-
- return p;
-}
-
-/* static MonoString*
-mono_string_new_wrapper (const char *text)
-{
- return text ? mono_string_new (mono_domain_get (), text) : NULL;
-} */
-
-static inline guint8 *
-emit_call_and_store_retval (guint8 *p, MonoMethodSignature *sig, guint stack_size, gboolean string_ctor)
-{
- guint32 simpletype;
-
- /* call "callme" */
- ppc_mtlr (p, ppc_r0);
- ppc_blrl (p);
-
- /* get return value */
- if (sig->ret->byref || string_ctor) {
- ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
- ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
- } else {
- simpletype = sig->ret->type;
-enum_retvalue:
- switch (simpletype) {
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
- ppc_stb (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
- break;
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- case MONO_TYPE_CHAR:
- ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
- ppc_sth (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
- break;
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_STRING:
- ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
- ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
- break;
- case MONO_TYPE_R4:
- ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
- ppc_stfs (p, ppc_f1, 0, ppc_r9); /* save return value (f1) to "retval" */
- break;
- case MONO_TYPE_R8:
- ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
- ppc_stfd (p, ppc_f1, 0, ppc_r9); /* save return value (f1) to "retval" */
- break;
- case MONO_TYPE_I8:
- ppc_lwz (p, ppc_r9, stack_size - 12, ppc_r31); /* load "retval" address */
- ppc_stw (p, ppc_r3, 0, ppc_r9); /* save return value (r3) to "retval" */
- ppc_stw (p, ppc_r4, 4, ppc_r9); /* save return value (r3) to "retval" */
- break;
- case MONO_TYPE_VALUETYPE:
- if (sig->ret->data.klass->enumtype) {
- simpletype = sig->ret->data.klass->enum_basetype->type;
- goto enum_retvalue;
- }
- break;
- case MONO_TYPE_VOID:
- break;
- default:
- g_error ("Can't handle as return value 0x%x", sig->ret->type);
- }
- }
-
- return p;
-}
-
-static inline guint8 *
-emit_epilog (guint8 *p, MonoMethodSignature *sig, guint stack_size)
-{
- /* function epilog */
- ppc_lwz (p, ppc_r11, 0, ppc_r1); /* r11 <--- sp[0] load backchain from caller's function */
- ppc_lwz (p, ppc_r0, RET_ADDR_OFFSET, ppc_r11); /* r0 <--- r11[4] load return address */
- ppc_mtlr (p, ppc_r0); /* LR <--- r0 set return address */
- ppc_lwz (p, ppc_r31, -4, ppc_r11); /* r31 <--- r11[-4] restore r31 */
- ppc_mr (p, ppc_r1, ppc_r11); /* sp <--- r11 restore stack */
- ppc_blr (p); /* return */
-
- return p;
-}
-
-MonoPIFunc
-mono_arch_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
-{
- guint8 *p, *code_buffer;
- guint stack_size, code_size;
- gboolean use_memcpy = FALSE;
-
- DEBUG (printf ("\nPInvoke [start emiting]\n"));
- calculate_sizes (sig, &stack_size, &code_size, string_ctor, &use_memcpy);
-
- p = code_buffer = alloc_code_memory (code_size);
- p = emit_prolog (p, sig, stack_size);
- p = emit_save_parameters (p, sig, stack_size, use_memcpy);
- p = emit_call_and_store_retval (p, sig, stack_size, string_ctor);
- p = emit_epilog (p, sig, stack_size);
-
- /* {
- guchar *cp;
- printf (".text\n.align 4\n.globl main\n.type main,@function\nmain:\n");
- for (cp = code_buffer; cp < p; cp++) {
- printf (".byte 0x%x\n", *cp);
- }
- } */
-
-#ifdef NEED_MPROTECT
- if (mprotect (code_buffer, 1024, PROT_READ | PROT_WRITE | PROT_EXEC)) {
- g_error ("Cannot mprotect trampoline\n");
- }
-#endif
-
- DEBUG (printf ("emited code size: %d\n", p - code_buffer));
- flush_icache (code_buffer, p - code_buffer);
-
- DEBUG (printf ("PInvoke [end emiting]\n"));
-
- return (MonoPIFunc) code_buffer;
- /* return fake_func; */
-}
-
-
-#ifdef __APPLE__
-#define MINV_POS 40 /* MonoInvocation structure offset on stack - STACK_PARAM_OFFSET + 4 pointer args for stackval_from_data */
-#else
-#define MINV_POS 8 /* MonoInvocation structure offset on stack */
-#endif
-#define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count)
-#define OBJ_POS 8
-#define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type))
-
-/*
- * Returns a pointer to a native function that can be used to
- * call the specified method.
- * The function created will receive the arguments according
- * to the call convention specified in the method.
- * This function works by creating a MonoInvocation structure,
- * filling the fields in and calling ves_exec_method on it.
- * Still need to figure out how to handle the exception stuff
- * across the managed/unmanaged boundary.
- */
-void *
-mono_arch_create_method_pointer (MonoMethod *method)
-{
- MonoMethodSignature *sig;
- MonoJitInfo *ji;
- guint8 *p, *code_buffer;
- guint i, align = 0, code_size, stack_size, stackval_arg_pos, local_pos, local_start, reg_param = 0, stack_param,
- cpos, vt_cur;
- gint *vtbuf;
- guint32 simpletype;
-
- code_size = 1024;
- stack_size = 1024;
- stack_param = 0;
-
- sig = mono_method_signature (method);
-
- p = code_buffer = g_malloc (code_size);
-
- DEBUG (printf ("\nDelegate [start emiting] %s\n", mono_method_get_name (method)));
-
- /* prolog */
- ppc_stwu (p, ppc_r1, -stack_size, ppc_r1); /* sp <--- sp - stack_size, sp[0] <---- sp save sp, alloc stack */
- ppc_mflr (p, ppc_r0); /* r0 <--- LR */
- ppc_stw (p, ppc_r31, stack_size - 4, ppc_r1); /* sp[+4] <--- r31 save r31 */
- ppc_stw (p, ppc_r0, stack_size + RET_ADDR_OFFSET, ppc_r1); /* sp[-4] <--- LR save return address for "callme" */
- ppc_mr (p, ppc_r31, ppc_r1); /* r31 <--- sp */
-
- /* let's fill MonoInvocation */
- /* first zero some fields */
- ppc_li (p, ppc_r0, 0);
- ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex)), ppc_r31);
- ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler)), ppc_r31);
- ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent)), ppc_r31);
-
- /* set method pointer */
- ppc_lis (p, ppc_r0, (guint32) method >> 16);
- ppc_ori (p, ppc_r0, ppc_r0, (guint32) method & 0xffff);
- ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method)), ppc_r31);
-
- local_start = local_pos = MINV_POS + sizeof (MonoInvocation) + (sig->param_count + 1) * sizeof (stackval);
-
- if (sig->hasthis) {
- ppc_stw (p, ppc_r3, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)), ppc_r31);
- reg_param = 1;
- }
-
- if (sig->param_count) {
- gint save_count = MIN (8, sig->param_count + sig->hasthis);
- for (i = reg_param; i < save_count; i ++) {
- ppc_stw (p, ppc_r3 + i, local_pos, ppc_r31);
- local_pos += 4;
- DEBUG (printf ("save r%d\n", 4 + i));
- }
- }
-
- /* prepare space for valuetypes */
- vt_cur = local_pos;
- vtbuf = alloca (sizeof(int)*sig->param_count);
- cpos = 0;
- for (i = 0; i < sig->param_count; i++) {
- MonoType *type = sig->params [i];
- vtbuf [i] = -1;
- if (type->type == MONO_TYPE_VALUETYPE) {
- MonoClass *klass = type->data.klass;
- gint size;
-
- if (klass->enumtype)
- continue;
- size = mono_class_native_size (klass, &align);
- cpos += align - 1;
- cpos &= ~(align - 1);
- vtbuf [i] = cpos;
- cpos += size;
- }
- }
- cpos += 3;
- cpos &= ~3;
-
- local_pos += cpos;
-
- /* set MonoInvocation::stack_args */
- stackval_arg_pos = MINV_POS + sizeof (MonoInvocation);
- ppc_addi (p, ppc_r0, ppc_r31, stackval_arg_pos);
- ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, stack_args)), ppc_r31);
-
- /* add stackval arguments */
- for (i = 0; i < sig->param_count; ++i) {
- if (reg_param < 8) {
- ppc_addi (p, ppc_r5, ppc_r31, local_start + i*4);
- reg_param ++;
- } else {
- ppc_addi (p, ppc_r5, stack_size + 8 + stack_param, ppc_r31);
- stack_param ++;
- }
- ppc_lis (p, ppc_r3, (guint32) sig->params [i] >> 16);
-
- if (vtbuf [i] >= 0) {
- ppc_addi (p, ppc_r4, ppc_r31, vt_cur);
- ppc_stw (p, ppc_r4, stackval_arg_pos, ppc_r31);
- ppc_addi (p, ppc_r4, ppc_r31, stackval_arg_pos);
- ppc_lwz (p, ppc_r5, 0, ppc_r5);
- vt_cur += vtbuf [i];
- } else {
- ppc_addi (p, ppc_r4, ppc_r31, stackval_arg_pos);
- }
- ppc_ori (p, ppc_r3, ppc_r3, (guint32) sig->params [i] & 0xffff);
- ppc_lis (p, ppc_r0, (guint32) stackval_from_data >> 16);
- ppc_li (p, ppc_r6, sig->pinvoke);
- ppc_ori (p, ppc_r0, ppc_r0, (guint32) stackval_from_data & 0xffff);
- ppc_mtlr (p, ppc_r0);
- ppc_blrl (p);
-
- stackval_arg_pos += sizeof (stackval);
- }
-
- /* return value storage */
- if (sig->param_count) {
- ppc_addi (p, ppc_r0, ppc_r31, stackval_arg_pos);
- }
- ppc_stw (p, ppc_r0, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)), ppc_r31);
-
- /* call ves_exec_method */
- ppc_lis (p, ppc_r0, (guint32) ves_exec_method >> 16);
- ppc_addi (p, ppc_r3, ppc_r31, MINV_POS);
- ppc_ori (p, ppc_r0, ppc_r0, (guint32) ves_exec_method & 0xffff);
- ppc_mtlr (p, ppc_r0);
- ppc_blrl (p);
-
- /* move retval from stackval to proper place (r3/r4/...) */
- if (sig->ret->byref) {
- DEBUG (printf ("ret by ref\n"));
- ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31);
- } else {
- enum_retvalue:
- switch (sig->ret->type) {
- case MONO_TYPE_VOID:
- break;
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- ppc_lbz (p, ppc_r3, stackval_arg_pos, ppc_r31);
- break;
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- ppc_lhz (p, ppc_r3, stackval_arg_pos, ppc_r31);
- break;
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_STRING:
- case MONO_TYPE_CLASS:
- ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31);
- break;
- case MONO_TYPE_I8:
- ppc_lwz (p, ppc_r3, stackval_arg_pos, ppc_r31);
- ppc_lwz (p, ppc_r4, stackval_arg_pos + 4, ppc_r31);
- break;
- case MONO_TYPE_R4:
- ppc_lfs (p, ppc_f1, stackval_arg_pos, ppc_r31);
- break;
- case MONO_TYPE_R8:
- ppc_lfd (p, ppc_f1, stackval_arg_pos, ppc_r31);
- break;
- case MONO_TYPE_VALUETYPE:
- if (sig->ret->data.klass->enumtype) {
- simpletype = sig->ret->data.klass->enum_basetype->type;
- goto enum_retvalue;
- }
- NOT_IMPLEMENTED ("value type as ret val from delegate");
- break;
- default:
- g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type);
- break;
- }
- }
-
- /* epilog */
- ppc_lwz (p, ppc_r11, 0, ppc_r1); /* r11 <--- sp[0] load backchain from caller's function */
- ppc_lwz (p, ppc_r0, RET_ADDR_OFFSET, ppc_r11); /* r0 <--- r11[4] load return address */
- ppc_mtlr (p, ppc_r0); /* LR <--- r0 set return address */
- ppc_lwz (p, ppc_r31, -4, ppc_r11); /* r31 <--- r11[-4] restore r31 */
- ppc_mr (p, ppc_r1, ppc_r11); /* sp <--- r11 restore stack */
- ppc_blr (p); /* return */
-
- DEBUG (printf ("emited code size: %d\n", p - code_buffer));
- DEBUG (disassemble (code_buffer, p - code_buffer));
- flush_icache (code_buffer, p - code_buffer);
-
- DEBUG (printf ("Delegate [end emiting]\n"));
-
- ji = g_new0 (MonoJitInfo, 1);
- ji->method = method;
- ji->code_size = p - code_buffer;
- ji->code_start = code_buffer;
-
- mono_jit_info_table_add (mono_get_root_domain (), ji);
-
- return ji->code_start;
-}
diff --git a/mono/arch/unknown.c b/mono/arch/unknown.c
deleted file mode 100644
index d865299001c..00000000000
--- a/mono/arch/unknown.c
+++ /dev/null
@@ -1,18 +0,0 @@
-#include "mono/interpreter/interp.h"
-#ifdef NO_PORT
-MonoPIFunc
-mono_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
-{
- g_error ("Unsupported arch");
- return NULL;
-}
-
-void *
-mono_create_method_pointer (MonoMethod *method)
-{
- g_error ("Unsupported arch");
- return NULL;
-}
-
-#endif
-
diff --git a/mono/arch/x86/Makefile.am b/mono/arch/x86/Makefile.am
index e88506e4cd8..bab0f9e54d6 100644
--- a/mono/arch/x86/Makefile.am
+++ b/mono/arch/x86/Makefile.am
@@ -1,5 +1 @@
-AM_CPPFLAGS = $(GLIB_CFLAGS) -I$(top_srcdir)
-
-noinst_LTLIBRARIES = libmonoarch-x86.la
-
-libmonoarch_x86_la_SOURCES = tramp.c x86-codegen.h
+EXTRA_DIST = x86-codegen.h
\ No newline at end of file
diff --git a/mono/arch/x86/test.c b/mono/arch/x86/test.c
deleted file mode 100644
index 3511e8fdaf0..00000000000
--- a/mono/arch/x86/test.c
+++ /dev/null
@@ -1,225 +0,0 @@
-#include "x86-codegen.h"
-#include
-
-/* don't run the resulting program, it will destroy your computer,
- * just objdump -d it to inspect we generated the correct assembler.
- */
-
-int main() {
- unsigned char code [16000];
- unsigned char *p = code;
- unsigned char *target, *start, *end;
- unsigned long mem_addr = 0xdeadbeef;
- int size, i;
-
- printf (".text\n.align 4\n.globl main\n.type main,@function\nmain:\n");
-
- x86_prolog (p, 16, X86_CALLER_REGS);
-
- x86_cmpxchg_reg_reg (p, X86_EAX, X86_EBP);
- x86_cmpxchg_membase_reg (p, X86_EAX, 12, X86_EBP);
-
- x86_xchg_reg_reg (p, X86_EAX, X86_EBP, 4);
- x86_xchg_reg_reg (p, X86_EAX, X86_EBP, 1); // FIXME?
- x86_xchg_membase_reg (p, X86_EAX, 12, X86_EBP, 4);
- x86_xchg_membase_reg (p, X86_EAX, 12, X86_EBP, 2);
- x86_xchg_membase_reg (p, X86_EAX, 12, X86_EBX, 1); // FIXME?
-
- x86_inc_reg (p, X86_EAX);
- x86_inc_mem (p, mem_addr);
- x86_inc_membase (p, X86_ESP, 4);
-
- x86_nop (p);
- x86_nop (p);
-
- x86_dec_reg (p, X86_EAX);
- x86_dec_reg (p, X86_ECX);
- x86_dec_mem (p, mem_addr);
- x86_dec_membase (p, X86_ESP, 4);
-
- x86_not_reg (p, X86_EDX);
- x86_not_reg (p, X86_ECX);
- x86_not_mem (p, mem_addr);
- x86_not_membase (p, X86_ESP, 4);
- x86_not_membase (p, X86_ESP, 0x4444444);
- x86_not_membase (p, X86_EBP, 0x4444444);
- x86_not_membase (p, X86_ECX, 0x4444444);
- x86_not_membase (p, X86_EDX, 0);
- x86_not_membase (p, X86_EBP, 0);
-
- x86_neg_reg (p, X86_EAX);
- x86_neg_reg (p, X86_ECX);
- x86_neg_mem (p, mem_addr);
- x86_neg_membase (p, X86_ESP, 8);
-
- x86_alu_reg_imm (p, X86_ADD, X86_EAX, 5);
- x86_alu_reg_imm (p, X86_ADD, X86_EBX, -10);
- x86_alu_reg_imm (p, X86_SUB, X86_EDX, 7);
- x86_alu_reg_imm (p, X86_OR, X86_ESP, 0xffffedaf);
- x86_alu_reg_imm (p, X86_CMP, X86_ECX, 1);
- x86_alu_mem_imm (p, X86_ADC, mem_addr, 2);
- x86_alu_membase_imm (p, X86_ADC, X86_ESP, -4, 4);
- x86_alu_membase_imm (p, X86_ADC, X86_ESP, -12, 0xffffedaf);
-
- x86_alu_mem_reg (p, X86_SUB, mem_addr, X86_EDX);
- x86_alu_reg_reg (p, X86_ADD, X86_EAX, X86_EBX);
- x86_alu_reg_mem (p, X86_ADD, X86_EAX, mem_addr);
- x86_alu_reg_imm (p, X86_ADD, X86_EAX, 0xdeadbeef);
- x86_alu_reg_membase (p, X86_XOR, X86_EDX, X86_ESP, 4);
- x86_alu_membase_reg (p, X86_XOR, X86_EBP, 8, X86_ESI);
-
- x86_test_reg_imm (p, X86_EAX, 16);
- x86_test_reg_imm (p, X86_EDX, -16);
- x86_test_mem_imm (p, mem_addr, 1);
- x86_test_membase_imm (p, X86_EBP, 8, 1);
-
- x86_test_reg_reg (p, X86_EAX, X86_EDX);
- x86_test_mem_reg (p, mem_addr, X86_EDX);
- x86_test_membase_reg (p, X86_ESI, 4, X86_EDX);
-
- x86_shift_reg_imm (p, X86_SHL, X86_EAX, 1);
- x86_shift_reg_imm (p, X86_SHL, X86_EDX, 2);
-
- x86_shift_mem_imm (p, X86_SHL, mem_addr, 2);
- x86_shift_membase_imm (p, X86_SHLR, X86_EBP, 8, 4);
-
- /*
- * Shift by CL
- */
- x86_shift_reg (p, X86_SHL, X86_EAX);
- x86_shift_mem (p, X86_SHL, mem_addr);
-
- x86_mul_reg (p, X86_EAX, 0);
- x86_mul_reg (p, X86_EAX, 1);
- x86_mul_membase (p, X86_EBP, 8, 1);
-
- x86_imul_reg_reg (p, X86_EBX, X86_EDX);
- x86_imul_reg_membase (p, X86_EBX, X86_EBP, 12);
-
- x86_imul_reg_reg_imm (p, X86_EBX, X86_EDX, 10);
- x86_imul_reg_mem_imm (p, X86_EBX, mem_addr, 20);
- x86_imul_reg_membase_imm (p, X86_EBX, X86_EBP, 16, 300);
-
- x86_div_reg (p, X86_EDX, 0);
- x86_div_reg (p, X86_EDX, 1);
- x86_div_mem (p, mem_addr, 1);
- x86_div_membase (p, X86_ESI, 4, 1);
-
- x86_mov_mem_reg (p, mem_addr, X86_EAX, 4);
- x86_mov_mem_reg (p, mem_addr, X86_EAX, 2);
- x86_mov_mem_reg (p, mem_addr, X86_EAX, 1);
- x86_mov_membase_reg (p, X86_EBP, 4, X86_EAX, 1);
-
- x86_mov_regp_reg (p, X86_EAX, X86_EAX, 4);
- x86_mov_membase_reg (p, X86_EAX, 0, X86_EAX, 4);
- x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
- x86_mov_reg_memindex (p, X86_ECX, X86_EAX, 34, X86_EDX, 2, 4);
- x86_mov_reg_memindex (p, X86_ECX, X86_NOBASEREG, 34, X86_EDX, 2, 4);
- x86_mov_memindex_reg (p, X86_EAX, X86_EAX, 0, X86_EDX, 2, 4);
- x86_mov_reg_reg (p, X86_EAX, X86_EAX, 1);
- x86_mov_reg_reg (p, X86_EAX, X86_EAX, 4);
- x86_mov_reg_mem (p, X86_EAX, mem_addr, 4);
-
- x86_mov_reg_imm (p, X86_EAX, 10);
- x86_mov_mem_imm (p, mem_addr, 54, 4);
- x86_mov_mem_imm (p, mem_addr, 54, 1);
-
- x86_lea_mem (p, X86_EDX, mem_addr);
- /* test widen */
- x86_widen_memindex (p, X86_EDX, X86_ECX, 0, X86_EBX, 2, 1, 0);
-
- x86_cdq (p);
- x86_wait (p);
-
- x86_fp_op_mem (p, X86_FADD, mem_addr, 1);
- x86_fp_op_mem (p, X86_FSUB, mem_addr, 0);
- x86_fp_op (p, X86_FSUB, 2);
- x86_fp_op_reg (p, X86_FMUL, 1, 0);
- x86_fstp (p, 2);
- x86_fcompp (p);
- x86_fnstsw (p);
- x86_fnstcw (p, mem_addr);
- x86_fnstcw_membase (p, X86_ESP, -8);
-
- x86_fldcw_membase (p, X86_ESP, -8);
- x86_fchs (p);
- x86_frem (p);
- x86_fxch (p, 3);
- x86_fcomip (p, 3);
- x86_fld_membase (p, X86_ESP, -8, 1);
- x86_fld_membase (p, X86_ESP, -8, 0);
- x86_fld80_membase (p, X86_ESP, -8);
- x86_fild_membase (p, X86_ESP, -8, 1);
- x86_fild_membase (p, X86_ESP, -8, 0);
- x86_fld_reg (p, 4);
- x86_fldz (p);
- x86_fld1 (p);
-
- x86_fst (p, mem_addr, 1, 0);
- x86_fst (p, mem_addr, 1, 1);
- x86_fst (p, mem_addr, 0, 1);
-
- x86_fist_pop_membase (p, X86_EDX, 4, 1);
- x86_fist_pop_membase (p, X86_EDX, 4, 0);
-
- x86_push_reg (p, X86_EBX);
- x86_push_membase (p, X86_EBP, 8);
- x86_push_imm (p, -1);
- x86_pop_reg (p, X86_EBX);
-
- x86_pushad (p);
- x86_pushfd (p);
- x86_popfd (p);
- x86_popad (p);
-
- target = p;
-
- start = p;
- x86_jump32 (p, mem_addr);
- x86_patch (start, target);
- start = p;
- x86_jump8 (p, 12);
- x86_patch (start, target);
- x86_jump_reg (p, X86_EAX);
- x86_jump_membase (p, X86_EDX, 16);
-
- x86_jump_code (p, target);
-
- x86_branch8 (p, X86_CC_EQ, 54, 1);
- x86_branch32 (p, X86_CC_LT, 54, 0);
- x86_branch (p, X86_CC_GT, target, 0);
- x86_branch_disp (p, X86_CC_NE, -4, 0);
-
- x86_set_reg (p, X86_CC_EQ, X86_EAX, 0);
- x86_set_membase (p, X86_CC_LE, X86_EBP, -8, 0);
-
- x86_call_code (p, printf);
- x86_call_reg (p, X86_ECX);
-
- x86_sahf (p);
-
- x86_fsin (p);
- x86_fcos (p);
- x86_fabs (p);
- x86_fpatan (p);
- x86_fprem (p);
- x86_fprem1 (p);
- x86_frndint (p);
- x86_fsqrt (p);
- x86_fptan (p);
-
- x86_leave (p);
- x86_ret (p);
- x86_ret_imm (p, 24);
-
- x86_cmov_reg (p, X86_CC_GT, 1, X86_EAX, X86_EDX);
- x86_cmov_membase (p, X86_CC_GT, 0, X86_EAX, X86_EDX, -4);
-
- x86_nop (p);
- x86_epilog (p, X86_CALLER_REGS);
-
- size = p-code;
- for (i = 0; i < size; ++i)
- printf (".byte %d\n", (unsigned int) code [i]);
- return 0;
-}
diff --git a/mono/arch/x86/tramp.c b/mono/arch/x86/tramp.c
deleted file mode 100644
index fab5a55325f..00000000000
--- a/mono/arch/x86/tramp.c
+++ /dev/null
@@ -1,545 +0,0 @@
-/*
- * Create trampolines to invoke arbitrary functions.
- *
- * Copyright (C) Ximian Inc.
- *
- * Authors:
- * Paolo Molaro (lupus@ximian.com)
- * Dietmar Maurer (dietmar@ximian.com)
- *
- */
-
-#include "config.h"
-#include
-#include
-#include "x86-codegen.h"
-#include "mono/metadata/class.h"
-#include "mono/metadata/tabledefs.h"
-#include "mono/interpreter/interp.h"
-#include "mono/metadata/appdomain.h"
-#include "mono/metadata/marshal.h"
-
-/*
- * The resulting function takes the form:
- * void func (void (*callme)(), void *retval, void *this_obj, stackval *arguments);
- */
-#define FUNC_ADDR_POS 8
-#define RETVAL_POS 12
-#define THIS_POS 16
-#define ARGP_POS 20
-#define LOC_POS -4
-
-#define ARG_SIZE sizeof (stackval)
-
-MonoPIFunc
-mono_arch_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
-{
- unsigned char *p, *code_buffer;
- guint32 stack_size = 0, code_size = 50;
- guint32 arg_pos, simpletype;
- int i, stringp;
- static GHashTable *cache = NULL;
- MonoPIFunc res;
-
- if (!cache)
- cache = g_hash_table_new ((GHashFunc)mono_signature_hash,
- (GCompareFunc)mono_metadata_signature_equal);
-
- if ((res = (MonoPIFunc)g_hash_table_lookup (cache, sig)))
- return res;
-
- if (sig->hasthis) {
- stack_size += sizeof (gpointer);
- code_size += 10;
- }
-
- if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref && !sig->ret->data.klass->enumtype) {
- stack_size += sizeof (gpointer);
- code_size += 5;
- }
-
- for (i = 0; i < sig->param_count; ++i) {
- if (sig->params [i]->byref) {
- stack_size += sizeof (gpointer);
- code_size += 20;
- continue;
- }
- simpletype = sig->params [i]->type;
-enum_calc_size:
- switch (simpletype) {
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_CHAR:
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_PTR:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_STRING:
- stack_size += 4;
- code_size += i < 10 ? 5 : 8;
- break;
- case MONO_TYPE_VALUETYPE: {
- int size;
- if (sig->params [i]->data.klass->enumtype) {
- simpletype = sig->params [i]->data.klass->enum_basetype->type;
- goto enum_calc_size;
- }
- if ((size = mono_class_native_size (sig->params [i]->data.klass, NULL)) != 4) {
- stack_size += size + 3;
- stack_size &= ~3;
- code_size += 32;
- } else {
- stack_size += 4;
- code_size += i < 10 ? 5 : 8;
- }
- break;
- }
- case MONO_TYPE_I8:
- stack_size += 8;
- code_size += i < 10 ? 5 : 8;
- break;
- case MONO_TYPE_R4:
- stack_size += 4;
- code_size += i < 10 ? 10 : 13;
- break;
- case MONO_TYPE_R8:
- stack_size += 8;
- code_size += i < 10 ? 7 : 10;
- break;
- default:
- g_error ("Can't trampoline 0x%x", sig->params [i]->type);
- }
- }
- /*
- * FIXME: take into account large return values.
- */
-
- code_buffer = p = alloca (code_size);
-
- /*
- * Standard function prolog.
- */
- x86_push_reg (p, X86_EBP);
- x86_mov_reg_reg (p, X86_EBP, X86_ESP, 4);
- /*
- * and align to 16 byte boundary...
- */
- stack_size += 15;
- stack_size &= ~15;
-
- if (stack_size)
- x86_alu_reg_imm (p, X86_SUB, X86_ESP, stack_size);
-
- /*
- * EDX has the pointer to the args.
- */
- x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
-
- /*
- * Push arguments in reverse order.
- */
- stringp = 0;
- for (i = sig->param_count; i; --i) {
- arg_pos = ARG_SIZE * (i - 1);
- if (sig->params [i - 1]->byref) {
- x86_push_membase (p, X86_EDX, arg_pos);
- continue;
- }
- simpletype = sig->params [i - 1]->type;
-enum_marshal:
- switch (simpletype) {
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- case MONO_TYPE_CHAR:
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_PTR:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_STRING:
- x86_push_membase (p, X86_EDX, arg_pos);
- break;
- case MONO_TYPE_R4:
- x86_alu_reg_imm (p, X86_SUB, X86_ESP, 4);
- x86_fld_membase (p, X86_EDX, arg_pos, TRUE);
- x86_fst_membase (p, X86_ESP, 0, FALSE, TRUE);
- break;
- case MONO_TYPE_CLASS:
- x86_push_membase (p, X86_EDX, arg_pos);
- break;
- case MONO_TYPE_SZARRAY:
- x86_push_membase (p, X86_EDX, arg_pos);
- break;
- case MONO_TYPE_VALUETYPE:
- if (!sig->params [i - 1]->data.klass->enumtype) {
- int size = mono_class_native_size (sig->params [i - 1]->data.klass, NULL);
- if (size == 4) {
- /* it's a structure that fits in 4 bytes, need to push the value pointed to */
- x86_mov_reg_membase (p, X86_EAX, X86_EDX, arg_pos, 4);
- x86_push_regp (p, X86_EAX);
- } else {
- int ss = size;
- ss += 3;
- ss &= ~3;
-
- x86_alu_reg_imm (p, X86_SUB, X86_ESP, ss);
- x86_push_imm (p, size);
- x86_push_membase (p, X86_EDX, arg_pos);
- x86_lea_membase (p, X86_EAX, X86_ESP, 2*4);
- x86_push_reg (p, X86_EAX);
- x86_mov_reg_imm (p, X86_EAX, memcpy);
- x86_call_reg (p, X86_EAX);
- x86_alu_reg_imm (p, X86_ADD, X86_ESP, 12);
- /* memcpy might clobber EDX so restore it */
- x86_mov_reg_membase (p, X86_EDX, X86_EBP, ARGP_POS, 4);
- }
- } else {
- /* it's an enum value */
- simpletype = sig->params [i - 1]->data.klass->enum_basetype->type;
- goto enum_marshal;
- }
- break;
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- case MONO_TYPE_R8:
- x86_push_membase (p, X86_EDX, arg_pos + 4);
- x86_push_membase (p, X86_EDX, arg_pos);
- break;
- default:
- g_error ("Can't trampoline 0x%x", sig->params [i - 1]->type);
- }
- }
-
- if (sig->hasthis) {
- if (sig->call_convention != MONO_CALL_THISCALL) {
- x86_mov_reg_membase (p, X86_EDX, X86_EBP, THIS_POS, 4);
- x86_push_reg (p, X86_EDX);
- } else {
- x86_mov_reg_membase (p, X86_ECX, X86_EBP, THIS_POS, 4);
- }
- }
-
- if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) {
- MonoClass *klass = sig->ret->data.klass;
- if (!klass->enumtype) {
- x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
- x86_push_membase (p, X86_ECX, 0);
- }
- }
-
- /*
- * Insert call to function
- */
- x86_mov_reg_membase (p, X86_EDX, X86_EBP, FUNC_ADDR_POS, 4);
- x86_call_reg (p, X86_EDX);
-
- /*
- * Handle retval.
- * Small integer and pointer values are in EAX.
- * Long integers are in EAX:EDX.
- * FP values are on the FP stack.
- */
-
- if (sig->ret->byref || string_ctor) {
- x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
- x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
- } else {
- simpletype = sig->ret->type;
- enum_retvalue:
- switch (simpletype) {
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
- x86_mov_regp_reg (p, X86_ECX, X86_EAX, 1);
- break;
- case MONO_TYPE_CHAR:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
- x86_mov_regp_reg (p, X86_ECX, X86_EAX, 2);
- break;
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_ARRAY:
- x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
- x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
- break;
- case MONO_TYPE_STRING:
- x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
- x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
- break;
- case MONO_TYPE_R4:
- x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
- x86_fst_membase (p, X86_ECX, 0, FALSE, TRUE);
- break;
- case MONO_TYPE_R8:
- x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
- x86_fst_membase (p, X86_ECX, 0, TRUE, TRUE);
- break;
- case MONO_TYPE_I8:
- x86_mov_reg_membase (p, X86_ECX, X86_EBP, RETVAL_POS, 4);
- x86_mov_regp_reg (p, X86_ECX, X86_EAX, 4);
- x86_mov_membase_reg (p, X86_ECX, 4, X86_EDX, 4);
- break;
- case MONO_TYPE_VALUETYPE:
- if (sig->ret->data.klass->enumtype) {
- simpletype = sig->ret->data.klass->enum_basetype->type;
- goto enum_retvalue;
- }
- case MONO_TYPE_VOID:
- break;
- default:
- g_error ("Can't handle as return value 0x%x", sig->ret->type);
- }
- }
-
- /*
- * Standard epilog.
- */
- x86_leave (p);
- x86_ret (p);
-
- g_assert (p - code_buffer < code_size);
- res = (MonoPIFunc)g_memdup (code_buffer, p - code_buffer);
-
- g_hash_table_insert (cache, sig, res);
-
- return res;
-}
-
-#define MINV_POS (- sizeof (MonoInvocation))
-#define STACK_POS (MINV_POS - sizeof (stackval) * sig->param_count)
-#define TYPE_OFFSET (G_STRUCT_OFFSET (stackval, type))
-
-/*
- * Returns a pointer to a native function that can be used to
- * call the specified method.
- * The function created will receive the arguments according
- * to the call convention specified in the method.
- * This function works by creating a MonoInvocation structure,
- * filling the fields in and calling ves_exec_method on it.
- * Still need to figure out how to handle the exception stuff
- * across the managed/unmanaged boundary.
- */
-void *
-mono_arch_create_method_pointer (MonoMethod *method)
-{
- MonoMethodSignature *sig;
- MonoJitInfo *ji;
- unsigned char *p, *code_buffer;
- gint32 local_size;
- gint32 stackval_pos, arg_pos = 8;
- int i, size, align, cpos;
- int *vtbuf;
-
- sig = method->signature;
-
- code_buffer = p = alloca (512); /* FIXME: check for overflows... */
- vtbuf = alloca (sizeof(int)*sig->param_count);
-
- local_size = sizeof (MonoInvocation) + sizeof (stackval) * (sig->param_count + 1);
-
- local_size += 7;
- local_size &= ~7;
-
- stackval_pos = -local_size;
-
- cpos = 0;
- for (i = 0; i < sig->param_count; i++) {
- MonoType *type = sig->params [i];
- vtbuf [i] = -1;
- if (type->type == MONO_TYPE_VALUETYPE) {
- MonoClass *klass = type->data.klass;
- if (klass->enumtype)
- continue;
- size = mono_class_native_size (klass, &align);
- cpos += align - 1;
- cpos &= ~(align - 1);
- vtbuf [i] = cpos;
- cpos += size;
- }
- }
-
- cpos += 7;
- cpos &= ~7;
-
- local_size += cpos;
-
- /*
- * Standard function prolog.
- */
- x86_push_reg (p, X86_EBP);
- x86_mov_reg_reg (p, X86_EBP, X86_ESP, 4);
- x86_alu_reg_imm (p, X86_SUB, X86_ESP, local_size);
-
- /*
- * Initialize MonoInvocation fields, first the ones known now.
- */
- x86_mov_reg_imm (p, X86_EAX, 0);
- x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex)), X86_EAX, 4);
- x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, ex_handler)), X86_EAX, 4);
- x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, parent)), X86_EAX, 4);
- /*
- * Set the method pointer.
- */
- x86_mov_membase_imm (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, method)), (int)method, 4);
-
- if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref && !sig->ret->data.klass->enumtype)
- arg_pos += 4;
-
- /*
- * Handle this.
- */
- if (sig->hasthis) {
- if (sig->call_convention != MONO_CALL_THISCALL) {
- /*
- * Grab it from the stack, otherwise it's already in ECX.
- */
- x86_mov_reg_membase (p, X86_ECX, X86_EBP, arg_pos, 4);
- arg_pos += 4;
- }
- x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, obj)), X86_ECX, 4);
- }
- /*
- * Handle the arguments. stackval_pos is the posset of the stackval array from EBP.
- * arg_pos is the offset from EBP to the incoming arg on the stack.
- * We just call stackval_from_data to handle all the (nasty) issues....
- */
- x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
- x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, stack_args)), X86_EAX, 4);
- for (i = 0; i < sig->param_count; ++i) {
- if (vtbuf [i] >= 0) {
- x86_lea_membase (p, X86_EAX, X86_EBP, - local_size + vtbuf [i]);
- x86_mov_membase_reg (p, X86_EBP, stackval_pos, X86_EAX, 4);
- }
- x86_mov_reg_imm (p, X86_ECX, stackval_from_data);
- x86_lea_membase (p, X86_EDX, X86_EBP, arg_pos);
- x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
- x86_push_imm (p, sig->pinvoke);
- x86_push_reg (p, X86_EDX);
- x86_push_reg (p, X86_EAX);
- x86_push_imm (p, sig->params [i]);
- x86_call_reg (p, X86_ECX);
- x86_alu_reg_imm (p, X86_SUB, X86_ESP, 16);
- stackval_pos += sizeof (stackval);
- /* fixme: alignment */
- if (sig->pinvoke)
- arg_pos += mono_type_native_stack_size (sig->params [i], &align);
- else
- arg_pos += mono_type_stack_size (sig->params [i], &align);
- }
-
- /*
- * Handle the return value storage area.
- */
- x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
- x86_mov_membase_reg (p, X86_EBP, (MINV_POS + G_STRUCT_OFFSET (MonoInvocation, retval)), X86_EAX, 4);
- if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->byref) {
- MonoClass *klass = sig->ret->data.klass;
- if (!klass->enumtype) {
- x86_mov_reg_membase (p, X86_ECX, X86_EBP, 8, 4);
- x86_mov_membase_reg (p, X86_EBP, stackval_pos, X86_ECX, 4);
- }
- }
-
- /*
- * Call the method.
- */
- x86_lea_membase (p, X86_EAX, X86_EBP, MINV_POS);
- x86_push_reg (p, X86_EAX);
- x86_mov_reg_imm (p, X86_EDX, ves_exec_method);
- x86_call_reg (p, X86_EDX);
-
- /*
- * Move the return value to the proper place.
- */
- x86_lea_membase (p, X86_EAX, X86_EBP, stackval_pos);
- if (sig->ret->byref) {
- x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
- } else {
- int simpletype = sig->ret->type;
- enum_retvalue:
- switch (sig->ret->type) {
- case MONO_TYPE_VOID:
- break;
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 1);
- break;
- case MONO_TYPE_CHAR:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 2);
- break;
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_STRING:
- case MONO_TYPE_CLASS:
- x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
- break;
- case MONO_TYPE_I8:
- x86_mov_reg_membase (p, X86_EDX, X86_EAX, 4, 4);
- x86_mov_reg_membase (p, X86_EAX, X86_EAX, 0, 4);
- break;
- case MONO_TYPE_R8:
- x86_fld_membase (p, X86_EAX, 0, TRUE);
- break;
- case MONO_TYPE_VALUETYPE:
- if (sig->ret->data.klass->enumtype) {
- simpletype = sig->ret->data.klass->enum_basetype->type;
- goto enum_retvalue;
- }
-
- x86_push_imm (p, sig->pinvoke);
- x86_push_membase (p, X86_EBP, stackval_pos);
- x86_push_reg (p, X86_EAX);
- x86_push_imm (p, sig->ret);
- x86_mov_reg_imm (p, X86_ECX, stackval_to_data);
- x86_call_reg (p, X86_ECX);
- x86_alu_reg_imm (p, X86_SUB, X86_ESP, 16);
-
- break;
- default:
- g_error ("Type 0x%x not handled yet in thunk creation", sig->ret->type);
- break;
- }
- }
-
- /*
- * Standard epilog.
- */
- x86_leave (p);
- x86_ret (p);
-
- g_assert (p - code_buffer < 512);
-
- ji = g_new0 (MonoJitInfo, 1);
- ji->method = method;
- ji->code_size = p - code_buffer;
- ji->code_start = g_memdup (code_buffer, p - code_buffer);
-
- mono_jit_info_table_add (mono_get_root_domain (), ji);
-
- return ji->code_start;
-}
diff --git a/mono/dis/Makefile.am b/mono/dis/Makefile.am
index fd581ff5514..0a6e86d0c0c 100644
--- a/mono/dis/Makefile.am
+++ b/mono/dis/Makefile.am
@@ -4,7 +4,6 @@ if HOST_WIN32
export HOST_CC
endif
-if JIT_SUPPORTED
if !SHARED_MONO
static_libs= \
$(top_builddir)/mono/metadata/libmonoruntime-static.la \
@@ -17,9 +16,6 @@ runtime_lib=../mini/$(LIBMONO_LA) $(static_libs)
else
runtime_lib=../mini/$(LIBMONO_LA)
endif
-else
-runtime_lib=../interpreter/libmint.la
-endif
if DISABLE_EXECUTABLES
bin_PROGRAMS =
diff --git a/mono/dis/dump.c b/mono/dis/dump.c
index 2b3a4851de0..391ec7fbc77 100755
--- a/mono/dis/dump.c
+++ b/mono/dis/dump.c
@@ -566,6 +566,7 @@ dump_table_method (MonoImage *m)
current_type = 1;
last_m = first_m = 1;
for (i = 1; i <= t->rows; i++){
+ MonoError error;
guint32 cols [MONO_METHOD_SIZE];
char *sig, *impl_flags;
const char *sigblob;
@@ -583,13 +584,17 @@ dump_table_method (MonoImage *m)
mono_metadata_string_heap (m, mono_metadata_decode_row_col (td, current_type - 2, MONO_TYPEDEF_NAME)));
first_m = last_m;
type_container = mono_metadata_load_generic_params (m, MONO_TOKEN_TYPE_DEF | (current_type - 1), NULL);
- if (type_container)
- mono_metadata_load_generic_param_constraints (m, MONO_TOKEN_TYPE_DEF | (current_type - 1), type_container);
+ if (type_container) {
+ mono_metadata_load_generic_param_constraints_checked (m, MONO_TOKEN_TYPE_DEF | (current_type - 1), type_container, &error);
+ g_assert (mono_error_ok (&error)); /*FIXME don't swallow the error message*/
+ }
}
method_container = mono_metadata_load_generic_params (m, MONO_TOKEN_METHOD_DEF | i, type_container);
- if (method_container)
- mono_metadata_load_generic_param_constraints (m, MONO_TOKEN_METHOD_DEF | i, method_container);
+ if (method_container) {
+ mono_metadata_load_generic_param_constraints_checked (m, MONO_TOKEN_METHOD_DEF | i, method_container, &error);
+ g_assert (mono_error_ok (&error)); /*FIXME don't swallow the error message*/
+ }
mono_metadata_decode_table_row (m, MONO_TABLE_METHOD, i - 1, cols, MONO_METHOD_SIZE);
sigblob = mono_metadata_blob_heap (m, cols [MONO_METHOD_SIGNATURE]);
mono_metadata_decode_blob_size (sigblob, &sigblob);
diff --git a/mono/dis/get.c b/mono/dis/get.c
index 34f87b0c8ad..a3f2e7b9cac 100755
--- a/mono/dis/get.c
+++ b/mono/dis/get.c
@@ -889,11 +889,14 @@ dis_stringify_method_signature_full (MonoImage *m, MonoMethodSignature *method,
method_name = mono_metadata_string_heap (m, cols [MONO_METHOD_NAME]);
param_index = cols [MONO_METHOD_PARAMLIST];
if (!method) {
+ MonoError error;
const char *sig = mono_metadata_blob_heap (m, cols [MONO_METHOD_SIGNATURE]);
container = mono_metadata_load_generic_params (m, MONO_TOKEN_METHOD_DEF | methoddef_row, container);
- if (container)
- mono_metadata_load_generic_param_constraints (m, MONO_TOKEN_METHOD_DEF | methoddef_row, container);
+ if (container) {
+ mono_metadata_load_generic_param_constraints_checked (m, MONO_TOKEN_METHOD_DEF | methoddef_row, container, &error);
+ g_assert (mono_error_ok (&error)); /*FIXME don't swallow the error message*/
+ }
mono_metadata_decode_blob_size (sig, &sig);
method = mono_metadata_parse_method_signature_full (m, container, methoddef_row, sig, &sig);
diff --git a/mono/dis/main.c b/mono/dis/main.c
index 42d735b0f75..b56da24c35a 100644
--- a/mono/dis/main.c
+++ b/mono/dis/main.c
@@ -854,10 +854,13 @@ dis_method_list (const char *klass_name, MonoImage *m, guint32 start, guint32 en
mono_metadata_decode_blob_size (sig, &sig);
container = mono_metadata_load_generic_params (m, MONO_TOKEN_METHOD_DEF | (i + 1), type_container);
- if (container)
- mono_metadata_load_generic_param_constraints (m, MONO_TOKEN_METHOD_DEF | (i + 1), container);
- else
+ if (container) {
+ MonoError error;
+ mono_metadata_load_generic_param_constraints_checked (m, MONO_TOKEN_METHOD_DEF | (i + 1), container, &error);
+ g_assert (mono_error_ok (&error)); /*FIXME don't swallow the error message*/
+ } else {
container = type_container;
+ }
ms = mono_metadata_parse_method_signature_full (m, container, i + 1, sig, &sig);
if (ms != NULL){
@@ -1181,8 +1184,11 @@ dis_type (MonoImage *m, int n, int is_nested, int forward)
}
container = mono_metadata_load_generic_params (m, MONO_TOKEN_TYPE_DEF | (n + 1), NULL);
- if (container)
- mono_metadata_load_generic_param_constraints (m, MONO_TOKEN_TYPE_DEF | (n + 1), container);
+ if (container) {
+ MonoError error;
+ mono_metadata_load_generic_param_constraints_checked (m, MONO_TOKEN_TYPE_DEF | (n + 1), container, &error);
+ g_assert (mono_error_ok (&error)); /*FIXME don't swallow the error message*/
+ }
esname = get_escaped_name (name);
if ((cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_CLASS_SEMANTIC_MASK) == TYPE_ATTRIBUTE_CLASS){
diff --git a/mono/io-layer/handles.c b/mono/io-layer/handles.c
index 8cd74e9ff36..5e706fb7280 100644
--- a/mono/io-layer/handles.c
+++ b/mono/io-layer/handles.c
@@ -29,6 +29,9 @@
# include
#endif
#include
+#ifdef HAVE_SYS_RESOURCE_H
+# include
+#endif
#include
#include
@@ -213,6 +216,21 @@ static void handle_cleanup (void)
g_free (_wapi_private_handles [i]);
}
+int
+wapi_getdtablesize (void)
+{
+#ifdef HAVE_GETRLIMIT
+ struct rlimit limit;
+ int res;
+
+ res = getrlimit (RLIMIT_NOFILE, &limit);
+ g_assert (res == 0);
+ return limit.rlim_cur;
+#else
+ return getdtablesize ();
+#endif
+}
+
/*
* wapi_init:
*
@@ -223,8 +241,8 @@ wapi_init (void)
{
g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
== WAPI_HANDLE_COUNT);
-
- _wapi_fd_reserve = getdtablesize();
+
+ _wapi_fd_reserve = wapi_getdtablesize ();
/* This is needed by the code in _wapi_handle_new_internal */
_wapi_fd_reserve = (_wapi_fd_reserve + (_WAPI_HANDLE_INITIAL_COUNT - 1)) & ~(_WAPI_HANDLE_INITIAL_COUNT - 1);
@@ -266,6 +284,7 @@ wapi_init (void)
_wapi_global_signal_cond = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_cond;
_wapi_global_signal_mutex = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_mutex;
+ wapi_processes_init ();
/* Using g_atexit here instead of an explicit function call in
* a cleanup routine lets us cope when a third-party library
@@ -1841,65 +1860,6 @@ void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
}
}
- for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
- struct _WapiHandleShared *shared;
- struct _WapiHandle_process *process_handle;
-
- shared = &_wapi_shared_layout->handles[i];
-
- if (shared->type == WAPI_HANDLE_PROCESS) {
- DIR *fd_dir;
- struct dirent *fd_entry;
- char subdir[_POSIX_PATH_MAX];
-
- process_handle = &shared->u.process;
- pid = process_handle->id;
-
- /* Look in /proc//fd/ but ignore
- * /proc//fd/, as we have the
- * file open too
- */
- g_snprintf (subdir, _POSIX_PATH_MAX, "/proc/%d/fd",
- pid);
-
- fd_dir = opendir (subdir);
- if (fd_dir == NULL) {
- continue;
- }
-
- DEBUG ("%s: Looking in %s", __func__, subdir);
-
- proc_fds = TRUE;
-
- while ((fd_entry = readdir (fd_dir)) != NULL) {
- char path[_POSIX_PATH_MAX];
- struct stat link_stat;
-
- if (!strcmp (fd_entry->d_name, ".") ||
- !strcmp (fd_entry->d_name, "..") ||
- (pid == self &&
- fd == atoi (fd_entry->d_name))) {
- continue;
- }
-
- g_snprintf (path, _POSIX_PATH_MAX,
- "/proc/%d/fd/%s", pid,
- fd_entry->d_name);
-
- stat (path, &link_stat);
- if (link_stat.st_dev == share_info->device &&
- link_stat.st_ino == share_info->inode) {
- DEBUG ("%s: Found it at %s",
- __func__, path);
-
- found = TRUE;
- }
- }
-
- closedir (fd_dir);
- }
- }
-
if (proc_fds == FALSE) {
_wapi_handle_check_share_by_pid (share_info);
} else if (found == FALSE) {
diff --git a/mono/io-layer/handles.h b/mono/io-layer/handles.h
index 04444d0ae82..31cab7bdb94 100644
--- a/mono/io-layer/handles.h
+++ b/mono/io-layer/handles.h
@@ -20,6 +20,8 @@ extern gboolean DuplicateHandle (gpointer srcprocess, gpointer src, gpointer tar
extern void wapi_init (void);
extern void wapi_cleanup (void);
+int wapi_getdtablesize (void);
+
G_END_DECLS
#endif /* _WAPI_HANDLES_H_ */
diff --git a/mono/io-layer/io-layer.h b/mono/io-layer/io-layer.h
index 394799bc86c..6b21f056ca2 100755
--- a/mono/io-layer/io-layer.h
+++ b/mono/io-layer/io-layer.h
@@ -21,9 +21,9 @@
* Declare as __GetProcessId for unsupported targets. */
#define GetProcessId __GetProcessId
#endif
-#include
#include
#include
+#include
/*
* The mingw version says:
* /usr/i686-pc-mingw32/sys-root/mingw/include/ws2tcpip.h:38:2: error: #error "ws2tcpip.h is not compatible with winsock.h. Include winsock2.h instead."
diff --git a/mono/io-layer/io.c b/mono/io-layer/io.c
index 169cb07617a..03672d4197e 100644
--- a/mono/io-layer/io.c
+++ b/mono/io-layer/io.c
@@ -3904,7 +3904,7 @@ GetLogicalDriveStrings_Mtab (guint32 len, gunichar2 *buf)
}
#endif
-#if (defined(HAVE_STATVFS) || defined(HAVE_STATFS)) && !defined(PLATFORM_ANDROID)
+#if defined(HAVE_STATVFS) || defined(HAVE_STATFS)
gboolean GetDiskFreeSpaceEx(const gunichar2 *path_name, WapiULargeInteger *free_bytes_avail,
WapiULargeInteger *total_number_of_bytes,
WapiULargeInteger *total_number_of_free_bytes)
@@ -3943,7 +3943,11 @@ gboolean GetDiskFreeSpaceEx(const gunichar2 *path_name, WapiULargeInteger *free_
block_size = fsstat.f_frsize;
#elif defined(HAVE_STATFS)
ret = statfs (utf8_path_name, &fsstat);
+#if defined (MNT_RDONLY)
isreadonly = ((fsstat.f_flags & MNT_RDONLY) == MNT_RDONLY);
+#elif defined (MS_RDONLY)
+ isreadonly = ((fsstat.f_flags & MS_RDONLY) == MS_RDONLY);
+#endif
block_size = fsstat.f_bsize;
#endif
} while(ret == -1 && errno == EINTR);
diff --git a/mono/io-layer/process-private.h b/mono/io-layer/process-private.h
index c3e6988732d..1da7f472f00 100644
--- a/mono/io-layer/process-private.h
+++ b/mono/io-layer/process-private.h
@@ -16,18 +16,24 @@
/* There doesn't seem to be a defined symbol for this */
#define _WAPI_PROCESS_CURRENT (gpointer)0xFFFFFFFF
+/*
+ * Handles > _WAPI_PROCESS_UNHANDLED are pseudo handles which represent processes
+ * not started by the runtime.
+ */
/* This marks a system process that we don't have a handle on */
/* FIXME: Cope with PIDs > sizeof guint */
#define _WAPI_PROCESS_UNHANDLED (1 << (8*sizeof(pid_t)-1))
#define _WAPI_PROCESS_UNHANDLED_PID_MASK (-1 & ~_WAPI_PROCESS_UNHANDLED)
+#define WAPI_IS_PSEUDO_PROCESS_HANDLE(handle) ((GPOINTER_TO_UINT(handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED)
+#define WAPI_PID_TO_HANDLE(pid) GINT_TO_POINTER (_WAPI_PROCESS_UNHANDLED + (pid))
+#define WAPI_HANDLE_TO_PID(handle) (GPOINTER_TO_UINT ((handle)) - _WAPI_PROCESS_UNHANDLED)
+void wapi_processes_init (void);
extern gpointer _wapi_process_duplicate (void);
extern void wapi_processes_cleanup (void);
extern struct _WapiHandleOps _wapi_process_ops;
-#define _WAPI_PROC_NAME_MAX_LEN _POSIX_PATH_MAX
-
/*
* MonoProcess describes processes we create.
* It contains a semaphore that can be waited on in order to wait
@@ -42,8 +48,7 @@ struct MonoProcess {
gint32 handle_count; /* the number of handles to this mono_process instance */
/* we keep a ref to the creating _WapiHandle_process handle until
* the process has exited, so that the information there isn't lost.
- * If we put the information there in this structure, it won't be
- * available to other processes when using shared handles. */
+ */
gpointer handle;
struct MonoProcess *next;
};
@@ -52,8 +57,6 @@ struct MonoProcess {
/*
* _WapiHandle_process is a structure containing all the required information
* for process handling.
- * The mono_process field is only present if this process has created
- * the corresponding process.
*/
struct _WapiHandle_process
{
@@ -62,12 +65,13 @@ struct _WapiHandle_process
gpointer main_thread;
WapiFileTime create_time;
WapiFileTime exit_time;
- gchar proc_name[_WAPI_PROC_NAME_MAX_LEN];
+ char *proc_name;
size_t min_working_set;
size_t max_working_set;
gboolean exited;
- pid_t self; /* mono_process is shared among processes, but only usable in the process that created it */
struct MonoProcess *mono_process;
};
+typedef struct _WapiHandle_process WapiHandle_process;
+
#endif /* _WAPI_PROCESS_PRIVATE_H_ */
diff --git a/mono/io-layer/processes.c b/mono/io-layer/processes.c
index c65bf23813c..3c0531f3de0 100644
--- a/mono/io-layer/processes.c
+++ b/mono/io-layer/processes.c
@@ -86,7 +86,7 @@
* arm-apple-darwin9. We'll manually define the symbol on Apple as it does
* in fact exist on all implementations (so far)
*/
-gchar ***_NSGetEnviron(void);
+char ***_NSGetEnviron(void);
#define environ (*_NSGetEnviron())
#else
extern char **environ;
@@ -142,22 +142,25 @@ static volatile gint32 mono_processes_cleaning_up = 0;
static mono_mutex_t mono_processes_mutex;
static void mono_processes_cleanup (void);
-static mono_once_t process_current_once=MONO_ONCE_INIT;
-static gpointer current_process=NULL;
+static gpointer current_process;
static char *cli_launcher;
-static mono_once_t process_ops_once=MONO_ONCE_INIT;
-
-static void process_ops_init (void)
+static WapiHandle_process *
+lookup_process_handle (gpointer handle)
{
- _wapi_handle_register_capabilities (WAPI_HANDLE_PROCESS,
- WAPI_HANDLE_CAP_WAIT |
- WAPI_HANDLE_CAP_SPECIAL_WAIT);
-}
+ WapiHandle_process *process_data;
+ gboolean ret;
+ ret = _wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS,
+ (gpointer *)&process_data);
+ if (!ret)
+ return NULL;
+ return process_data;
+}
/* Check if a pid is valid - i.e. if a process exists with this pid. */
-static gboolean is_pid_valid (pid_t pid)
+static gboolean
+is_pid_valid (pid_t pid)
{
gboolean result = FALSE;
@@ -169,7 +172,7 @@ static gboolean is_pid_valid (pid_t pid)
if (get_team_info ((team_id)pid, &teamInfo) == B_OK)
result = TRUE;
#else
- gchar *dir = g_strdup_printf ("/proc/%d", pid);
+ char *dir = g_strdup_printf ("/proc/%d", pid);
if (!access (dir, F_OK))
result = TRUE;
g_free (dir);
@@ -178,7 +181,8 @@ static gboolean is_pid_valid (pid_t pid)
return result;
}
-static void process_set_defaults (struct _WapiHandle_process *process_handle)
+static void
+process_set_defaults (WapiHandle_process *process_handle)
{
/* These seem to be the defaults on w2k */
process_handle->min_working_set = 204800;
@@ -233,42 +237,6 @@ utf16_concat (const gunichar2 *first, ...)
return ret;
}
-#ifdef PLATFORM_MACOSX
-
-/* 0 = no detection; -1 = not 10.5 or higher; 1 = 10.5 or higher */
-static int osx_10_5_or_higher;
-
-static void
-detect_osx_10_5_or_higher (void)
-{
- struct utsname u;
- char *p;
- int v;
-
- if (uname (&u) != 0){
- osx_10_5_or_higher = 1;
- return;
- }
-
- p = u.release;
- v = atoi (p);
-
- if (v < 9)
- osx_10_5_or_higher = -1;
- else
- osx_10_5_or_higher = 1;
-}
-
-static gboolean
-is_macos_10_5_or_higher (void)
-{
- if (osx_10_5_or_higher == 0)
- detect_osx_10_5_or_higher ();
-
- return (osx_10_5_or_higher == 1);
-}
-#endif
-
static const gunichar2 utf16_space_bytes [2] = { 0x20, 0 };
static const gunichar2 *utf16_space = utf16_space_bytes;
static const gunichar2 utf16_quote_bytes [2] = { 0x22, 0 };
@@ -279,7 +247,7 @@ static const gunichar2 *utf16_quote = utf16_quote_bytes;
void
print_utf16 (gunichar2 *str)
{
- gchar *res;
+ char *res;
res = g_utf16_to_utf8 (str, -1, NULL, NULL, NULL);
g_print ("%s\n", res);
@@ -288,7 +256,8 @@ print_utf16 (gunichar2 *str)
#endif
/* Implemented as just a wrapper around CreateProcess () */
-gboolean ShellExecuteEx (WapiShellExecuteInfo *sei)
+gboolean
+ShellExecuteEx (WapiShellExecuteInfo *sei)
{
gboolean ret;
WapiProcessInformation process_info;
@@ -299,13 +268,12 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei)
* that
*/
SetLastError (ERROR_INVALID_PARAMETER);
- return (FALSE);
+ return FALSE;
}
- if (sei->lpFile == NULL) {
+ if (sei->lpFile == NULL)
/* w2k returns TRUE for this, for some reason. */
- return (TRUE);
- }
+ return TRUE;
/* Put both executable and parameters into the second argument
* to CreateProcess (), so it searches $PATH. The conversion
@@ -313,9 +281,9 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei)
* g_strdup_printf () equivalent for gunichar2 :-(
*/
args = utf16_concat (utf16_quote, sei->lpFile, utf16_quote, sei->lpParameters == NULL ? NULL : utf16_space, sei->lpParameters, NULL);
- if (args == NULL){
+ if (args == NULL) {
SetLastError (ERROR_INVALID_DATA);
- return (FALSE);
+ return FALSE;
}
ret = CreateProcess (NULL, args, NULL, NULL, TRUE,
CREATE_UNICODE_ENVIRONMENT, NULL,
@@ -346,7 +314,7 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei)
handler = g_find_program_in_path ("kfmclient");
if (handler == NULL){
handler_utf16 = (gunichar2 *) -1;
- return (FALSE);
+ return FALSE;
} else {
/* kfmclient needs exec argument */
char *old = handler;
@@ -370,7 +338,7 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei)
sei->lpFile, utf16_quote,
sei->lpParameters == NULL ? NULL : utf16_space,
sei->lpParameters, NULL);
- if (args == NULL){
+ if (args == NULL) {
SetLastError (ERROR_INVALID_DATA);
return FALSE;
}
@@ -378,7 +346,7 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei)
CREATE_UNICODE_ENVIRONMENT, NULL,
sei->lpDirectory, NULL, &process_info);
g_free (args);
- if (!ret){
+ if (!ret) {
if (GetLastError () != ERROR_OUTOFMEMORY)
SetLastError (ERROR_INVALID_DATA);
return FALSE;
@@ -388,17 +356,16 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei)
process_info.hProcess = NULL;
}
- if (sei->fMask & SEE_MASK_NOCLOSEPROCESS) {
+ if (sei->fMask & SEE_MASK_NOCLOSEPROCESS)
sei->hProcess = process_info.hProcess;
- } else {
+ else
CloseHandle (process_info.hProcess);
- }
- return (ret);
+ return ret;
}
static gboolean
-is_managed_binary (const gchar *filename)
+is_managed_binary (const char *filename)
{
int original_errno = errno;
#if defined(HAVE_LARGE_FILE_SUPPORT) && defined(O_LARGEFILE)
@@ -505,17 +472,18 @@ is_managed_binary (const gchar *filename)
return managed;
}
-gboolean CreateProcessWithLogonW (const gunichar2 *username,
- const gunichar2 *domain,
- const gunichar2 *password,
- const guint32 logonFlags,
- const gunichar2 *appname,
- const gunichar2 *cmdline,
- guint32 create_flags,
- gpointer env,
- const gunichar2 *cwd,
- WapiStartupInfo *startup,
- WapiProcessInformation *process_info)
+gboolean
+CreateProcessWithLogonW (const gunichar2 *username,
+ const gunichar2 *domain,
+ const gunichar2 *password,
+ const guint32 logonFlags,
+ const gunichar2 *appname,
+ const gunichar2 *cmdline,
+ guint32 create_flags,
+ gpointer env,
+ const gunichar2 *cwd,
+ WapiStartupInfo *startup,
+ WapiProcessInformation *process_info)
{
/* FIXME: use user information */
return CreateProcess (appname, cmdline, NULL, NULL, FALSE, create_flags, env, cwd, startup, process_info);
@@ -535,17 +503,15 @@ is_executable (const char *prog)
}
static void
-switchDirectorySeparators(gchar *path)
+switch_dir_separators (char *path)
{
size_t i, pathLength = strlen(path);
/* Turn all the slashes round the right way, except for \' */
/* There are probably other characters that need to be excluded as well. */
- for (i = 0; i < pathLength; i++)
- {
- if (path[i] == '\\' && i < pathLength - 1 && path[i+1] != '\'' ) {
+ for (i = 0; i < pathLength; i++) {
+ if (path[i] == '\\' && i < pathLength - 1 && path[i+1] != '\'' )
path[i] = '/';
- }
}
}
@@ -557,11 +523,12 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline,
WapiStartupInfo *startup,
WapiProcessInformation *process_info)
{
- gchar *cmd=NULL, *prog = NULL, *full_prog = NULL, *args = NULL, *args_after_prog = NULL, *dir = NULL, **env_strings = NULL, **argv = NULL;
+ char *cmd = NULL, *prog = NULL, *full_prog = NULL, *args = NULL, *args_after_prog = NULL;
+ char *dir = NULL, **env_strings = NULL, **argv = NULL;
guint32 i, env_count = 0;
gboolean ret = FALSE;
gpointer handle;
- struct _WapiHandle_process process_handle = {0}, *process_handle_data;
+ WapiHandle_process process_handle = {0}, *process_handle_data;
GError *gerr = NULL;
int in_fd, out_fd, err_fd;
pid_t pid;
@@ -570,10 +537,9 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline,
int dummy;
struct MonoProcess *mono_process;
gboolean fork_failed = FALSE;
-
- mono_once (&process_ops_once, process_ops_init);
+
mono_once (&process_sig_chld_once, process_add_sigchld_handler);
-
+
/* appname and cmdline specify the executable and its args:
*
* If appname is not NULL, it is the name of the executable.
@@ -610,7 +576,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline,
goto free_strings;
}
- switchDirectorySeparators(cmd);
+ switch_dir_separators(cmd);
}
if (cmdline != NULL) {
@@ -633,13 +599,13 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline,
}
/* Turn all the slashes round the right way */
- switchDirectorySeparators(dir);
+ switch_dir_separators(dir);
}
/* We can't put off locating the executable any longer :-( */
if (cmd != NULL) {
- gchar *unquoted;
+ char *unquoted;
if (g_ascii_isalpha (cmd[0]) && (cmd[1] == ':')) {
/* Strip off the drive letter. I can't
* believe that CP/M holdover is still
@@ -684,7 +650,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline,
args_after_prog = args;
} else {
- gchar *token = NULL;
+ char *token = NULL;
char quote;
/* Dig out the first token from args, taking quotation
@@ -747,7 +713,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline,
/* Turn all the slashes round the right way. Only for
* the prg. name
*/
- switchDirectorySeparators(token);
+ switch_dir_separators(token);
if (g_ascii_isalpha (token[0]) && (token[1] == ':')) {
/* Strip off the drive letter. I can't
@@ -770,7 +736,6 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline,
SetLastError (ERROR_FILE_NOT_FOUND);
goto free_strings;
}
-
} else {
char *curdir = g_get_current_dir ();
@@ -846,7 +811,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline,
}
if (args_after_prog != NULL && *args_after_prog) {
- gchar *qprog;
+ char *qprog;
qprog = g_shell_quote (prog);
full_prog = g_strconcat (qprog, " ", args_after_prog, NULL);
@@ -873,8 +838,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline,
err_fd = GPOINTER_TO_UINT (GetStdHandle (STD_ERROR_HANDLE));
}
- g_strlcpy (process_handle.proc_name, prog,
- _WAPI_PROC_NAME_MAX_LEN - 1);
+ process_handle.proc_name = g_strdup (prog);
process_set_defaults (&process_handle);
@@ -895,7 +859,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline,
* environment variables in the new process. Otherwise the
* new process inherits the same environment.
*/
- if (new_environ != NULL) {
+ if (new_environ) {
gunichar2 *new_environp;
/* Count the number of strings */
@@ -910,7 +874,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline,
/* +2: one for the process handle value, and the last
* one is NULL
*/
- env_strings = g_new0 (gchar *, env_count + 2);
+ env_strings = g_new0 (char *, env_count + 2);
/* Copy each environ string into 'strings' turning it
* into utf8 (or the requested encoding) at the same
@@ -926,14 +890,13 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline,
}
}
} else {
- for (i = 0; environ[i] != NULL; i++) {
+ for (i = 0; environ[i] != NULL; i++)
env_count++;
- }
/* +2: one for the process handle value, and the last
* one is NULL
*/
- env_strings = g_new0 (gchar *, env_count + 2);
+ env_strings = g_new0 (char *, env_count + 2);
/* Copy each environ string into 'strings' turning it
* into utf8 (or the requested encoding) at the same
@@ -945,18 +908,6 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline,
env_count++;
}
}
- /* pass process handle info to the child, so it doesn't have
- * to do an expensive search over the whole list
- */
- if (env_strings != NULL) {
- struct _WapiHandleUnshared *handle_data;
- struct _WapiHandle_shared_ref *ref;
-
- handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(handle));
- ref = &handle_data->u.shared;
-
- env_strings[env_count] = g_strdup_printf ("_WAPI_PROCESS_HANDLE_OFFSET=%d", ref->offset);
- }
/* Create a pipe to make sure the child doesn't exit before
* we can add the process to the linked list of mono_processes */
@@ -1000,20 +951,17 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline,
}
/* Close all file descriptors */
- for (i = getdtablesize () - 1; i > 2; i--) {
+ for (i = wapi_getdtablesize () - 1; i > 2; i--)
close (i);
- }
#ifdef DEBUG_ENABLED
DEBUG ("%s: exec()ing [%s] in dir [%s]", __func__, cmd,
- dir==NULL?".":dir);
- for (i = 0; argv[i] != NULL; i++) {
+ dir == NULL?".":dir);
+ for (i = 0; argv[i] != NULL; i++)
g_message ("arg %d: [%s]", i, argv[i]);
- }
- for (i = 0; env_strings[i] != NULL; i++) {
+ for (i = 0; env_strings[i] != NULL; i++)
g_message ("env %d: [%s]", i, env_strings[i]);
- }
#endif
/* set cwd */
@@ -1030,9 +978,8 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline,
}
/* parent */
- ret = _wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS,
- (gpointer *)&process_handle_data);
- if (ret == FALSE) {
+ process_handle_data = lookup_process_handle (handle);
+ if (!process_handle_data) {
g_warning ("%s: error looking up process handle %p", __func__,
handle);
_wapi_handle_unref (handle);
@@ -1057,7 +1004,6 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline,
_wapi_handle_ref (handle);
mono_process->handle = handle;
- process_handle_data->self = _wapi_getpid ();
process_handle_data->mono_process = mono_process;
mono_mutex_lock (&mono_processes_mutex);
@@ -1091,27 +1037,20 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline,
}
free_strings:
- if (cmd != NULL) {
+ if (cmd)
g_free (cmd);
- }
- if (full_prog != NULL) {
+ if (full_prog)
g_free (full_prog);
- }
- if (prog != NULL) {
+ if (prog)
g_free (prog);
- }
- if (args != NULL) {
+ if (args)
g_free (args);
- }
- if (dir != NULL) {
+ if (dir)
g_free (dir);
- }
- if(env_strings != NULL) {
+ if (env_strings)
g_strfreev (env_strings);
- }
- if (argv != NULL) {
+ if (argv)
g_strfreev (argv);
- }
DEBUG ("%s: returning handle %p for pid %d", __func__, handle,
pid);
@@ -1119,98 +1058,39 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline,
/* Check if something needs to be cleaned up. */
mono_processes_cleanup ();
- return(ret);
+ return ret;
}
-static void process_set_name (struct _WapiHandle_process *process_handle)
+static void
+process_set_name (WapiHandle_process *process_handle)
{
- gchar *progname, *utf8_progname, *slash;
+ char *progname, *utf8_progname, *slash;
- progname=g_get_prgname ();
- utf8_progname=mono_utf8_from_external (progname);
+ progname = g_get_prgname ();
+ utf8_progname = mono_utf8_from_external (progname);
DEBUG ("%s: using [%s] as prog name", __func__, progname);
- if(utf8_progname!=NULL) {
- slash=strrchr (utf8_progname, '/');
- if(slash!=NULL) {
- g_strlcpy (process_handle->proc_name, slash+1,
- _WAPI_PROC_NAME_MAX_LEN - 1);
- } else {
- g_strlcpy (process_handle->proc_name, utf8_progname,
- _WAPI_PROC_NAME_MAX_LEN - 1);
- }
-
+ if (utf8_progname) {
+ slash = strrchr (utf8_progname, '/');
+ if (slash)
+ process_handle->proc_name = g_strdup (slash+1);
+ else
+ process_handle->proc_name = g_strdup (utf8_progname);
g_free (utf8_progname);
}
}
-extern void _wapi_time_t_to_filetime (time_t timeval, WapiFileTime *filetime);
-
-#if !GLIB_CHECK_VERSION (2,4,0)
-#define g_setenv(a,b,c) setenv(a,b,c)
-#define g_unsetenv(a) unsetenv(a)
-#endif
-
-static void process_set_current (void)
+void
+wapi_processes_init (void)
{
pid_t pid = _wapi_getpid ();
- const char *handle_env;
- struct _WapiHandle_process process_handle = {0};
-
- mono_once (&process_ops_once, process_ops_init);
-
- handle_env = g_getenv ("_WAPI_PROCESS_HANDLE_OFFSET");
- g_unsetenv ("_WAPI_PROCESS_HANDLE_OFFSET");
-
- if (handle_env != NULL) {
- struct _WapiHandle_process *process_handlep;
- gchar *procname = NULL;
- gboolean ok;
-
- current_process = _wapi_handle_new_from_offset (WAPI_HANDLE_PROCESS, atoi (handle_env), TRUE);
-
- DEBUG ("%s: Found my process handle: %p (offset %d 0x%x)",
- __func__, current_process, atoi (handle_env),
- atoi (handle_env));
-
- ok = _wapi_lookup_handle (current_process, WAPI_HANDLE_PROCESS,
- (gpointer *)&process_handlep);
- if (ok) {
- /* This test will probably break on linuxthreads, but
- * that should be ancient history on all distros we
- * care about by now
- */
- if (process_handlep->id == pid) {
- procname = process_handlep->proc_name;
- if (!strcmp (procname, "mono")) {
- /* Set a better process name */
- DEBUG ("%s: Setting better process name", __func__);
-
- process_set_name (process_handlep);
- } else {
- DEBUG ("%s: Leaving process name: %s", __func__, procname);
- }
-
- return;
- }
-
- /* Wrong pid, so drop this handle and fall through to
- * create a new one
- */
- _wapi_handle_unref (current_process);
- }
- }
-
- /* We get here if the handle wasn't specified in the
- * environment, or if the process ID was wrong, or if the
- * handle lookup failed (eg if the parent process forked and
- * quit immediately, and deleted the shared data before the
- * child got a chance to attach it.)
- */
-
- DEBUG ("%s: Need to create my own process handle", __func__);
+ WapiHandle_process process_handle = {0};
+ _wapi_handle_register_capabilities (WAPI_HANDLE_PROCESS,
+ WAPI_HANDLE_CAP_WAIT |
+ WAPI_HANDLE_CAP_SPECIAL_WAIT);
+
process_handle.id = pid;
process_set_defaults (&process_handle);
@@ -1218,273 +1098,60 @@ static void process_set_current (void)
current_process = _wapi_handle_new (WAPI_HANDLE_PROCESS,
&process_handle);
- if (current_process == _WAPI_HANDLE_INVALID) {
- g_warning ("%s: error creating process handle", __func__);
- return;
- }
+ g_assert (current_process);
}
-gpointer _wapi_process_duplicate ()
+gpointer
+_wapi_process_duplicate (void)
{
- mono_once (&process_current_once, process_set_current);
-
_wapi_handle_ref (current_process);
- return(current_process);
+ return current_process;
}
/* Returns a pseudo handle that doesn't need to be closed afterwards */
-gpointer GetCurrentProcess (void)
+gpointer
+GetCurrentProcess (void)
{
- mono_once (&process_current_once, process_set_current);
-
- return(_WAPI_PROCESS_CURRENT);
+ return _WAPI_PROCESS_CURRENT;
}
-guint32 GetProcessId (gpointer handle)
+guint32
+GetProcessId (gpointer handle)
{
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
- if ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle))
/* This is a pseudo handle */
- return(GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED_PID_MASK);
- }
+ return WAPI_HANDLE_TO_PID (handle);
- ok = _wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS,
- (gpointer *)&process_handle);
- if (ok == FALSE) {
+ process_handle = lookup_process_handle (handle);
+ if (!process_handle) {
SetLastError (ERROR_INVALID_HANDLE);
- return (0);
+ return 0;
}
- return (process_handle->id);
+ return process_handle->id;
}
-guint32 GetCurrentProcessId (void)
+static gboolean
+process_open_compare (gpointer handle, gpointer user_data)
{
- mono_once (&process_current_once, process_set_current);
-
- return (GetProcessId (current_process));
-}
+ pid_t wanted_pid;
+ WapiHandle_process *process_handle;
+ pid_t checking_pid;
-/* Returns the process id as a convenience to the functions that call this */
-static pid_t signal_process_if_gone (gpointer handle)
-{
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ g_assert (!WAPI_IS_PSEUDO_PROCESS_HANDLE (handle));
- g_assert ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) != _WAPI_PROCESS_UNHANDLED);
-
- /* Make sure the process is signalled if it has exited - if
- * the parent process didn't wait for it then it won't be
- */
- ok = _wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS,
- (gpointer *)&process_handle);
- if (ok == FALSE) {
- /* It's possible that the handle has vanished during
- * the _wapi_search_handle before it gets here, so
- * don't spam the console with warnings.
- */
-/* g_warning ("%s: error looking up process handle %p",
- __func__, handle);*/
-
- return (0);
- }
+ process_handle = lookup_process_handle (handle);
+ g_assert (process_handle);
DEBUG ("%s: looking at process %d", __func__, process_handle->id);
- if (kill (process_handle->id, 0) == -1 &&
- (errno == ESRCH ||
- errno == EPERM)) {
- /* The process is dead, (EPERM tells us a new process
- * has that ID, but as it's owned by someone else it
- * can't be the one listed in our shared memory file)
- */
- _wapi_shared_handle_set_signal_state (handle, TRUE);
- }
-
- return (process_handle->id);
-}
-
-#ifdef UNUSED_CODE
-static gboolean process_enum (gpointer handle, gpointer user_data)
-{
- GArray *processes=user_data;
- pid_t pid = signal_process_if_gone (handle);
- int i;
-
- if (pid == 0) {
- return (FALSE);
- }
-
- /* Ignore processes that have already exited (ie they are signalled) */
- if (_wapi_handle_issignalled (handle) == FALSE) {
- DEBUG ("%s: process %d added to array", __func__, pid);
-
- /* This ensures that duplicates aren't returned (see
- * the comment above _wapi_search_handle () for why
- * it's needed
- */
- for (i = 0; i < processes->len; i++) {
- if (g_array_index (processes, pid_t, i) == pid) {
- /* We've already got this one, return
- * FALSE to keep searching
- */
- return (FALSE);
- }
- }
-
- g_array_append_val (processes, pid);
- }
-
- /* Return false to keep searching */
- return(FALSE);
-}
-#endif /* UNUSED_CODE */
-
-#if defined(PLATFORM_MACOSX) || defined(__OpenBSD__)
-
-gboolean EnumProcesses (guint32 *pids, guint32 len, guint32 *needed)
-{
- guint32 count, fit, i, j;
- gint32 err;
- gboolean done;
- size_t proclength, size;
-#if defined(__OpenBSD__)
- struct kinfo_proc *result;
- int name[6];
- name[0] = CTL_KERN;
- name[1] = KERN_PROC;
- name[2] = KERN_PROC_ALL;
- name[3] = 0;
- name[4] = sizeof(struct kinfo_proc);
- name[5] = 0;
-#else
- struct kinfo_proc *result;
- static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
-#endif
-
- mono_once (&process_current_once, process_set_current);
-
- result = NULL;
- done = FALSE;
-
- do {
- proclength = 0;
-#if defined(__OpenBSD__)
- size = (sizeof(name) / sizeof(*name));
-#else
- size = (sizeof(name) / sizeof(*name)) - 1;
-#endif
- err = sysctl ((int *)name, size, NULL, &proclength, NULL, 0);
-
- if (err == 0) {
- result = malloc (proclength);
-
- if (result == NULL)
- return FALSE;
+ checking_pid = process_handle->id;
-#if defined(__OpenBSD__)
- name[5] = (int)(proclength / sizeof(struct kinfo_proc));
-#endif
-
- err = sysctl ((int *) name, size, result, &proclength, NULL, 0);
-
- if (err == 0)
- done = TRUE;
- else {
- free (result);
- result = NULL;
- }
- }
- } while (err == 0 && !done);
-
- if (err != 0) {
- if (result != NULL) {
- free (result);
- result = NULL;
- }
- return(FALSE);
- }
-
- count = proclength / sizeof(struct kinfo_proc);
-
- fit = len / sizeof(guint32);
- for (i = 0, j = 0; j< fit && i < count; i++) {
-#if defined(__OpenBSD__)
- pids [j++] = result [i].p_pid;
-#else
- if (result[i].kp_proc.p_pid > 0) /* Pid 0 not supported */
- pids [j++] = result [i].kp_proc.p_pid;
-#endif
- }
- free (result);
- result = NULL;
- *needed = j * sizeof(guint32);
-
- return(TRUE);
-}
-#elif defined(__HAIKU__)
-
-gboolean EnumProcesses (guint32 *pids, guint32 len, guint32 *needed)
-{
- guint32 fit, i = 0;
- int32 cookie = 0;
- team_info teamInfo;
-
- mono_once (&process_current_once, process_set_current);
-
- fit = len / sizeof (guint32);
- while (get_next_team_info (&cookie, &teamInfo) == B_OK && i < fit) {
- pids [i++] = teamInfo.team;
- }
- *needed = i * sizeof (guint32);
-
- return TRUE;
-}
-#else
-gboolean EnumProcesses (guint32 *pids, guint32 len, guint32 *needed)
-{
- guint32 fit, i;
- DIR *dir;
- struct dirent *entry;
-
- mono_once (&process_current_once, process_set_current);
-
- dir = opendir ("/proc");
- if (dir == NULL) {
- return(FALSE);
- }
-
- i = 0;
- fit = len / sizeof (guint32);
- while(i < fit && (entry = readdir (dir)) != NULL) {
- pid_t pid;
- char *endptr;
-
- if (!isdigit (entry->d_name[0]))
- continue;
-
- pid = (pid_t) strtol (entry->d_name, &endptr, 10);
- if (*endptr == '\0')
- pids [i++] = (guint32) pid;
- }
- closedir (dir);
- *needed = i * sizeof(guint32);
-
- return(TRUE);
-}
-#endif
-
-static gboolean process_open_compare (gpointer handle, gpointer user_data)
-{
- pid_t wanted_pid;
- pid_t checking_pid = signal_process_if_gone (handle);
-
- if (checking_pid == 0) {
- return(FALSE);
- }
+ if (checking_pid == 0)
+ return FALSE;
wanted_pid = GPOINTER_TO_UINT (user_data);
@@ -1493,37 +1160,34 @@ static gboolean process_open_compare (gpointer handle, gpointer user_data)
* unsignalled
*/
if (checking_pid == wanted_pid &&
- _wapi_handle_issignalled (handle) == FALSE) {
+ !_wapi_handle_issignalled (handle)) {
/* If the handle is blown away in the window between
* returning TRUE here and _wapi_search_handle pinging
* the timestamp, the search will continue
*/
- return(TRUE);
+ return TRUE;
} else {
- return(FALSE);
+ return FALSE;
}
}
-gboolean CloseProcess(gpointer handle)
+gboolean
+CloseProcess (gpointer handle)
{
- if ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
- /* This is a pseudo handle */
- return(TRUE);
- }
-
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle))
+ return TRUE;
return CloseHandle (handle);
}
/*
* The caller owns the returned handle and must call CloseProcess () on it to clean it up.
*/
-gpointer OpenProcess (guint32 req_access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 pid)
+gpointer
+OpenProcess (guint32 req_access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 pid)
{
/* Find the process handle that corresponds to pid */
gpointer handle = NULL;
- mono_once (&process_current_once, process_set_current);
-
DEBUG ("%s: looking for process %d", __func__, pid);
handle = _wapi_search_handle (WAPI_HANDLE_PROCESS,
@@ -1534,34 +1198,31 @@ gpointer OpenProcess (guint32 req_access G_GNUC_UNUSED, gboolean inherit G_GNUC_
/* Return a pseudo handle for processes we
* don't have handles for
*/
- return GINT_TO_POINTER (_WAPI_PROCESS_UNHANDLED + pid);
+ return WAPI_PID_TO_HANDLE (pid);
} else {
DEBUG ("%s: Can't find pid %d", __func__, pid);
SetLastError (ERROR_PROC_NOT_FOUND);
- return(NULL);
+ return NULL;
}
}
/* _wapi_search_handle () already added a ref */
- return(handle);
+ return handle;
}
-gboolean GetExitCodeProcess (gpointer process, guint32 *code)
+gboolean
+GetExitCodeProcess (gpointer process, guint32 *code)
{
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
guint32 pid = -1;
- mono_once (&process_current_once, process_set_current);
-
- if(code==NULL) {
- return(FALSE);
- }
+ if (!code)
+ return FALSE;
- pid = GPOINTER_TO_UINT (process) - _WAPI_PROCESS_UNHANDLED;
- if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) {
+ pid = WAPI_HANDLE_TO_PID (process);
/* This is a pseudo handle, so we don't know what the
* exit code was, but we can check whether it's alive or not
*/
@@ -1573,12 +1234,11 @@ gboolean GetExitCodeProcess (gpointer process, guint32 *code)
}
}
- ok=_wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
- (gpointer *)&process_handle);
- if(ok==FALSE) {
+ process_handle = lookup_process_handle (process);
+ if (!process_handle) {
DEBUG ("%s: Can't find process %p", __func__, process);
- return(FALSE);
+ return FALSE;
}
/* A process handle is only signalled if the process has exited
@@ -1589,53 +1249,46 @@ gboolean GetExitCodeProcess (gpointer process, guint32 *code)
*/
process_wait (process, 0, TRUE);
- if (_wapi_handle_issignalled (process) == TRUE) {
+ if (_wapi_handle_issignalled (process))
*code = process_handle->exitstatus;
- } else {
+ else
*code = STILL_ACTIVE;
- }
- return(TRUE);
+ return TRUE;
}
-gboolean GetProcessTimes (gpointer process, WapiFileTime *create_time,
- WapiFileTime *exit_time, WapiFileTime *kernel_time,
- WapiFileTime *user_time)
+gboolean
+GetProcessTimes (gpointer process, WapiFileTime *create_time,
+ WapiFileTime *exit_time, WapiFileTime *kernel_time,
+ WapiFileTime *user_time)
{
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
gboolean ku_times_set = FALSE;
- mono_once (&process_current_once, process_set_current);
-
- if(create_time==NULL || exit_time==NULL || kernel_time==NULL ||
- user_time==NULL) {
+ if (create_time == NULL || exit_time == NULL || kernel_time == NULL ||
+ user_time == NULL)
/* Not sure if w32 allows NULLs here or not */
- return(FALSE);
- }
+ return FALSE;
- if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process))
/* This is a pseudo handle, so just fail for now
*/
- return(FALSE);
- }
+ return FALSE;
- ok=_wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
- (gpointer *)&process_handle);
- if(ok==FALSE) {
+ process_handle = lookup_process_handle (process);
+ if (!process_handle) {
DEBUG ("%s: Can't find process %p", __func__, process);
- return(FALSE);
+ return FALSE;
}
- *create_time=process_handle->create_time;
+ *create_time = process_handle->create_time;
/* A process handle is only signalled if the process has
* exited. Otherwise exit_time isn't set
*/
- if(_wapi_handle_issignalled (process)==TRUE) {
- *exit_time=process_handle->exit_time;
- }
+ if (_wapi_handle_issignalled (process))
+ *exit_time = process_handle->exit_time;
#ifdef HAVE_GETRUSAGE
if (process_handle->id == getpid ()) {
@@ -1655,18 +1308,18 @@ gboolean GetProcessTimes (gpointer process, WapiFileTime *create_time,
memset (user_time, 0, sizeof (WapiFileTime));
}
- return(TRUE);
+ return TRUE;
}
typedef struct
{
gpointer address_start;
gpointer address_end;
- gchar *perms;
+ char *perms;
gpointer address_offset;
dev_t device;
ino_t inode;
- gchar *filename;
+ char *filename;
} WapiProcModule;
static void free_procmodule (WapiProcModule *mod)
@@ -1843,9 +1496,9 @@ static GSList *load_modules (FILE *fp)
{
GSList *ret = NULL;
WapiProcModule *mod;
- gchar buf[MAXPATHLEN + 1], *p, *endp;
- gchar *start_start, *end_start, *prot_start, *offset_start;
- gchar *maj_dev_start, *min_dev_start, *inode_start, prot_buf[5];
+ char buf[MAXPATHLEN + 1], *p, *endp;
+ char *start_start, *end_start, *prot_start, *offset_start;
+ char *maj_dev_start, *min_dev_start, *inode_start, prot_buf[5];
gpointer address_start, address_end, address_offset;
guint32 maj_dev, min_dev;
ino_t inode;
@@ -1959,7 +1612,7 @@ static GSList *load_modules (FILE *fp)
}
#endif
-static gboolean match_procname_to_modulename (gchar *procname, gchar *modulename)
+static gboolean match_procname_to_modulename (char *procname, char *modulename)
{
char* lastsep = NULL;
char* lastsep2 = NULL;
@@ -2006,13 +1659,13 @@ static FILE *
open_process_map (int pid, const char *mode)
{
FILE *fp = NULL;
- const gchar *proc_path[] = {
+ const char *proc_path[] = {
"/proc/%d/maps", /* GNU/Linux */
"/proc/%d/map", /* FreeBSD */
NULL
};
int i;
- gchar *filename;
+ char *filename;
for (i = 0; fp == NULL && proc_path [i]; i++) {
filename = g_strdup_printf (proc_path[i], pid);
@@ -2027,8 +1680,7 @@ open_process_map (int pid, const char *mode)
gboolean EnumProcessModules (gpointer process, gpointer *modules,
guint32 size, guint32 *needed)
{
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
#if !defined(__OpenBSD__) && !defined(PLATFORM_MACOSX)
FILE *fp;
#endif
@@ -2037,7 +1689,7 @@ gboolean EnumProcessModules (gpointer process, gpointer *modules,
guint32 count, avail = size / sizeof(gpointer);
int i;
pid_t pid;
- gchar *proc_name = NULL;
+ char *proc_name = NULL;
/* Store modules in an array of pointers (main module as
* modules[0]), using the load address for each module as a
@@ -2048,72 +1700,76 @@ gboolean EnumProcessModules (gpointer process, gpointer *modules,
* implement /dev/kmem reading or whatever other horrid
* technique is needed.
*/
- if (size < sizeof(gpointer)) {
- return(FALSE);
- }
+ if (size < sizeof(gpointer))
+ return FALSE;
- if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
- /* This is a pseudo handle */
- pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK);
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) {
+ pid = WAPI_HANDLE_TO_PID (process);
} else {
- ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
- (gpointer *)&process_handle);
- if (ok == FALSE) {
+ process_handle = lookup_process_handle (process);
+ if (!process_handle) {
DEBUG ("%s: Can't find process %p", __func__, process);
- return(FALSE);
+ return FALSE;
}
pid = process_handle->id;
proc_name = process_handle->proc_name;
}
#if defined(PLATFORM_MACOSX) || defined(__OpenBSD__) || defined(__HAIKU__)
- {
- mods = load_modules ();
+ mods = load_modules ();
+ if (!proc_name) {
+ modules[0] = NULL;
+ *needed = sizeof(gpointer);
+ return TRUE;
+ }
#else
- if ((fp = open_process_map (pid, "r")) == NULL) {
+ fp = open_process_map (pid, "r");
+ if (!fp) {
/* No /proc//maps so just return the main module
* shortcut for now
*/
modules[0] = NULL;
*needed = sizeof(gpointer);
- } else {
- mods = load_modules (fp);
- fclose (fp);
+ return TRUE;
+ }
+ mods = load_modules (fp);
+ fclose (fp);
#endif
- count = g_slist_length (mods);
+ count = g_slist_length (mods);
- /* count + 1 to leave slot 0 for the main module */
- *needed = sizeof(gpointer) * (count + 1);
-
- /* Use the NULL shortcut, as the first line in
- * /proc//maps isn't the executable, and we need
- * that first in the returned list. Check the module name
- * to see if it ends with the proc name and substitute
- * the first entry with it. FIXME if this turns out to
- * be a problem.
- */
- modules[0] = NULL;
- for (i = 0; i < (avail - 1) && i < count; i++) {
- module = (WapiProcModule *)g_slist_nth_data (mods, i);
- if (modules[0] != NULL)
- modules[i] = module->address_start;
- else if (match_procname_to_modulename (proc_name, module->filename))
- modules[0] = module->address_start;
- else
- modules[i + 1] = module->address_start;
- }
+ /* count + 1 to leave slot 0 for the main module */
+ *needed = sizeof(gpointer) * (count + 1);
+
+ /*
+ * Use the NULL shortcut, as the first line in
+ * /proc//maps isn't the executable, and we need
+ * that first in the returned list. Check the module name
+ * to see if it ends with the proc name and substitute
+ * the first entry with it. FIXME if this turns out to
+ * be a problem.
+ */
+ modules[0] = NULL;
+ for (i = 0; i < (avail - 1) && i < count; i++) {
+ module = (WapiProcModule *)g_slist_nth_data (mods, i);
+ if (modules[0] != NULL)
+ modules[i] = module->address_start;
+ else if (match_procname_to_modulename (proc_name, module->filename))
+ modules[0] = module->address_start;
+ else
+ modules[i + 1] = module->address_start;
+ }
- for (i = 0; i < count; i++) {
- free_procmodule (g_slist_nth_data (mods, i));
- }
- g_slist_free (mods);
+ for (i = 0; i < count; i++) {
+ free_procmodule (g_slist_nth_data (mods, i));
}
+ g_slist_free (mods);
- return(TRUE);
+ return TRUE;
}
-static gchar *get_process_name_from_proc (pid_t pid)
+static char *
+get_process_name_from_proc (pid_t pid)
{
#if defined(__OpenBSD__)
int mib [6];
@@ -2127,10 +1783,10 @@ static gchar *get_process_name_from_proc (pid_t pid)
#endif
#else
FILE *fp;
- gchar *filename = NULL;
+ char *filename = NULL;
#endif
- gchar buf[256];
- gchar *ret = NULL;
+ char buf[256];
+ char *ret = NULL;
#if defined(PLATFORM_SOLARIS)
filename = g_strdup_printf ("/proc/%d/psinfo", pid);
@@ -2239,7 +1895,7 @@ static gchar *get_process_name_from_proc (pid_t pid)
filename = g_strdup_printf ("/proc/%d/stat", pid);
if ((fp = fopen (filename, "r")) != NULL) {
if (fgets (buf, 256, fp) != NULL) {
- gchar *start, *end;
+ char *start, *end;
start = strchr (buf, '(');
if (start != NULL) {
@@ -2266,11 +1922,11 @@ static gchar *get_process_name_from_proc (pid_t pid)
* Return the full path of the executable of the process PID, or NULL if it cannot be determined.
* Returns malloc-ed memory.
*/
-gchar*
+char*
wapi_process_get_path (pid_t pid)
{
#if defined(PLATFORM_MACOSX) && !defined(__mono_ppc__) && defined(TARGET_OSX)
- gchar buf [PROC_PIDPATHINFO_MAXSIZE];
+ char buf [PROC_PIDPATHINFO_MAXSIZE];
int res;
res = proc_pidpath (pid, buf, sizeof (buf));
@@ -2296,15 +1952,15 @@ wapi_process_set_cli_launcher (char *path)
cli_launcher = path ? g_strdup (path) : NULL;
}
-static guint32 get_module_name (gpointer process, gpointer module,
- gunichar2 *basename, guint32 size,
- gboolean base)
+static guint32
+get_module_name (gpointer process, gpointer module,
+ gunichar2 *basename, guint32 size,
+ gboolean base)
{
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
pid_t pid;
gunichar2 *procname;
- gchar *procname_ext = NULL;
+ char *procname_ext = NULL;
glong len;
gsize bytes;
#if !defined(__OpenBSD__) && !defined(PLATFORM_MACOSX)
@@ -2314,31 +1970,27 @@ static guint32 get_module_name (gpointer process, gpointer module,
WapiProcModule *found_module;
guint32 count;
int i;
- gchar *proc_name = NULL;
+ char *proc_name = NULL;
- mono_once (&process_current_once, process_set_current);
-
DEBUG ("%s: Getting module base name, process handle %p module %p",
__func__, process, module);
- size = size*sizeof(gunichar2); /* adjust for unicode characters */
+ size = size * sizeof (gunichar2); /* adjust for unicode characters */
- if (basename == NULL || size == 0) {
- return(0);
- }
+ if (basename == NULL || size == 0)
+ return 0;
- if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) {
/* This is a pseudo handle */
- pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK);
+ pid = (pid_t)WAPI_HANDLE_TO_PID (process);
proc_name = get_process_name_from_proc (pid);
} else {
- ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
- (gpointer *)&process_handle);
- if (ok == FALSE) {
+ process_handle = lookup_process_handle (process);
+ if (!process_handle) {
DEBUG ("%s: Can't find process %p", __func__,
process);
- return(0);
+ return 0;
}
pid = process_handle->id;
proc_name = g_strdup (process_handle->proc_name);
@@ -2346,10 +1998,10 @@ static guint32 get_module_name (gpointer process, gpointer module,
/* Look up the address in /proc//maps */
#if defined(PLATFORM_MACOSX) || defined(__OpenBSD__) || defined(__HAIKU__)
- {
- mods = load_modules ();
+ mods = load_modules ();
#else
- if ((fp = open_process_map (pid, "r")) == NULL) {
+ fp = open_process_map (pid, "r");
+ if (fp == NULL) {
if (errno == EACCES && module == NULL && base == TRUE) {
procname_ext = get_process_name_from_proc (pid);
} else {
@@ -2357,47 +2009,45 @@ static guint32 get_module_name (gpointer process, gpointer module,
* for now
*/
g_free (proc_name);
- return(0);
+ return 0;
}
} else {
mods = load_modules (fp);
fclose (fp);
+ }
#endif
- count = g_slist_length (mods);
-
- /* If module != NULL compare the address.
- * If module == NULL we are looking for the main module.
- * The best we can do for now check it the module name end with the process name.
- */
- for (i = 0; i < count; i++) {
- found_module = (WapiProcModule *)g_slist_nth_data (mods, i);
- if (procname_ext == NULL &&
- ((module == NULL && match_procname_to_modulename (proc_name, found_module->filename)) ||
- (module != NULL && found_module->address_start == module))) {
- if (base) {
- procname_ext = g_path_get_basename (found_module->filename);
- } else {
- procname_ext = g_strdup (found_module->filename);
- }
- }
+ count = g_slist_length (mods);
- free_procmodule (found_module);
+ /* If module != NULL compare the address.
+ * If module == NULL we are looking for the main module.
+ * The best we can do for now check it the module name end with the process name.
+ */
+ for (i = 0; i < count; i++) {
+ found_module = (WapiProcModule *)g_slist_nth_data (mods, i);
+ if (procname_ext == NULL &&
+ ((module == NULL && match_procname_to_modulename (proc_name, found_module->filename)) ||
+ (module != NULL && found_module->address_start == module))) {
+ if (base)
+ procname_ext = g_path_get_basename (found_module->filename);
+ else
+ procname_ext = g_strdup (found_module->filename);
}
- if (procname_ext == NULL)
- {
- /* If it's *still* null, we might have hit the
- * case where reading /proc/$pid/maps gives an
- * empty file for this user.
- */
- procname_ext = get_process_name_from_proc (pid);
- }
+ free_procmodule (found_module);
+ }
- g_slist_free (mods);
- g_free (proc_name);
+ if (procname_ext == NULL) {
+ /* If it's *still* null, we might have hit the
+ * case where reading /proc/$pid/maps gives an
+ * empty file for this user.
+ */
+ procname_ext = get_process_name_from_proc (pid);
}
- if (procname_ext != NULL) {
+ g_slist_free (mods);
+ g_free (proc_name);
+
+ if (procname_ext) {
DEBUG ("%s: Process name is [%s]", __func__,
procname_ext);
@@ -2405,7 +2055,7 @@ static guint32 get_module_name (gpointer process, gpointer module,
if (procname == NULL) {
/* bugger */
g_free (procname_ext);
- return(0);
+ return 0;
}
len = (bytes / 2);
@@ -2427,29 +2077,31 @@ static guint32 get_module_name (gpointer process, gpointer module,
g_free (procname);
g_free (procname_ext);
- return(len);
+ return len;
}
- return(0);
+ return 0;
}
-guint32 GetModuleBaseName (gpointer process, gpointer module,
- gunichar2 *basename, guint32 size)
+guint32
+GetModuleBaseName (gpointer process, gpointer module,
+ gunichar2 *basename, guint32 size)
{
- return(get_module_name (process, module, basename, size, TRUE));
+ return get_module_name (process, module, basename, size, TRUE);
}
-guint32 GetModuleFileNameEx (gpointer process, gpointer module,
- gunichar2 *filename, guint32 size)
+guint32
+GetModuleFileNameEx (gpointer process, gpointer module,
+ gunichar2 *filename, guint32 size)
{
- return(get_module_name (process, module, filename, size, FALSE));
+ return get_module_name (process, module, filename, size, FALSE);
}
-gboolean GetModuleInformation (gpointer process, gpointer module,
- WapiModuleInfo *modinfo, guint32 size)
+gboolean
+GetModuleInformation (gpointer process, gpointer module,
+ WapiModuleInfo *modinfo, guint32 size)
{
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
pid_t pid;
#if !defined(__OpenBSD__) && !defined(PLATFORM_MACOSX)
FILE *fp;
@@ -2459,37 +2111,31 @@ gboolean GetModuleInformation (gpointer process, gpointer module,
guint32 count;
int i;
gboolean ret = FALSE;
- gchar *proc_name = NULL;
-
- mono_once (&process_current_once, process_set_current);
+ char *proc_name = NULL;
DEBUG ("%s: Getting module info, process handle %p module %p",
__func__, process, module);
- if (modinfo == NULL || size < sizeof(WapiModuleInfo)) {
- return(FALSE);
- }
+ if (modinfo == NULL || size < sizeof (WapiModuleInfo))
+ return FALSE;
- if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
- /* This is a pseudo handle */
- pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK);
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) {
+ pid = (pid_t)WAPI_HANDLE_TO_PID (process);
proc_name = get_process_name_from_proc (pid);
} else {
- ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
- (gpointer *)&process_handle);
- if (ok == FALSE) {
+ process_handle = lookup_process_handle (process);
+ if (!process_handle) {
DEBUG ("%s: Can't find process %p", __func__,
process);
- return(FALSE);
+ return FALSE;
}
pid = process_handle->id;
proc_name = g_strdup (process_handle->proc_name);
}
#if defined(PLATFORM_MACOSX) || defined(__OpenBSD__) || defined(__HAIKU__)
- {
- mods = load_modules ();
+ mods = load_modules ();
#else
/* Look up the address in /proc//maps */
if ((fp = open_process_map (pid, "r")) == NULL) {
@@ -2497,22 +2143,22 @@ gboolean GetModuleInformation (gpointer process, gpointer module,
* for now
*/
g_free (proc_name);
- return(FALSE);
- } else {
- mods = load_modules (fp);
- fclose (fp);
+ return FALSE;
+ }
+ mods = load_modules (fp);
+ fclose (fp);
#endif
- count = g_slist_length (mods);
+ count = g_slist_length (mods);
- /* If module != NULL compare the address.
- * If module == NULL we are looking for the main module.
- * The best we can do for now check it the module name end with the process name.
- */
- for (i = 0; i < count; i++) {
+ /* If module != NULL compare the address.
+ * If module == NULL we are looking for the main module.
+ * The best we can do for now check it the module name end with the process name.
+ */
+ for (i = 0; i < count; i++) {
found_module = (WapiProcModule *)g_slist_nth_data (mods, i);
- if ( ret == FALSE &&
- ((module == NULL && match_procname_to_modulename (proc_name, found_module->filename)) ||
- (module != NULL && found_module->address_start == module))) {
+ if (ret == FALSE &&
+ ((module == NULL && match_procname_to_modulename (proc_name, found_module->filename)) ||
+ (module != NULL && found_module->address_start == module))) {
modinfo->lpBaseOfDll = found_module->address_start;
modinfo->SizeOfImage = (gsize)(found_module->address_end) - (gsize)(found_module->address_start);
modinfo->EntryPoint = found_module->address_offset;
@@ -2520,94 +2166,79 @@ gboolean GetModuleInformation (gpointer process, gpointer module,
}
free_procmodule (found_module);
- }
-
- g_slist_free (mods);
- g_free (proc_name);
}
- return(ret);
+ g_slist_free (mods);
+ g_free (proc_name);
+
+ return ret;
}
-gboolean GetProcessWorkingSetSize (gpointer process, size_t *min, size_t *max)
+gboolean
+GetProcessWorkingSetSize (gpointer process, size_t *min, size_t *max)
{
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
- mono_once (&process_current_once, process_set_current);
-
- if(min==NULL || max==NULL) {
+ if (min == NULL || max == NULL)
/* Not sure if w32 allows NULLs here or not */
- return(FALSE);
- }
+ return FALSE;
- if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
- /* This is a pseudo handle, so just fail for now
- */
- return(FALSE);
- }
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process))
+ /* This is a pseudo handle, so just fail for now */
+ return FALSE;
- ok=_wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
- (gpointer *)&process_handle);
- if(ok==FALSE) {
+ process_handle = lookup_process_handle (process);
+ if (!process_handle) {
DEBUG ("%s: Can't find process %p", __func__, process);
- return(FALSE);
+ return FALSE;
}
- *min=process_handle->min_working_set;
- *max=process_handle->max_working_set;
+ *min = process_handle->min_working_set;
+ *max = process_handle->max_working_set;
- return(TRUE);
+ return TRUE;
}
-gboolean SetProcessWorkingSetSize (gpointer process, size_t min, size_t max)
+gboolean
+SetProcessWorkingSetSize (gpointer process, size_t min, size_t max)
{
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
- mono_once (&process_current_once, process_set_current);
-
- if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process))
/* This is a pseudo handle, so just fail for now
*/
- return(FALSE);
- }
+ return FALSE;
- ok=_wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
- (gpointer *)&process_handle);
- if(ok==FALSE) {
+ process_handle = lookup_process_handle (process);
+ if (!process_handle) {
DEBUG ("%s: Can't find process %p", __func__, process);
- return(FALSE);
+ return FALSE;
}
- process_handle->min_working_set=min;
- process_handle->max_working_set=max;
+ process_handle->min_working_set = min;
+ process_handle->max_working_set = max;
- return(TRUE);
+ return TRUE;
}
gboolean
TerminateProcess (gpointer process, gint32 exitCode)
{
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
int signo;
int ret;
pid_t pid;
- if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) {
/* This is a pseudo handle */
- pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK);
+ pid = (pid_t)WAPI_HANDLE_TO_PID (process);
} else {
- ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
- (gpointer *) &process_handle);
-
- if (ok == FALSE) {
- DEBUG ("%s: Can't find process %p", __func__,
- process);
+ process_handle = lookup_process_handle (process);
+ if (!process_handle) {
+ DEBUG ("%s: Can't find process %p", __func__, process);
SetLastError (ERROR_INVALID_HANDLE);
return FALSE;
}
@@ -2639,19 +2270,16 @@ guint32
GetPriorityClass (gpointer process)
{
#ifdef HAVE_GETPRIORITY
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
int ret;
pid_t pid;
- if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) {
/* This is a pseudo handle */
- pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK);
+ pid = (pid_t)WAPI_HANDLE_TO_PID (process);
} else {
- ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
- (gpointer *) &process_handle);
-
- if (!ok) {
+ process_handle = lookup_process_handle (process);
+ if (!process_handle) {
SetLastError (ERROR_INVALID_HANDLE);
return FALSE;
}
@@ -2699,20 +2327,17 @@ gboolean
SetPriorityClass (gpointer process, guint32 priority_class)
{
#ifdef HAVE_SETPRIORITY
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
int ret;
int prio;
pid_t pid;
- if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) {
+ if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) {
/* This is a pseudo handle */
- pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK);
+ pid = (pid_t)WAPI_HANDLE_TO_PID (process);
} else {
- ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
- (gpointer *) &process_handle);
-
- if (!ok) {
+ process_handle = lookup_process_handle (process);
+ if (!process_handle) {
SetLastError (ERROR_INVALID_HANDLE);
return FALSE;
}
@@ -2796,6 +2421,12 @@ mono_processes_cleanup (void)
mp = mp->next;
}
+ /*
+ * Remove processes which exited from the mono_processes list.
+ * We need to synchronize with the sigchld handler here, which runs
+ * asynchronously. The handler requires that the mono_processes list
+ * remain valid.
+ */
mp = mono_processes;
spin = 0;
while (mp != NULL) {
@@ -2807,6 +2438,10 @@ mono_processes_cleanup (void)
/* We've found a candidate */
mono_mutex_lock (&mono_processes_mutex);
+ /*
+ * This code can run parallel with the sigchld handler, but the
+ * modifications it makes are safe.
+ */
if (candidate == NULL) {
/* unlink it */
if (mp == mono_processes) {
@@ -2857,12 +2492,14 @@ mono_processes_cleanup (void)
static void
process_close (gpointer handle, gpointer data)
{
- struct _WapiHandle_process *process_handle;
+ WapiHandle_process *process_handle;
DEBUG ("%s", __func__);
- process_handle = (struct _WapiHandle_process *) data;
- if (process_handle->mono_process && process_handle->self == _wapi_getpid ())
+ process_handle = (WapiHandle_process *) data;
+ g_free (process_handle->proc_name);
+ process_handle->proc_name = NULL;
+ if (process_handle->mono_process)
InterlockedDecrement (&process_handle->mono_process->handle_count);
mono_processes_cleanup ();
}
@@ -2874,9 +2511,7 @@ MONO_SIGNAL_HANDLER_FUNC (static, mono_sigchld_signal_handler, (int _dummy, sigi
int pid;
struct MonoProcess *p;
-#if DEBUG
- fprintf (stdout, "SIG CHILD handler for pid: %i\n", info->si_pid);
-#endif
+ DEBUG ("SIG CHILD handler for pid: %i\n", info->si_pid);
InterlockedIncrement (&mono_processes_read_lock);
@@ -2888,9 +2523,7 @@ MONO_SIGNAL_HANDLER_FUNC (static, mono_sigchld_signal_handler, (int _dummy, sigi
if (pid <= 0)
break;
-#if DEBUG
- fprintf (stdout, "child ended: %i", pid);
-#endif
+ DEBUG ("child ended: %i", pid);
p = mono_processes;
while (p != NULL) {
if (p->pid == pid) {
@@ -2905,14 +2538,13 @@ MONO_SIGNAL_HANDLER_FUNC (static, mono_sigchld_signal_handler, (int _dummy, sigi
InterlockedDecrement (&mono_processes_read_lock);
-#if DEBUG
- fprintf (stdout, "SIG CHILD handler: done looping.");
-#endif
+ DEBUG ("SIG CHILD handler: done looping.");
}
#endif
-static void process_add_sigchld_handler (void)
+static void
+process_add_sigchld_handler (void)
{
#if HAVE_SIGACTION
struct sigaction sa;
@@ -2925,23 +2557,15 @@ static void process_add_sigchld_handler (void)
#endif
}
-static guint32 process_wait (gpointer handle, guint32 timeout, gboolean alertable)
+static guint32
+process_wait (gpointer handle, guint32 timeout, gboolean alertable)
{
- struct _WapiHandle_process *process_handle;
- gboolean ok;
+ WapiHandle_process *process_handle;
pid_t pid, ret;
int status;
guint32 start;
guint32 now;
struct MonoProcess *mp;
- gboolean spin;
- gpointer current_thread;
-
- current_thread = wapi_get_current_thread_handle ();
- if (current_thread == NULL) {
- SetLastError (ERROR_INVALID_HANDLE);
- return WAIT_FAILED;
- }
/* FIXME: We can now easily wait on processes that aren't our own children,
* but WaitFor*Object won't call us for pseudo handles. */
@@ -2949,8 +2573,8 @@ static guint32 process_wait (gpointer handle, guint32 timeout, gboolean alertabl
DEBUG ("%s (%p, %u)", __func__, handle, timeout);
- ok = _wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS, (gpointer *)&process_handle);
- if (ok == FALSE) {
+ process_handle = lookup_process_handle (handle);
+ if (!process_handle) {
g_warning ("%s: error looking up process handle %p", __func__, handle);
return WAIT_FAILED;
}
@@ -2968,48 +2592,33 @@ static guint32 process_wait (gpointer handle, guint32 timeout, gboolean alertabl
/* We don't need to lock mono_processes here, the entry
* has a handle_count > 0 which means it will not be freed. */
mp = process_handle->mono_process;
- if (mp && process_handle->self != _wapi_getpid ()) {
- /* mono_process points to memory in another process' address space: we can't use it */
- mp = NULL;
- }
+ g_assert (mp);
start = mono_msec_ticks ();
now = start;
- spin = mp == NULL;
while (1) {
- if (mp != NULL) {
- /* We have a semaphore we can wait on */
- if (timeout != INFINITE) {
- DEBUG ("%s (%p, %u): waiting on semaphore for %li ms...",
- __func__, handle, timeout, (timeout - (now - start)));
+ if (timeout != INFINITE) {
+ DEBUG ("%s (%p, %u): waiting on semaphore for %li ms...",
+ __func__, handle, timeout, (timeout - (now - start)));
- ret = MONO_SEM_TIMEDWAIT_ALERTABLE (&mp->exit_sem, (timeout - (now - start)), alertable);
- } else {
- DEBUG ("%s (%p, %u): waiting on semaphore forever...",
- __func__, handle, timeout);
- ret = MONO_SEM_WAIT_ALERTABLE (&mp->exit_sem, alertable);
- }
+ ret = MONO_SEM_TIMEDWAIT_ALERTABLE (&mp->exit_sem, (timeout - (now - start)), alertable);
+ } else {
+ DEBUG ("%s (%p, %u): waiting on semaphore forever...",
+ __func__, handle, timeout);
+ ret = MONO_SEM_WAIT_ALERTABLE (&mp->exit_sem, alertable);
+ }
- if (ret == -1 && errno != EINTR && errno != ETIMEDOUT) {
- DEBUG ("%s (%p, %u): sem_timedwait failure: %s",
- __func__, handle, timeout, g_strerror (errno));
- /* Should we return a failure here? */
- }
+ if (ret == -1 && errno != EINTR && errno != ETIMEDOUT) {
+ DEBUG ("%s (%p, %u): sem_timedwait failure: %s",
+ __func__, handle, timeout, g_strerror (errno));
+ /* Should we return a failure here? */
+ }
- if (ret == 0) {
- /* Success, process has exited */
- MONO_SEM_POST (&mp->exit_sem);
- break;
- }
- } else {
- /* We did not create this process, so we can't waidpid / sem_wait it.
- * We need to poll for the pid existence */
- DEBUG ("%s (%p, %u): polling on pid...", __func__, handle, timeout);
- if (!is_pid_valid (pid)) {
- /* Success, process has exited */
- break;
- }
+ if (ret == 0) {
+ /* Success, process has exited */
+ MONO_SEM_POST (&mp->exit_sem);
+ break;
}
if (timeout == 0) {
@@ -3022,14 +2631,8 @@ static guint32 process_wait (gpointer handle, guint32 timeout, gboolean alertabl
DEBUG ("%s (%p, %u): WAIT_TIMEOUT", __func__, handle, timeout);
return WAIT_TIMEOUT;
}
-
- if (spin) {
- /* "timeout - (now - start)" will not underflow, since timeout is always >=0,
- * and we passed the check just above */
- _wapi_handle_spin (MIN (100, timeout - (now - start)));
- }
- if (alertable && _wapi_thread_apc_pending (current_thread)) {
+ if (alertable && _wapi_thread_cur_apc_pending ()) {
DEBUG ("%s (%p, %u): WAIT_IO_COMPLETION", __func__, handle, timeout);
return WAIT_IO_COMPLETION;
}
@@ -3042,11 +2645,10 @@ static guint32 process_wait (gpointer handle, guint32 timeout, gboolean alertabl
g_assert (ret == 0);
status = mp ? mp->status : 0;
- if (WIFSIGNALED (status)) {
+ if (WIFSIGNALED (status))
process_handle->exitstatus = 128 + WTERMSIG (status);
- } else {
+ else
process_handle->exitstatus = WEXITSTATUS (status);
- }
_wapi_time_t_to_filetime (time (NULL), &process_handle->exit_time);
process_handle->exited = TRUE;
@@ -3054,7 +2656,7 @@ static guint32 process_wait (gpointer handle, guint32 timeout, gboolean alertabl
DEBUG ("%s (%p, %u): Setting pid %d signalled, exit status %d",
__func__, handle, timeout, process_handle->id, process_handle->exitstatus);
- _wapi_shared_handle_set_signal_state (handle, TRUE);
+ _wapi_handle_set_signal_state (handle, TRUE, TRUE);
_wapi_handle_unlock_shared_handles ();
diff --git a/mono/io-layer/processes.h b/mono/io-layer/processes.h
index 8e4c0aa558b..c2b78d44387 100644
--- a/mono/io-layer/processes.h
+++ b/mono/io-layer/processes.h
@@ -10,6 +10,9 @@
#ifndef _WAPI_PROCESSES_H_
#define _WAPI_PROCESSES_H_
+#ifdef HAVE_UNISTD_H
+#include
+#endif
#include
#include
@@ -188,8 +191,6 @@ extern gboolean CreateProcessWithLogonW (const gunichar2 *username,
extern gpointer GetCurrentProcess (void);
extern guint32 GetProcessId (gpointer handle);
-extern guint32 GetCurrentProcessId (void);
-extern gboolean EnumProcesses (guint32 *pids, guint32 len, guint32 *needed);
extern gboolean CloseProcess (gpointer handle);
extern gpointer OpenProcess (guint32 access, gboolean inherit, guint32 pid);
extern gboolean GetExitCodeProcess (gpointer process, guint32 *code);
diff --git a/mono/io-layer/shared.c b/mono/io-layer/shared.c
index 1800f9b74a7..f8539039cad 100644
--- a/mono/io-layer/shared.c
+++ b/mono/io-layer/shared.c
@@ -44,8 +44,6 @@
static mono_mutex_t noshm_sems[_WAPI_SHARED_SEM_COUNT];
-gboolean _wapi_shm_disabled = TRUE;
-
static gpointer wapi_storage [16];
static void
@@ -152,12 +150,13 @@ _wapi_shm_detach (_wapi_shm_t type)
}
gboolean
-_wapi_shm_enabled (void)
+_wapi_shm_enabled_internal (void)
{
return FALSE;
}
-#else
+#else /* DISABLE_SHARED_HANDLES */
+
/*
* Use POSIX shared memory if possible, it is simpler, and it has the advantage that
* writes to the shared area does not need to be written to disk, avoiding spinning up
@@ -167,6 +166,8 @@ _wapi_shm_enabled (void)
#define USE_SHM 1
#endif
+static gboolean _wapi_shm_disabled = TRUE;
+
static gchar *
_wapi_shm_base_name (_wapi_shm_t type)
{
@@ -404,7 +405,7 @@ _wapi_shm_file_open (const gchar *filename, guint32 wanted_size)
}
gboolean
-_wapi_shm_enabled (void)
+_wapi_shm_enabled_internal (void)
{
static gboolean env_checked;
diff --git a/mono/io-layer/shared.h b/mono/io-layer/shared.h
index b175b6e306b..5f66a732e6d 100644
--- a/mono/io-layer/shared.h
+++ b/mono/io-layer/shared.h
@@ -17,15 +17,23 @@ typedef enum {
WAPI_SHM_FILESHARE
} _wapi_shm_t;
-extern gboolean _wapi_shm_disabled;
-
extern gpointer _wapi_shm_attach (_wapi_shm_t type);
extern void _wapi_shm_detach (_wapi_shm_t type);
-extern gboolean _wapi_shm_enabled (void);
+extern gboolean _wapi_shm_enabled_internal (void);
extern void _wapi_shm_semaphores_init (void);
extern void _wapi_shm_semaphores_remove (void);
extern int _wapi_shm_sem_lock (int sem);
extern int _wapi_shm_sem_trylock (int sem);
extern int _wapi_shm_sem_unlock (int sem);
+static inline gboolean
+_wapi_shm_enabled (void)
+{
+#ifdef DISABLE_SHARED_HANDLES
+ return FALSE;
+#else
+ return _wapi_shm_enabled_internal ();
+#endif
+}
+
#endif /* _WAPI_SHARED_H_ */
diff --git a/mono/io-layer/wapi-private.h b/mono/io-layer/wapi-private.h
index f982d860607..34de2f0fd99 100644
--- a/mono/io-layer/wapi-private.h
+++ b/mono/io-layer/wapi-private.h
@@ -42,8 +42,7 @@ typedef enum {
extern const char *_wapi_handle_typename[];
-#define _WAPI_SHARED_HANDLE(type) (type == WAPI_HANDLE_PROCESS || \
- type == WAPI_HANDLE_NAMEDMUTEX || \
+#define _WAPI_SHARED_HANDLE(type) (type == WAPI_HANDLE_NAMEDMUTEX || \
type == WAPI_HANDLE_NAMEDSEM || \
type == WAPI_HANDLE_NAMEDEVENT)
@@ -136,6 +135,7 @@ struct _WapiHandleUnshared
struct _WapiHandle_sem sem;
struct _WapiHandle_socket sock;
struct _WapiHandle_thread thread;
+ struct _WapiHandle_process process;
struct _WapiHandle_shared_ref shared;
} u;
};
@@ -149,7 +149,6 @@ struct _WapiHandleShared
union
{
- struct _WapiHandle_process process;
struct _WapiHandle_namedmutex namedmutex;
struct _WapiHandle_namedsem namedsem;
struct _WapiHandle_namedevent namedevent;
diff --git a/mono/metadata/Makefile.am b/mono/metadata/Makefile.am
index f0c175f08e3..335484ae676 100644
--- a/mono/metadata/Makefile.am
+++ b/mono/metadata/Makefile.am
@@ -124,6 +124,7 @@ common_sources = \
icall.c \
icall-def.h \
image.c \
+ jit-info.c \
loader.c \
locales.c \
locales.h \
@@ -222,9 +223,6 @@ sgen_sources = \
sgen-gc.c \
sgen-internal.c \
sgen-marksweep.c \
- sgen-marksweep-fixed.c \
- sgen-marksweep-par.c \
- sgen-marksweep-fixed-par.c \
sgen-los.c \
sgen-protocol.c \
sgen-bridge.c \
@@ -239,6 +237,8 @@ sgen_sources = \
sgen-archdep.h \
sgen-cardtable.c \
sgen-cardtable.h \
+ sgen-pointer-queue.c \
+ sgen-pointer-queue.h \
sgen-pinning.c \
sgen-pinning.h \
sgen-pinning-stats.c \
@@ -269,7 +269,8 @@ sgen_sources = \
sgen-layout-stats.c \
sgen-layout-stats.h \
sgen-qsort.c \
- sgen-qsort.h
+ sgen-qsort.h \
+ sgen-tagged-pointer.h
libmonoruntime_la_SOURCES = $(common_sources) $(gc_dependent_sources) $(null_gc_sources) $(boehm_sources)
libmonoruntime_la_CFLAGS = $(BOEHM_DEFINES)
diff --git a/mono/metadata/appdomain.c b/mono/metadata/appdomain.c
index 45b9a606ab6..c46bdfa2db4 100644
--- a/mono/metadata/appdomain.c
+++ b/mono/metadata/appdomain.c
@@ -2415,6 +2415,7 @@ mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
unload_data *thread_data;
MonoNativeThreadId tid;
MonoDomain *caller_domain = mono_domain_get ();
+ char *name;
/* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, GetCurrentThreadId ()); */
@@ -2466,7 +2467,10 @@ mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
if (thread_handle == NULL)
return;
+ name = g_strdup_printf ("Unload thread for domain %x", domain);
+ mono_thread_info_set_name (tid, name);
mono_thread_info_resume (tid);
+ g_free (name);
/* Wait for the thread */
while (!thread_data->done && WaitForSingleObjectEx (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
diff --git a/mono/metadata/boehm-gc.c b/mono/metadata/boehm-gc.c
index 3320820f877..090f2f7a1dc 100644
--- a/mono/metadata/boehm-gc.c
+++ b/mono/metadata/boehm-gc.c
@@ -753,7 +753,7 @@ create_allocator (int atype, int tls_key)
bytes_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
if (atype == ATYPE_STRING) {
/* a string alloator method takes the args: (vtable, len) */
- /* bytes = (sizeof (MonoString) + ((len + 1) * 2)); */
+ /* bytes = (offsetof (MonoString, chars) + ((len + 1) * 2)); */
mono_mb_emit_ldarg (mb, 1);
mono_mb_emit_icon (mb, 1);
mono_mb_emit_byte (mb, MONO_CEE_ADD);
@@ -1291,6 +1291,18 @@ mono_gc_get_los_limit (void)
return G_MAXINT;
}
+void
+mono_gc_set_string_length (MonoString *str, gint32 new_length)
+{
+ mono_unichar2 *new_end = str->chars + new_length;
+
+ /* zero the discarded string. This null-delimits the string and allows
+ * the space to be reclaimed by SGen. */
+
+ memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2));
+ str->length = new_length;
+}
+
gboolean
mono_gc_user_markers_supported (void)
{
diff --git a/mono/metadata/class-internals.h b/mono/metadata/class-internals.h
index ab4a5cb5789..2bf904143f1 100644
--- a/mono/metadata/class-internals.h
+++ b/mono/metadata/class-internals.h
@@ -208,8 +208,8 @@ enum {
MONO_EXCEPTION_GENERIC_SHARING_FAILED = 11,
MONO_EXCEPTION_BAD_IMAGE = 12,
MONO_EXCEPTION_OBJECT_SUPPLIED = 13, /*The exception object is already created.*/
- MONO_EXCEPTION_OUT_OF_MEMORY = 14
- /* add other exception type */
+ MONO_EXCEPTION_OUT_OF_MEMORY = 14,
+ MONO_EXCEPTION_INLINE_FAILED = 15
};
/* This struct collects the info needed for the runtime use of a class,
@@ -1228,13 +1228,9 @@ MONO_API MonoGenericContainer *
mono_metadata_load_generic_params (MonoImage *image, guint32 token,
MonoGenericContainer *parent_container);
-MONO_API void
-mono_metadata_load_generic_param_constraints (MonoImage *image, guint32 token,
- MonoGenericContainer *container);
-
-gboolean
-mono_metadata_load_generic_param_constraints_full (MonoImage *image, guint32 token,
- MonoGenericContainer *container) MONO_INTERNAL;
+MONO_API gboolean
+mono_metadata_load_generic_param_constraints_checked (MonoImage *image, guint32 token,
+ MonoGenericContainer *container, MonoError *error);
MonoMethodSignature*
mono_create_icall_signature (const char *sigstr) MONO_INTERNAL;
@@ -1298,7 +1294,7 @@ MONO_API gboolean
mono_class_is_valid_enum (MonoClass *klass);
MonoType *
-mono_type_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context) MONO_INTERNAL;
+mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error) MONO_INTERNAL;
gboolean
mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass) MONO_INTERNAL;
@@ -1386,4 +1382,16 @@ mono_class_get_methods_by_name (MonoClass *klass, const char *name, guint32 bfla
char*
mono_class_full_name (MonoClass *klass) MONO_INTERNAL;
+MonoClass*
+mono_class_inflate_generic_class_checked (MonoClass *gklass, MonoGenericContext *context, MonoError *error) MONO_INTERNAL;
+
+MonoClass *
+mono_class_get_checked (MonoImage *image, guint32 type_token, MonoError *error) MONO_INTERNAL;
+
+MonoClass *
+mono_class_get_and_inflate_typespec_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error) MONO_INTERNAL;
+
+MonoClass *
+mono_class_from_name_case_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error) MONO_INTERNAL;
+
#endif /* __MONO_METADATA_CLASS_INTERBALS_H__ */
diff --git a/mono/metadata/class.c b/mono/metadata/class.c
index d438803266c..e9ff58249ef 100644
--- a/mono/metadata/class.c
+++ b/mono/metadata/class.c
@@ -52,6 +52,9 @@ gboolean mono_print_vtable = FALSE;
guint32 inflated_classes, inflated_classes_size, inflated_methods_size;
guint32 classes_size, class_ext_size;
+/* Low level lock which protects data structures in this module */
+static mono_mutex_t classes_mutex;
+
/* Function supplied by the runtime to find classes by name using information from the AOT file */
static MonoGetClassFromName get_class_from_name = NULL;
@@ -100,6 +103,18 @@ static int record_gclass_instantiation;
static GSList *gclass_recorded_list;
typedef gboolean (*gclass_record_func) (MonoClass*, void*);
+static inline void
+classes_lock (void)
+{
+ mono_locks_acquire (&classes_mutex, ClassesLock);
+}
+
+static inline void
+classes_unlock (void)
+{
+ mono_locks_release (&classes_mutex, ClassesLock);
+}
+
/*
* LOCKING: loader lock must be held until pairing disable_gclass_recording is called.
*/
@@ -151,59 +166,60 @@ MonoClass *
mono_class_from_typeref (MonoImage *image, guint32 type_token)
{
MonoError error;
+ MonoClass *class = mono_class_from_typeref_checked (image, type_token, &error);
+ g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
+ return class;
+}
+
+MonoClass *
+mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError *error)
+{
guint32 cols [MONO_TYPEREF_SIZE];
MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
guint32 idx;
const char *name, *nspace;
- MonoClass *res;
+ MonoClass *res = NULL;
MonoImage *module;
- if (!mono_verifier_verify_typeref_row (image, (type_token & 0xffffff) - 1, &error)) {
- mono_trace_warning (MONO_TRACE_TYPE, "Failed to resolve typeref from %s due to '%s'", image->name, mono_error_get_message (&error));
+ mono_error_init (error);
+
+ if (!mono_verifier_verify_typeref_row (image, (type_token & 0xffffff) - 1, error))
return NULL;
- }
mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
- idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLTION_SCOPE_BITS;
- switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLTION_SCOPE_MASK) {
- case MONO_RESOLTION_SCOPE_MODULE:
+ idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLUTION_SCOPE_BITS;
+ switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLUTION_SCOPE_MASK) {
+ case MONO_RESOLUTION_SCOPE_MODULE:
/*
LAMESPEC The spec says that a null module resolution scope should go through the exported type table.
This is not the observed behavior of existing implementations.
The defacto behavior is that it's just a typedef in disguise.
*/
/* a typedef in disguise */
- return mono_class_from_name (image, nspace, name);
- case MONO_RESOLTION_SCOPE_MODULEREF:
+ res = mono_class_from_name (image, nspace, name); /*FIXME proper error handling*/
+ goto done;
+
+ case MONO_RESOLUTION_SCOPE_MODULEREF:
module = mono_image_load_module (image, idx);
if (module)
- return mono_class_from_name (module, nspace, name);
- else {
- char *msg = g_strdup_printf ("%s%s%s", nspace, nspace [0] ? "." : "", name);
- char *human_name;
-
- human_name = mono_stringify_assembly_name (&image->assembly->aname);
- mono_loader_set_error_type_load (msg, human_name);
- g_free (msg);
- g_free (human_name);
-
- return NULL;
- }
- case MONO_RESOLTION_SCOPE_TYPEREF: {
+ res = mono_class_from_name (module, nspace, name); /*FIXME proper error handling*/
+ goto done;
+
+ case MONO_RESOLUTION_SCOPE_TYPEREF: {
MonoClass *enclosing;
GList *tmp;
if (idx == mono_metadata_token_index (type_token)) {
- mono_loader_set_error_bad_image (g_strdup_printf ("Image %s with self-referencing typeref token %08x.", image->name, type_token));
+ mono_error_set_bad_image (error, image, "Image with self-referencing typeref token %08x.", type_token);
return NULL;
}
- enclosing = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | idx);
- if (!enclosing)
+ enclosing = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | idx, error);
+ if (!mono_error_ok (error))
return NULL;
if (enclosing->nested_classes_inited && enclosing->ext) {
@@ -221,28 +237,21 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token)
guint32 string_offset = mono_metadata_decode_row_col (&enclosing->image->tables [MONO_TABLE_TYPEDEF], class_nested - 1, MONO_TYPEDEF_NAME);
const char *nname = mono_metadata_string_heap (enclosing->image, string_offset);
- if (strcmp (nname, name) == 0) {
- MonoClass *res = mono_class_create_from_typedef (enclosing->image, MONO_TOKEN_TYPE_DEF | class_nested, &error);
- if (!mono_error_ok (&error)) {
- mono_loader_set_error_from_mono_error (&error);
- mono_error_cleanup (&error); /*FIXME don't swallow error message.*/
- return NULL;
- }
- return res;
- }
+ if (strcmp (nname, name) == 0)
+ return mono_class_create_from_typedef (enclosing->image, MONO_TOKEN_TYPE_DEF | class_nested, error);
i = mono_metadata_nesting_typedef (enclosing->image, enclosing->type_token, i + 1);
}
}
g_warning ("TypeRef ResolutionScope not yet handled (%d) for %s.%s in image %s", idx, nspace, name, image->name);
- return NULL;
+ goto done;
}
- case MONO_RESOLTION_SCOPE_ASSEMBLYREF:
+ case MONO_RESOLUTION_SCOPE_ASSEMBLYREF:
break;
}
if (idx > image->tables [MONO_TABLE_ASSEMBLYREF].rows) {
- mono_loader_set_error_bad_image (g_strdup_printf ("Image %s with invalid assemblyref token %08x.", image->name, idx));
+ mono_error_set_bad_image (error, image, "Image with invalid assemblyref token %08x.", idx);
return NULL;
}
@@ -257,13 +266,20 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token)
mono_assembly_get_assemblyref (image, idx - 1, &aname);
human_name = mono_stringify_assembly_name (&aname);
- mono_loader_set_error_assembly_load (human_name, image->assembly ? image->assembly->ref_only : FALSE);
- g_free (human_name);
-
+ mono_error_set_assembly_load_simple (error, human_name, image->assembly ? image->assembly->ref_only : FALSE);
return NULL;
}
- return mono_class_from_name (image->references [idx - 1]->image, nspace, name);
+ res = mono_class_from_name (image->references [idx - 1]->image, nspace, name);
+
+done:
+ /* Generic case, should be avoided for when a better error is possible. */
+ if (!res && mono_error_ok (error)) {
+ char *name = mono_class_name_from_token (image, type_token);
+ char *assembly = mono_assembly_name_from_token (image, type_token);
+ mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x", type_token);
+ }
+ return res;
}
@@ -878,7 +894,7 @@ mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoG
return inflated;
}
-static MonoClass*
+MonoClass*
mono_class_inflate_generic_class_checked (MonoClass *gklass, MonoGenericContext *context, MonoError *error)
{
MonoClass *res;
@@ -1243,7 +1259,7 @@ mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* con
* in a separate function since it is cheaper than calling mono_class_setup_fields.
*/
static MonoType*
-mono_class_find_enum_basetype (MonoClass *class)
+mono_class_find_enum_basetype (MonoClass *class, MonoError *error)
{
MonoGenericContainer *container = NULL;
MonoImage *m = class->image;
@@ -1252,6 +1268,8 @@ mono_class_find_enum_basetype (MonoClass *class)
g_assert (class->enumtype);
+ mono_error_init (error);
+
if (class->generic_container)
container = class->generic_container;
else if (class->generic_class) {
@@ -1276,27 +1294,41 @@ mono_class_find_enum_basetype (MonoClass *class)
if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC) //no need to decode static fields
continue;
- if (!mono_verifier_verify_field_signature (class->image, cols [MONO_FIELD_SIGNATURE], NULL))
- return NULL;
+ if (!mono_verifier_verify_field_signature (class->image, cols [MONO_FIELD_SIGNATURE], NULL)) {
+ mono_error_set_bad_image (error, class->image, "Invalid field signature %x", cols [MONO_FIELD_SIGNATURE]);
+ goto fail;
+ }
sig = mono_metadata_blob_heap (m, cols [MONO_FIELD_SIGNATURE]);
mono_metadata_decode_value (sig, &sig);
/* FIELD signature == 0x06 */
- if (*sig != 0x06)
- return NULL;
+ if (*sig != 0x06) {
+ mono_error_set_bad_image (error, class->image, "Invalid field signature %x, expected 0x6 but got %x", cols [MONO_FIELD_SIGNATURE], *sig);
+ goto fail;
+ }
ftype = mono_metadata_parse_type_full (m, container, MONO_PARSE_FIELD, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
- if (!ftype)
- return NULL;
+ if (!ftype) {
+ if (mono_loader_get_last_error ()) /*FIXME plug the above to not leak errors*/
+ mono_error_set_from_loader_error (error);
+ else
+ mono_error_set_bad_image (error, class->image, "Could not parse type for field signature %x", cols [MONO_FIELD_SIGNATURE]);
+ goto fail;
+ }
if (class->generic_class) {
//FIXME do we leak here?
- ftype = mono_class_inflate_generic_type (ftype, mono_class_get_context (class));
+ ftype = mono_class_inflate_generic_type_checked (ftype, mono_class_get_context (class), error);
+ if (!mono_error_ok (error))
+ goto fail;
ftype->attrs = cols [MONO_FIELD_FLAGS];
}
return ftype;
}
+ mono_error_set_type_load_class (error, class, "Could not find base type");
+fail:
+ g_assert (!mono_loader_get_last_error ());
return NULL;
}
@@ -1610,6 +1642,10 @@ mono_class_setup_fields (MonoClass *class)
mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Invalid negative field offset %d for %s", field->offset, field->name));
break;
}
+ if (class->generic_container) {
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Generic class cannot have explicit layout."));
+ break;
+ }
}
}
@@ -1907,7 +1943,9 @@ mono_class_layout_fields (MonoClass *class)
}
}
break;
- case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
+ case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT: {
+ guint8 *ref_bitmap;
+
real_size = 0;
for (i = 0; i < top; i++) {
gint32 align;
@@ -1920,7 +1958,6 @@ mono_class_layout_fields (MonoClass *class)
* There must be info about all the fields in a type if it
* uses explicit layout.
*/
-
if (mono_field_is_deleted (field))
continue;
if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
@@ -1950,6 +1987,43 @@ mono_class_layout_fields (MonoClass *class)
*/
real_size = MAX (real_size, size + field->offset);
}
+
+ if (class->has_references) {
+ ref_bitmap = g_new0 (guint8, real_size / sizeof (gpointer));
+
+ /* Check for overlapping reference and non-reference fields */
+ for (i = 0; i < top; i++) {
+ MonoType *ftype;
+
+ field = &class->fields [i];
+
+ if (mono_field_is_deleted (field))
+ continue;
+ if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
+ continue;
+ ftype = mono_type_get_underlying_type (field->type);
+ if (MONO_TYPE_IS_REFERENCE (ftype))
+ ref_bitmap [field->offset / sizeof (gpointer)] = 1;
+ }
+ for (i = 0; i < top; i++) {
+ field = &class->fields [i];
+
+ if (mono_field_is_deleted (field))
+ continue;
+ if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
+ continue;
+
+ // FIXME: Too much code does this
+#if 0
+ if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field->offset / sizeof (gpointer)]) {
+ char *err_msg = g_strdup_printf ("Could not load type '%s' because it contains an object field at offset %d that is incorrectly aligned or overlapped by a non-object field.", class->name, field->offset);
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, err_msg);
+ }
+#endif
+ }
+ g_free (ref_bitmap);
+ }
+
class->instance_size = MAX (real_size, class->instance_size);
if (class->instance_size & (class->min_align - 1)) {
class->instance_size += class->min_align - 1;
@@ -1957,6 +2031,7 @@ mono_class_layout_fields (MonoClass *class)
}
break;
}
+ }
if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
/*
@@ -2030,7 +2105,7 @@ create_array_method (MonoClass *class, const char *name, MonoMethodSignature *si
* mono_class_setup_methods:
* @class: a class
*
- * Initializes the 'methods' array in the klass.
+ * Initializes the 'methods' array in CLASS.
* Calling this method should be avoided if possible since it allocates a lot
* of long-living MonoMethod structures.
* Methods belonging to an interface are assigned a sequential slot starting
@@ -2041,19 +2116,12 @@ create_array_method (MonoClass *class, const char *name, MonoMethodSignature *si
void
mono_class_setup_methods (MonoClass *class)
{
- int i;
+ int i, count;
MonoMethod **methods;
if (class->methods)
return;
- mono_loader_lock ();
-
- if (class->methods) {
- mono_loader_unlock ();
- return;
- }
-
if (class->generic_class) {
MonoError error;
MonoClass *gklass = class->generic_class->container_class;
@@ -2062,17 +2130,16 @@ mono_class_setup_methods (MonoClass *class)
if (!gklass->exception_type)
mono_class_setup_methods (gklass);
if (gklass->exception_type) {
- /*FIXME make exception_data less opaque so it's possible to dup it here*/
+ /* FIXME make exception_data less opaque so it's possible to dup it here */
mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
- mono_loader_unlock ();
return;
}
/* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
- class->method.count = gklass->method.count;
- methods = mono_class_alloc0 (class, sizeof (MonoMethod*) * (class->method.count + 1));
+ count = gklass->method.count;
+ methods = mono_class_alloc0 (class, sizeof (MonoMethod*) * (count + 1));
- for (i = 0; i < class->method.count; i++) {
+ for (i = 0; i < count; i++) {
methods [i] = mono_class_inflate_generic_method_full_checked (
gklass->methods [i], class, mono_class_get_context (class), &error);
if (!mono_error_ok (&error)) {
@@ -2081,7 +2148,6 @@ mono_class_setup_methods (MonoClass *class)
g_free (method);
mono_error_cleanup (&error);
- mono_loader_unlock ();
return;
}
}
@@ -2092,18 +2158,18 @@ mono_class_setup_methods (MonoClass *class)
int count_generic = 0, first_generic = 0;
int method_num = 0;
- class->method.count = 3 + (class->rank > 1? 2: 1);
+ count = 3 + (class->rank > 1? 2: 1);
mono_class_setup_interfaces (class, &error);
g_assert (mono_error_ok (&error)); /*FIXME can this fail for array types?*/
if (class->interface_count) {
count_generic = generic_array_methods (class);
- first_generic = class->method.count;
- class->method.count += class->interface_count * count_generic;
+ first_generic = count;
+ count += class->interface_count * count_generic;
}
- methods = mono_class_alloc0 (class, sizeof (MonoMethod*) * class->method.count);
+ methods = mono_class_alloc0 (class, sizeof (MonoMethod*) * count);
sig = mono_metadata_signature_alloc (class->image, class->rank);
sig->ret = &mono_defaults.void_class->byval_arg;
@@ -2157,8 +2223,9 @@ mono_class_setup_methods (MonoClass *class)
for (i = 0; i < class->interface_count; i++)
setup_generic_array_ifaces (class, class->interfaces [i], methods, first_generic + i * count_generic);
} else {
- methods = mono_class_alloc (class, sizeof (MonoMethod*) * class->method.count);
- for (i = 0; i < class->method.count; ++i) {
+ count = class->method.count;
+ methods = mono_class_alloc (class, sizeof (MonoMethod*) * count);
+ for (i = 0; i < count; ++i) {
int idx = mono_metadata_translate_token_index (class->image, MONO_TABLE_METHOD, class->method.first + i + 1);
methods [i] = mono_get_method (class->image, MONO_TOKEN_METHOD_DEF | idx, class);
}
@@ -2167,18 +2234,24 @@ mono_class_setup_methods (MonoClass *class)
if (MONO_CLASS_IS_INTERFACE (class)) {
int slot = 0;
/*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/
- for (i = 0; i < class->method.count; ++i) {
+ for (i = 0; i < count; ++i) {
if (methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL)
methods [i]->slot = slot++;
}
}
- /* Needed because of the double-checking locking pattern */
- mono_memory_barrier ();
+ mono_image_lock (class->image);
- class->methods = methods;
+ if (!class->methods) {
+ class->method.count = count;
- mono_loader_unlock ();
+ /* Needed because of the double-checking locking pattern */
+ mono_memory_barrier ();
+
+ class->methods = methods;
+ }
+
+ mono_image_unlock (class->image);
}
/*
@@ -2296,7 +2369,13 @@ mono_class_get_vtable_size (MonoClass *klass)
return klass->vtable_size;
}
-/*This method can fail the class.*/
+/*
+ * mono_class_setup_properties:
+ *
+ * Initialize class->ext.property and class->ext.properties.
+ *
+ * This method can fail the class.
+ */
static void
mono_class_setup_properties (MonoClass *class)
{
@@ -2305,19 +2384,11 @@ mono_class_setup_properties (MonoClass *class)
MonoTableInfo *msemt = &class->image->tables [MONO_TABLE_METHODSEMANTICS];
MonoProperty *properties;
guint32 last;
+ int first, count;
if (class->ext && class->ext->properties)
return;
- mono_loader_lock ();
-
- if (class->ext && class->ext->properties) {
- mono_loader_unlock ();
- return;
- }
-
- mono_class_alloc_ext (class);
-
if (class->generic_class) {
MonoClass *gklass = class->generic_class->container_class;
@@ -2325,15 +2396,12 @@ mono_class_setup_properties (MonoClass *class)
mono_class_setup_properties (gklass);
if (gklass->exception_type) {
mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
- mono_loader_unlock ();
return;
}
- class->ext->property = gklass->ext->property;
+ properties = mono_class_new0 (class, MonoProperty, gklass->ext->property.count + 1);
- properties = mono_class_new0 (class, MonoProperty, class->ext->property.count + 1);
-
- for (i = 0; i < class->ext->property.count; i++) {
+ for (i = 0; i < gklass->ext->property.count; i++) {
MonoProperty *prop = &properties [i];
*prop = gklass->ext->properties [i];
@@ -2347,20 +2415,19 @@ mono_class_setup_properties (MonoClass *class)
prop->parent = class;
}
+
+ first = gklass->ext->property.first;
+ count = gklass->ext->property.count;
} else {
- int first = mono_metadata_properties_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last);
- int count = last - first;
+ first = mono_metadata_properties_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last);
+ count = last - first;
if (count) {
mono_class_setup_methods (class);
- if (class->exception_type) {
- mono_loader_unlock ();
+ if (class->exception_type)
return;
- }
}
- class->ext->property.first = first;
- class->ext->property.count = count;
properties = mono_class_alloc0 (class, sizeof (MonoProperty) * count);
for (i = first; i < last; ++i) {
mono_metadata_decode_table_row (class->image, MONO_TABLE_PROPERTY, i, cols, MONO_PROPERTY_SIZE);
@@ -2393,13 +2460,27 @@ mono_class_setup_properties (MonoClass *class)
}
}
}
- /*Flush any pending writes as we do double checked locking on class->properties */
+
+ mono_class_alloc_ext (class);
+
+ mono_image_lock (class->image);
+
+ if (class->ext->properties) {
+ /* We leak 'properties' which was allocated from the image mempool */
+ mono_image_unlock (class->image);
+ return;
+ }
+
+ class->ext->property.first = first;
+ class->ext->property.count = count;
+
+ /* Flush any pending writes as we do double checked locking on class->ext->properties */
mono_memory_barrier ();
/* Leave this assignment as the last op in the function */
class->ext->properties = properties;
- mono_loader_unlock ();
+ mono_image_unlock (class->image);
}
static MonoMethod**
@@ -2433,34 +2514,26 @@ mono_class_setup_events (MonoClass *class)
if (class->ext && class->ext->events)
return;
- mono_loader_lock ();
-
- if (class->ext && class->ext->events) {
- mono_loader_unlock ();
- return;
- }
-
- mono_class_alloc_ext (class);
-
if (class->generic_class) {
MonoClass *gklass = class->generic_class->container_class;
- MonoGenericContext *context;
+ MonoGenericContext *context = NULL;
mono_class_setup_events (gklass);
if (gklass->exception_type) {
mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
- mono_loader_unlock ();
return;
}
- class->ext->event = gklass->ext->event;
- class->ext->events = mono_class_new0 (class, MonoEvent, class->ext->event.count);
+ first = gklass->ext->event.first;
+ count = gklass->ext->event.count;
- if (class->ext->event.count)
+ events = mono_class_new0 (class, MonoEvent, count);
+
+ if (count)
context = mono_class_get_context (class);
- for (i = 0; i < class->ext->event.count; i++) {
- MonoEvent *event = &class->ext->events [i];
+ for (i = 0; i < count; i++) {
+ MonoEvent *event = &events [i];
MonoEvent *gevent = &gklass->ext->events [i];
event->parent = class;
@@ -2473,89 +2546,97 @@ mono_class_setup_events (MonoClass *class)
#endif
event->attrs = gevent->attrs;
}
+ } else {
+ first = mono_metadata_events_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last);
+ count = last - first;
- mono_loader_unlock ();
- return;
- }
-
- first = mono_metadata_events_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last);
- count = last - first;
-
- if (count) {
- mono_class_setup_methods (class);
- if (class->exception_type) {
- mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
- mono_loader_unlock ();
- return;
+ if (count) {
+ mono_class_setup_methods (class);
+ if (class->exception_type) {
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
+ return;
+ }
}
- }
- class->ext->event.first = first;
- class->ext->event.count = count;
- events = mono_class_alloc0 (class, sizeof (MonoEvent) * class->ext->event.count);
- for (i = first; i < last; ++i) {
- MonoEvent *event = &events [i - first];
- mono_metadata_decode_table_row (class->image, MONO_TABLE_EVENT, i, cols, MONO_EVENT_SIZE);
- event->parent = class;
- event->attrs = cols [MONO_EVENT_FLAGS];
- event->name = mono_metadata_string_heap (class->image, cols [MONO_EVENT_NAME]);
+ events = mono_class_alloc0 (class, sizeof (MonoEvent) * count);
+ for (i = first; i < last; ++i) {
+ MonoEvent *event = &events [i - first];
- startm = mono_metadata_methods_from_event (class->image, i, &endm);
- for (j = startm; j < endm; ++j) {
- MonoMethod *method;
+ mono_metadata_decode_table_row (class->image, MONO_TABLE_EVENT, i, cols, MONO_EVENT_SIZE);
+ event->parent = class;
+ event->attrs = cols [MONO_EVENT_FLAGS];
+ event->name = mono_metadata_string_heap (class->image, cols [MONO_EVENT_NAME]);
- mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
+ startm = mono_metadata_methods_from_event (class->image, i, &endm);
+ for (j = startm; j < endm; ++j) {
+ MonoMethod *method;
- if (class->image->uncompressed_metadata)
- /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
- method = mono_get_method (class->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], class);
- else
- method = class->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - class->method.first];
+ mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
- switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
- case METHOD_SEMANTIC_ADD_ON:
- event->add = method;
- break;
- case METHOD_SEMANTIC_REMOVE_ON:
- event->remove = method;
- break;
- case METHOD_SEMANTIC_FIRE:
- event->raise = method;
- break;
- case METHOD_SEMANTIC_OTHER: {
+ if (class->image->uncompressed_metadata)
+ /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
+ method = mono_get_method (class->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], class);
+ else
+ method = class->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - class->method.first];
+
+ switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
+ case METHOD_SEMANTIC_ADD_ON:
+ event->add = method;
+ break;
+ case METHOD_SEMANTIC_REMOVE_ON:
+ event->remove = method;
+ break;
+ case METHOD_SEMANTIC_FIRE:
+ event->raise = method;
+ break;
+ case METHOD_SEMANTIC_OTHER: {
#ifndef MONO_SMALL_CONFIG
- int n = 0;
-
- if (event->other == NULL) {
- event->other = g_new0 (MonoMethod*, 2);
- } else {
- while (event->other [n])
- n++;
- event->other = g_realloc (event->other, (n + 2) * sizeof (MonoMethod*));
- }
- event->other [n] = method;
- /* NULL terminated */
- event->other [n + 1] = NULL;
+ int n = 0;
+
+ if (event->other == NULL) {
+ event->other = g_new0 (MonoMethod*, 2);
+ } else {
+ while (event->other [n])
+ n++;
+ event->other = g_realloc (event->other, (n + 2) * sizeof (MonoMethod*));
+ }
+ event->other [n] = method;
+ /* NULL terminated */
+ event->other [n + 1] = NULL;
#endif
- break;
- }
- default:
- break;
+ break;
+ }
+ default:
+ break;
+ }
}
}
}
- /*Flush any pending writes as we do double checked locking on class->properties */
+
+ mono_class_alloc_ext (class);
+
+ mono_image_lock (class->image);
+
+ if (class->ext->events) {
+ mono_image_unlock (class->image);
+ return;
+ }
+
+ class->ext->event.first = first;
+ class->ext->event.count = count;
+
+ /* Flush any pending writes as we do double checked locking on class->ext.events */
mono_memory_barrier ();
/* Leave this assignment as the last op in the function */
class->ext->events = events;
- mono_loader_unlock ();
+ mono_image_unlock (class->image);
}
/*
* Global pool of interface IDs, represented as a bitset.
- * LOCKING: this is supposed to be accessed with the loader lock held.
+ * LOCKING: Protected by the classes lock.
*/
static MonoBitSet *global_interface_bitset = NULL;
@@ -2570,18 +2651,18 @@ static MonoBitSet *global_interface_bitset = NULL;
void
mono_unload_interface_ids (MonoBitSet *bitset)
{
- mono_loader_lock ();
+ classes_lock ();
mono_bitset_sub (global_interface_bitset, bitset);
- mono_loader_unlock ();
+ classes_unlock ();
}
void
mono_unload_interface_id (MonoClass *class)
{
if (global_interface_bitset && class->interface_id) {
- mono_loader_lock ();
+ classes_lock ();
mono_bitset_clear (global_interface_bitset, class->interface_id);
- mono_loader_unlock ();
+ classes_unlock ();
}
}
@@ -2591,7 +2672,7 @@ mono_unload_interface_id (MonoClass *class)
*
* Assign a unique integer ID to the interface represented by @class.
* The ID will positive and as small as possible.
- * LOCKING: this is supposed to be called with the loader lock held.
+ * LOCKING: Acquires the classes lock.
* Returns: the new ID.
*/
static guint
@@ -2601,6 +2682,8 @@ mono_get_unique_iid (MonoClass *class)
g_assert (MONO_CLASS_IS_INTERFACE (class));
+ classes_lock ();
+
if (!global_interface_bitset) {
global_interface_bitset = mono_bitset_new (128, 0);
}
@@ -2628,6 +2711,8 @@ mono_get_unique_iid (MonoClass *class)
mono_bitset_set (class->image->interface_bitset, iid);
}
+ classes_unlock ();
+
#ifndef MONO_SMALL_CONFIG
if (mono_print_vtable) {
int generic_id;
@@ -5060,14 +5145,11 @@ mono_class_init (MonoClass *class)
} else {
class->vtable_size = szarray_vtable_size[slot];
}
- class->has_finalize_inited = TRUE;
} else if (class->generic_class && !MONO_CLASS_IS_INTERFACE (class)) {
MonoClass *gklass = class->generic_class->container_class;
/* Generic instance case */
class->ghcimpl = gklass->ghcimpl;
- class->has_finalize = mono_class_has_finalizer (gklass);
- class->has_finalize_inited = TRUE;
class->has_cctor = gklass->has_cctor;
mono_class_setup_vtable (gklass);
@@ -5184,55 +5266,61 @@ mono_class_init (MonoClass *class)
gboolean
mono_class_has_finalizer (MonoClass *klass)
{
- if (!klass->has_finalize_inited) {
- MonoClass *class = klass;
+ MonoClass *class = klass;
+ gboolean has_finalize = FALSE;
- mono_loader_lock ();
+ if (klass->has_finalize_inited)
+ return klass->has_finalize;
- /* Interfaces and valuetypes are not supposed to have finalizers */
- if (!(MONO_CLASS_IS_INTERFACE (class) || class->valuetype)) {
- MonoMethod *cmethod = NULL;
+ /* Interfaces and valuetypes are not supposed to have finalizers */
+ if (!(MONO_CLASS_IS_INTERFACE (class) || class->valuetype)) {
+ MonoMethod *cmethod = NULL;
- if (class->parent && class->parent->has_finalize) {
- class->has_finalize = 1;
- } else {
- if (class->parent) {
- /*
- * Can't search in metadata for a method named Finalize, because that
- * ignores overrides.
- */
- mono_class_setup_vtable (class);
- if (class->exception_type || mono_loader_get_last_error ())
- goto leave;
+ if (class->rank == 1 && class->byval_arg.type == MONO_TYPE_SZARRAY) {
+ } else if (class->generic_class) {
+ MonoClass *gklass = class->generic_class->container_class;
+
+ has_finalize = mono_class_has_finalizer (gklass);
+ } else if (class->parent && class->parent->has_finalize) {
+ has_finalize = TRUE;
+ } else {
+ if (class->parent) {
+ /*
+ * Can't search in metadata for a method named Finalize, because that
+ * ignores overrides.
+ */
+ mono_class_setup_vtable (class);
+ if (class->exception_type || mono_loader_get_last_error ())
+ cmethod = NULL;
+ else
cmethod = class->vtable [finalize_slot];
- }
+ }
- if (cmethod) {
- g_assert (class->vtable_size > finalize_slot);
+ if (cmethod) {
+ g_assert (class->vtable_size > finalize_slot);
- class->has_finalize = 0;
- if (class->parent) {
- if (cmethod->is_inflated)
- cmethod = ((MonoMethodInflated*)cmethod)->declaring;
- if (cmethod != default_finalize) {
- class->has_finalize = 1;
- }
- }
+ if (class->parent) {
+ if (cmethod->is_inflated)
+ cmethod = ((MonoMethodInflated*)cmethod)->declaring;
+ if (cmethod != default_finalize)
+ has_finalize = TRUE;
}
}
}
+ }
+
+ mono_image_lock (klass->image);
+
+ if (!klass->has_finalize_inited) {
+ klass->has_finalize = has_finalize ? 1 : 0;
mono_memory_barrier ();
klass->has_finalize_inited = TRUE;
-
- mono_loader_unlock ();
}
- return klass->has_finalize;
+ mono_image_unlock (klass->image);
- leave:
- mono_loader_unlock ();
- return FALSE;
+ return klass->has_finalize;
}
gboolean
@@ -5653,10 +5741,12 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
class->byval_arg.data.klass = class;
class->byval_arg.type = MONO_TYPE_CLASS;
}
- parent = mono_class_get_full (image, parent_token, context);
+ parent = mono_class_get_checked (image, parent_token, error);
+ if (parent && context) /* Always inflate */
+ parent = mono_class_inflate_generic_class_checked (parent, context, error);
if (parent == NULL) {
- mono_class_set_failure_from_loader_error (class, error, g_strdup_printf ("Could not load parent, token is %x", parent_token));
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
goto parent_failure;
}
@@ -5755,11 +5845,11 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
}
if (class->enumtype) {
- MonoType *enum_basetype = mono_class_find_enum_basetype (class);
+ MonoType *enum_basetype = mono_class_find_enum_basetype (class, error);
if (!enum_basetype) {
/*set it to a default value as the whole runtime can't handle this to be null*/
class->cast_class = class->element_class = mono_defaults.int32_class;
- mono_class_set_failure_and_error (class, error, "Could not enum basetype");
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
mono_loader_unlock ();
mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
g_assert (!mono_loader_get_last_error ());
@@ -5773,8 +5863,8 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
* We must do this after the class has been constructed to make certain recursive scenarios
* work.
*/
- if (class->generic_container && !mono_metadata_load_generic_param_constraints_full (image, type_token, class->generic_container)){
- mono_class_set_failure_from_loader_error (class, error, g_strdup ("Could not load generic parameter constraints"));
+ if (class->generic_container && !mono_metadata_load_generic_param_constraints_checked (image, type_token, class->generic_container, error)) {
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not load generic parameter constrains due to %s", mono_error_get_message (error)));
mono_loader_unlock ();
mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
g_assert (!mono_loader_get_last_error ());
@@ -6075,7 +6165,7 @@ set_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar, MonoClass *kla
}
ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
if (!ht) {
- mono_loader_lock ();
+ mono_image_lock (image);
ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
if (!ht) {
ht = g_hash_table_new (NULL, NULL);
@@ -6085,7 +6175,7 @@ set_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar, MonoClass *kla
else
image->var_cache_slow = ht;
}
- mono_loader_unlock ();
+ mono_image_unlock (image);
}
g_hash_table_insert (ht, GINT_TO_POINTER (n), klass);
@@ -6327,23 +6417,20 @@ mono_class_from_mono_type (MonoType *type)
static MonoType *
mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate, MonoError *error)
{
- MonoType *t = mono_type_create_from_typespec (image, type_spec);
+ MonoType *t = mono_type_create_from_typespec_checked (image, type_spec, error);
- mono_error_init (error);
*did_inflate = FALSE;
- if (!t) {
- char *name = mono_class_name_from_token (image, type_spec);
- char *assembly = mono_assembly_name_from_token (image, type_spec);
- mono_error_set_type_load_name (error, name, assembly, "Could not resolve typespec token %08x", type_spec);
+ if (!t)
return NULL;
- }
if (context && (context->class_inst || context->method_inst)) {
MonoType *inflated = inflate_generic_type (NULL, t, context, error);
- if (!mono_error_ok (error))
+ if (!mono_error_ok (error)) {
+ g_assert (!mono_loader_get_last_error ());
return NULL;
+ }
if (inflated) {
t = inflated;
@@ -6837,11 +6924,17 @@ mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_typ
g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
if (!klass->ext || !klass->ext->field_def_values) {
- mono_loader_lock ();
+ MonoFieldDefaultValue *def_values;
+
mono_class_alloc_ext (klass);
+
+ def_values = mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count);
+
+ mono_image_lock (klass->image);
+ mono_memory_barrier ();
if (!klass->ext->field_def_values)
- klass->ext->field_def_values = mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count);
- mono_loader_unlock ();
+ klass->ext->field_def_values = def_values;
+ mono_image_unlock (klass->image);
}
field_index = mono_field_get_index (field);
@@ -7050,18 +7143,18 @@ mono_assembly_name_from_token (MonoImage *image, guint32 type_token)
}
mono_metadata_decode_row (t, idx-1, cols, MONO_TYPEREF_SIZE);
- idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLTION_SCOPE_BITS;
- switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLTION_SCOPE_MASK) {
- case MONO_RESOLTION_SCOPE_MODULE:
+ idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLUTION_SCOPE_BITS;
+ switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLUTION_SCOPE_MASK) {
+ case MONO_RESOLUTION_SCOPE_MODULE:
/* FIXME: */
return g_strdup ("");
- case MONO_RESOLTION_SCOPE_MODULEREF:
+ case MONO_RESOLUTION_SCOPE_MODULEREF:
/* FIXME: */
return g_strdup ("");
- case MONO_RESOLTION_SCOPE_TYPEREF:
+ case MONO_RESOLUTION_SCOPE_TYPEREF:
/* FIXME: */
return g_strdup ("");
- case MONO_RESOLTION_SCOPE_ASSEMBLYREF:
+ case MONO_RESOLUTION_SCOPE_ASSEMBLYREF:
mono_assembly_get_assemblyref (image, idx - 1, &aname);
return mono_stringify_assembly_name (&aname);
default:
@@ -7084,6 +7177,7 @@ mono_assembly_name_from_token (MonoImage *image, guint32 type_token)
* @image: the image where the class resides
* @type_token: the token for the class
* @context: the generic context used to evaluate generic instantiations in
+ * @deprecated: Functions that expose MonoGenericContext are going away in mono 4.0
*
* Returns: the MonoClass that represents @type_token in @image
*/
@@ -7091,49 +7185,79 @@ MonoClass *
mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
{
MonoError error;
+ MonoClass *class;
+ class = mono_class_get_checked (image, type_token, &error);
+
+ if (class && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC)
+ class = mono_class_inflate_generic_class_checked (class, context, &error);
+
+ if (!class) {
+ mono_loader_set_error_from_mono_error (&error);
+ mono_error_cleanup (&error); /*FIXME don't swallow this error */
+ }
+ return class;
+}
+
+
+MonoClass *
+mono_class_get_and_inflate_typespec_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
+{
+ MonoClass *class;
+
+ mono_error_init (error);
+ class = mono_class_get_checked (image, type_token, error);
+
+ if (class && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC)
+ class = mono_class_inflate_generic_class_checked (class, context, error);
+
+ return class;
+}
+/**
+ * mono_class_get_checked:
+ * @image: the image where the class resides
+ * @type_token: the token for the class
+ * @error: error object to return any error
+ *
+ * Returns: the MonoClass that represents @type_token in @image
+ */
+MonoClass *
+mono_class_get_checked (MonoImage *image, guint32 type_token, MonoError *error)
+{
MonoClass *class = NULL;
+ mono_error_init (error);
+
if (image_is_dynamic (image)) {
int table = mono_metadata_token_table (type_token);
if (table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPESPEC) {
- mono_loader_set_error_bad_image (g_strdup ("Bad type token."));
+ mono_error_set_bad_image (error, image,"Bad token table for dynamic image: %x", table);
return NULL;
}
- return mono_lookup_dynamic_token (image, type_token, context);
+ class = mono_lookup_dynamic_token (image, type_token, NULL); /*FIXME proper error handling*/
+ goto done;
}
switch (type_token & 0xff000000){
case MONO_TOKEN_TYPE_DEF:
- class = mono_class_create_from_typedef (image, type_token, &error);
- if (!mono_error_ok (&error)) {
- mono_loader_set_error_from_mono_error (&error);
- /*FIXME don't swallow the error message*/
- mono_error_cleanup (&error);
- return NULL;
- }
+ class = mono_class_create_from_typedef (image, type_token, error);
break;
case MONO_TOKEN_TYPE_REF:
- class = mono_class_from_typeref (image, type_token);
+ class = mono_class_from_typeref_checked (image, type_token, error);
break;
case MONO_TOKEN_TYPE_SPEC:
- class = mono_class_create_from_typespec (image, type_token, context, &error);
- if (!mono_error_ok (&error)) {
- /*FIXME don't swallow the error message*/
- mono_error_cleanup (&error);
- }
+ class = mono_class_create_from_typespec (image, type_token, NULL, error);
break;
default:
- g_warning ("unknown token type %x", type_token & 0xff000000);
- g_assert_not_reached ();
+ mono_error_set_bad_image (error, image, "Unknown type token %x", type_token & 0xff000000);
}
- if (!class){
+done:
+ /* Generic case, should be avoided for when a better error is possible. */
+ if (!class && mono_error_ok (error)) {
char *name = mono_class_name_from_token (image, type_token);
char *assembly = mono_assembly_name_from_token (image, type_token);
- mono_loader_set_error_type_load (name, assembly);
- g_free (name);
- g_free (assembly);
+ mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x", type_token);
}
return class;
@@ -7141,42 +7265,44 @@ mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *c
/**
- * mono_type_get_full:
+ * mono_type_get_checked:
* @image: the image where the type resides
* @type_token: the token for the type
* @context: the generic context used to evaluate generic instantiations in
+ * @error: Error handling context
*
* This functions exists to fullfill the fact that sometimes it's desirable to have access to the
*
* Returns: the MonoType that represents @type_token in @image
*/
MonoType *
-mono_type_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
+mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
{
- MonoError error;
MonoType *type = NULL;
gboolean inflated = FALSE;
+ mono_error_init (error);
+
//FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then?
if (image_is_dynamic (image))
return mono_class_get_type (mono_lookup_dynamic_token (image, type_token, context));
if ((type_token & 0xff000000) != MONO_TOKEN_TYPE_SPEC) {
- MonoClass *class = mono_class_get_full (image, type_token, context);
- return class ? mono_class_get_type (class) : NULL;
- }
+ MonoClass *class = mono_class_get_checked (image, type_token, error);
- type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated, &error);
+ if (!class) {
+ g_assert (!mono_loader_get_last_error ());
+ return NULL;
+ }
- if (!mono_error_ok (&error)) {
- /*FIXME don't swalloc the error message.*/
- char *name = mono_class_name_from_token (image, type_token);
- char *assembly = mono_assembly_name_from_token (image, type_token);
+ g_assert (class);
+ return mono_class_get_type (class);
+ }
- g_warning ("Error loading type %s from %s due to %s", name, assembly, mono_error_get_message (&error));
+ type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated, error);
- mono_error_cleanup (&error);
- mono_loader_set_error_type_load (name, assembly);
+ if (!type) {
+ g_assert (!mono_loader_get_last_error ());
return NULL;
}
@@ -7336,6 +7462,7 @@ find_nocase (gpointer key, gpointer value, gpointer user_data)
* @image: The MonoImage where the type is looked up in
* @name_space: the type namespace
* @name: the type short name.
+ * @deprecated: use the _checked variant
*
* Obtains a MonoClass with a given namespace and a given name which
* is located in the given MonoImage. The namespace and name
@@ -7343,6 +7470,15 @@ find_nocase (gpointer key, gpointer value, gpointer user_data)
*/
MonoClass *
mono_class_from_name_case (MonoImage *image, const char* name_space, const char *name)
+{
+ MonoError error;
+ MonoClass *res = mono_class_from_name_case_checked (image, name_space, name, &error);
+ g_assert (!mono_error_ok (&error));
+ return res;
+}
+
+MonoClass *
+mono_class_from_name_case_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error)
{
MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
guint32 cols [MONO_TYPEDEF_SIZE];
@@ -7350,6 +7486,8 @@ mono_class_from_name_case (MonoImage *image, const char* name_space, const char
const char *nspace;
guint32 i, visib;
+ mono_error_init (error);
+
if (image_is_dynamic (image)) {
guint32 token = 0;
FindUserData user_data;
@@ -7378,7 +7516,7 @@ mono_class_from_name_case (MonoImage *image, const char* name_space, const char
mono_image_unlock (image);
if (token)
- return mono_class_get (image, MONO_TOKEN_TYPE_DEF | token);
+ return mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | token, error);
else
return NULL;
@@ -7397,7 +7535,7 @@ mono_class_from_name_case (MonoImage *image, const char* name_space, const char
n = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
if (mono_utf8_strcasecmp (n, name) == 0 && mono_utf8_strcasecmp (nspace, name_space) == 0)
- return mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
+ return mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | i, error);
}
return NULL;
}
@@ -8271,26 +8409,34 @@ mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class,
case MONO_TOKEN_TYPE_DEF:
case MONO_TOKEN_TYPE_REF:
case MONO_TOKEN_TYPE_SPEC: {
+ MonoError error;
MonoType *type;
if (handle_class)
*handle_class = mono_defaults.typehandle_class;
- type = mono_type_get_full (image, token, context);
- if (!type)
+ type = mono_type_get_checked (image, token, context, &error);
+ if (!type) {
+ mono_loader_set_error_from_mono_error (&error);
+ mono_error_cleanup (&error); /* FIXME Don't swallow the error */
return NULL;
+ }
mono_class_init (mono_class_from_mono_type (type));
/* We return a MonoType* as handle */
return type;
}
case MONO_TOKEN_FIELD_DEF: {
MonoClass *class;
+ MonoError error;
guint32 type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
if (!type)
return NULL;
if (handle_class)
*handle_class = mono_defaults.fieldhandle_class;
- class = mono_class_get_full (image, MONO_TOKEN_TYPE_DEF | type, context);
- if (!class)
+ class = mono_class_get_and_inflate_typespec_checked (image, MONO_TOKEN_TYPE_DEF | type, context, &error);
+ if (!class) {
+ mono_loader_set_error_from_mono_error (&error);
+ mono_error_cleanup (&error); /* FIXME Don't swallow the error */
return NULL;
+ }
mono_class_init (class);
return mono_class_get_field (class, token);
}
@@ -8878,6 +9024,58 @@ mono_class_get_interfaces (MonoClass* klass, gpointer *iter)
return NULL;
}
+static void
+setup_nested_types (MonoClass *klass)
+{
+ MonoError error;
+ GList *classes, *nested_classes, *l;
+ int i;
+
+ if (klass->nested_classes_inited)
+ return;
+
+ if (!klass->type_token)
+ klass->nested_classes_inited = TRUE;
+
+ i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1);
+ classes = NULL;
+ while (i) {
+ MonoClass* nclass;
+ guint32 cols [MONO_NESTED_CLASS_SIZE];
+ mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
+ nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED], &error);
+ if (!mono_error_ok (&error)) {
+ /*FIXME don't swallow the error message*/
+ mono_error_cleanup (&error);
+
+ i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
+ continue;
+ }
+
+ classes = g_list_prepend (classes, nclass);
+
+ i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
+ }
+
+ mono_class_alloc_ext (klass);
+
+ nested_classes = NULL;
+ for (l = classes; l; l = l->next)
+ nested_classes = g_list_prepend_image (klass->image, nested_classes, l->data);
+ g_list_free (classes);
+
+ mono_image_lock (klass->image);
+
+ mono_memory_barrier ();
+ if (!klass->nested_classes_inited) {
+ klass->ext->nested_classes = nested_classes;
+ mono_memory_barrier ();
+ klass->nested_classes_inited = TRUE;
+ }
+
+ mono_image_unlock (klass->image);
+}
+
/**
* mono_class_get_nested_types
* @klass: the MonoClass to act on
@@ -8894,40 +9092,12 @@ mono_class_get_interfaces (MonoClass* klass, gpointer *iter)
MonoClass*
mono_class_get_nested_types (MonoClass* klass, gpointer *iter)
{
- MonoError error;
GList *item;
- int i;
if (!iter)
return NULL;
- if (!klass->nested_classes_inited) {
- if (!klass->type_token)
- klass->nested_classes_inited = TRUE;
- mono_loader_lock ();
- if (!klass->nested_classes_inited) {
- i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1);
- while (i) {
- MonoClass* nclass;
- guint32 cols [MONO_NESTED_CLASS_SIZE];
- mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
- nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED], &error);
- if (!mono_error_ok (&error)) {
- /*FIXME don't swallow the error message*/
- mono_error_cleanup (&error);
-
- i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
- continue;
- }
- mono_class_alloc_ext (klass);
- klass->ext->nested_classes = g_list_prepend_image (klass->image, klass->ext->nested_classes, nclass);
-
- i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
- }
- }
- mono_memory_barrier ();
- klass->nested_classes_inited = TRUE;
- mono_loader_unlock ();
- }
+ if (!klass->nested_classes_inited)
+ setup_nested_types (klass);
if (!*iter) {
/* start from the first */
@@ -9068,15 +9238,19 @@ mono_field_get_rva (MonoClassField *field)
guint32 rva;
int field_index;
MonoClass *klass = field->parent;
+ MonoFieldDefaultValue *field_def_values;
g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA);
if (!klass->ext || !klass->ext->field_def_values) {
- mono_loader_lock ();
mono_class_alloc_ext (klass);
+
+ field_def_values = mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count);
+
+ mono_image_lock (klass->image);
if (!klass->ext->field_def_values)
- klass->ext->field_def_values = mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count);
- mono_loader_unlock ();
+ klass->ext->field_def_values = field_def_values;
+ mono_image_unlock (klass->image);
}
field_index = mono_field_get_index (field);
@@ -9397,6 +9571,8 @@ mono_class_get_exception_data (MonoClass *klass)
void
mono_classes_init (void)
{
+ mono_mutex_init (&classes_mutex);
+
mono_counters_register ("Inflated methods size",
MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_methods_size);
mono_counters_register ("Inflated classes",
@@ -9420,6 +9596,7 @@ mono_classes_cleanup (void)
if (global_interface_bitset)
mono_bitset_free (global_interface_bitset);
global_interface_bitset = NULL;
+ mono_mutex_destroy (&classes_mutex);
}
/**
@@ -10024,15 +10201,22 @@ mono_class_setup_interface_id (MonoClass *class)
* mono_class_alloc_ext:
*
* Allocate klass->ext if not already done.
- * LOCKING: Assumes the loader lock is held.
*/
void
mono_class_alloc_ext (MonoClass *klass)
{
- if (!klass->ext) {
- klass->ext = mono_class_alloc0 (klass, sizeof (MonoClassExt));
- class_ext_size += sizeof (MonoClassExt);
- }
+ MonoClassExt *ext;
+
+ if (klass->ext)
+ return;
+
+ ext = mono_class_alloc0 (klass, sizeof (MonoClassExt));
+ mono_image_lock (klass->image);
+ mono_memory_barrier ();
+ if (!klass->ext)
+ klass->ext = ext;
+ class_ext_size += sizeof (MonoClassExt);
+ mono_image_unlock (klass->image);
}
/*
@@ -10045,53 +10229,62 @@ mono_class_alloc_ext (MonoClass *klass)
void
mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
{
- int i;
+ int i, interface_count;
+ MonoClass **interfaces;
mono_error_init (error);
if (klass->interfaces_inited)
return;
- mono_loader_lock ();
-
- if (klass->interfaces_inited) {
- mono_loader_unlock ();
- return;
- }
-
if (klass->rank == 1 && klass->byval_arg.type != MONO_TYPE_ARRAY) {
MonoType *args [1];
/* generic IList, ICollection, IEnumerable */
- klass->interface_count = mono_defaults.generic_ireadonlylist_class ? 2 : 1;
- klass->interfaces = mono_image_alloc0 (klass->image, sizeof (MonoClass*) * klass->interface_count);
+ interface_count = mono_defaults.generic_ireadonlylist_class ? 2 : 1;
+ interfaces = mono_image_alloc0 (klass->image, sizeof (MonoClass*) * interface_count);
args [0] = &klass->element_class->byval_arg;
- klass->interfaces [0] = mono_class_bind_generic_parameters (
+ interfaces [0] = mono_class_bind_generic_parameters (
mono_defaults.generic_ilist_class, 1, args, FALSE);
- if (klass->interface_count > 1)
- klass->interfaces [1] = mono_class_bind_generic_parameters (
+ if (interface_count > 1)
+ interfaces [1] = mono_class_bind_generic_parameters (
mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
} else if (klass->generic_class) {
MonoClass *gklass = klass->generic_class->container_class;
- klass->interface_count = gklass->interface_count;
- klass->interfaces = mono_class_new0 (klass, MonoClass *, klass->interface_count);
- for (i = 0; i < klass->interface_count; i++) {
- klass->interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (klass->generic_class), error);
+ mono_class_setup_interfaces (gklass, error);
+ if (!mono_error_ok (error)) {
+ mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not setup the interfaces"));
+ return;
+ }
+
+ interface_count = gklass->interface_count;
+ interfaces = mono_class_new0 (klass, MonoClass *, interface_count);
+ for (i = 0; i < interface_count; i++) {
+ interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (klass->generic_class), error);
if (!mono_error_ok (error)) {
mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not setup the interfaces"));
- klass->interfaces = NULL;
return;
}
}
+ } else {
+ interface_count = 0;
+ interfaces = NULL;
}
- mono_memory_barrier ();
+ mono_image_lock (klass->image);
- klass->interfaces_inited = TRUE;
+ if (!klass->interfaces_inited) {
+ klass->interface_count = interface_count;
+ klass->interfaces = interfaces;
- mono_loader_unlock ();
+ mono_memory_barrier ();
+
+ klass->interfaces_inited = TRUE;
+ }
+
+ mono_image_unlock (klass->image);
}
static void
diff --git a/mono/metadata/class.h b/mono/metadata/class.h
index a65bd4565e9..d9f315139b1 100644
--- a/mono/metadata/class.h
+++ b/mono/metadata/class.h
@@ -4,6 +4,7 @@
#include
#include
#include
+#include
MONO_BEGIN_DECLS
@@ -37,6 +38,9 @@ mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int p
MONO_API MonoClass *
mono_class_from_typeref (MonoImage *image, uint32_t type_token);
+MONO_API MonoClass *
+mono_class_from_typeref_checked (MonoImage *image, uint32_t type_token, MonoError *error);
+
MONO_API MonoClass *
mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, mono_bool is_mvar);
diff --git a/mono/metadata/console-unix.c b/mono/metadata/console-unix.c
index 6a70b350085..dffba190e31 100644
--- a/mono/metadata/console-unix.c
+++ b/mono/metadata/console-unix.c
@@ -277,7 +277,7 @@ mono_console_handle_async_ops (void)
static gboolean in_sigint;
-MONO_SIGNAL_HANDLER_FUNC (static, sigint_handler, (int signo))
+MONO_SIG_HANDLER_FUNC (static, sigint_handler)
{
int save_errno;
MONO_ARCH_SAVE_REGS;
@@ -295,7 +295,7 @@ MONO_SIGNAL_HANDLER_FUNC (static, sigint_handler, (int signo))
static struct sigaction save_sigcont, save_sigint, save_sigwinch;
-MONO_SIGNAL_HANDLER_FUNC (static, sigcont_handler, (int signo, void *the_siginfo, void *data))
+MONO_SIG_HANDLER_FUNC (static, sigcont_handler)
{
int unused;
// Ignore error, there is not much we can do in the sigcont handler.
@@ -308,10 +308,10 @@ MONO_SIGNAL_HANDLER_FUNC (static, sigcont_handler, (int signo, void *the_siginfo
if (save_sigcont.sa_sigaction != NULL &&
save_sigcont.sa_sigaction != (void *)SIG_DFL &&
save_sigcont.sa_sigaction != (void *)SIG_IGN)
- (*save_sigcont.sa_sigaction) (signo, the_siginfo, data);
+ (*save_sigcont.sa_sigaction) (MONO_SIG_HANDLER_PARAMS);
}
-MONO_SIGNAL_HANDLER_FUNC (static, sigwinch_handler, (int signo, void *the_siginfo, void *data))
+MONO_SIG_HANDLER_FUNC (static, sigwinch_handler)
{
int dims = terminal_get_dimensions ();
if (dims != -1)
@@ -321,7 +321,7 @@ MONO_SIGNAL_HANDLER_FUNC (static, sigwinch_handler, (int signo, void *the_siginf
if (save_sigwinch.sa_sigaction != NULL &&
save_sigwinch.sa_sigaction != (void *)SIG_DFL &&
save_sigwinch.sa_sigaction != (void *)SIG_IGN)
- (*save_sigwinch.sa_sigaction) (signo, the_siginfo, data);
+ (*save_sigwinch.sa_sigaction) (MONO_SIG_HANDLER_PARAMS);
}
/*
diff --git a/mono/metadata/culture-info-tables.h b/mono/metadata/culture-info-tables.h
index 5df6721ed4d..bdbeb1daf6b 100644
--- a/mono/metadata/culture-info-tables.h
+++ b/mono/metadata/culture-info-tables.h
@@ -223,7 +223,7 @@ static const DateTimeFormatEntry datetime_format_entries [] = {
{3943, 2309, 323, 331, 44, 55, 0, 0, {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}, {36041, 36052, 13523, 36063, 36074, 36081, 36090, 36103, 36110, 36123, 36136, 36149, 0}, {36041, 36052, 13523, 36063, 36074, 36081, 36090, 36103, 36110, 36123, 36136, 36149, 0}, {36041, 36052, 13523, 36063, 36074, 36081, 36090, 36103, 36110, 36123, 36136, 36149, 0}, {36041, 36052, 13523, 36063, 36074, 36081, 36090, 36103, 36110, 36123, 36136, 36149, 0}, 0, 6, 2541, 241, {2309,1236,1210,0,0,0,0,0,0,0,0,0,0,0},{3943,254,0,0,0,0,0,0},{331,274,35,0,0,0,0,0,0,0,0,0},{323,280,23,0,0,0,0,0,0}},
{1344, 2927, 323, 331, 1375, 1391, 1404, 1411, {1418, 1428, 1438, 1448, 1458, 1468, 1478}, {34903, 34910, 34917, 34924, 34931, 34938, 34945}, {1537, 1541, 1545, 1549, 1553, 1557, 1561}, {1655, 1660, 1665, 1670, 1675, 1680, 1685, 1690, 1695, 1700, 1706, 1712, 0}, {1655, 1660, 1665, 1670, 1675, 1680, 1685, 1690, 1695, 1700, 1706, 1712, 0}, {1655, 1660, 1665, 1670, 1675, 1680, 1685, 1690, 1695, 1700, 1706, 1712, 0}, {1655, 1660, 1665, 1670, 1675, 1680, 1685, 1690, 1695, 1700, 1706, 1712, 0}, 0, 0, 239, 241, {2927,1229,14,1765,1779,1366,1736,1210,0,0,0,0,0,0},{1344,36162,36189,2543,0,0,0,0},{331,274,0,0,0,0,0,0,0,0,0,0},{323,280,0,0,0,0,0,0,0}},
{2568, 2587, 280, 274, 1906, 1916, 2598, 2604, {2611, 2619, 2626, 2635, 2644, 2655, 2663}, {2671, 2674, 2677, 2680, 2683, 2686, 2689}, {2018, 2403, 2692, 2403, 2692, 2409, 2018}, {2694, 2701, 2709, 2715, 2721, 2725, 2730, 2735, 2742, 2752, 2760, 2769, 0}, {2694, 2701, 2709, 2715, 2721, 2725, 2730, 2735, 2742, 2752, 2760, 2769, 0}, {2778, 2782, 2786, 2791, 2721, 2795, 2799, 2803, 2807, 2811, 2815, 2819, 0}, {2778, 2782, 2786, 2791, 2721, 2795, 2799, 2803, 2807, 2811, 2815, 2819, 0}, 2, 1, 754, 241, {2587,1245,2835,35120,2843,1210,0,0,0,0,0,0,0,0},{2568,1882,35130,0,0,0,0,0},{274,331,8214,8204,2862,8237,8242,8223,8229,0,0,0},{280,323,8274,8287,2887,2873,2902,0,0}},
- {2909, 14812, 2936, 2947, 1906, 352, 7992, 21969, {3719, 3726, 3733, 3741, 3751, 3760, 3767}, {3776, 3780, 3784, 3788, 3792, 3796, 3800}, {2018, 2403, 2405, 3804, 2405, 2409, 2018}, {3806, 3814, 3823, 2715, 3829, 3833, 3838, 2735, 2742, 3843, 2760, 3851, 0}, {3806, 3814, 3823, 2715, 3829, 3833, 3838, 2735, 2742, 3843, 2760, 3851, 0}, {2778, 2782, 3860, 2791, 3829, 2795, 2799, 2803, 2807, 3864, 2815, 3868, 0}, {2778, 2782, 3860, 2791, 3829, 2795, 2799, 2803, 2807, 3864, 2815, 3868, 0}, 0, 0, 239, 241, {14812,1221,14,2835,1210,0,0,0,0,0,0,0,0,0},{2909,3672,0,0,0,0,0,0},{2947,35,274,331,0,0,0,0,0,0,0,0},{2936,23,280,323,0,0,0,0,0}},
+ {2909, 14812, 2936, 2947, 1906, 352, 7213, 7218, {3719, 3726, 3733, 3741, 3751, 3760, 3767}, {3776, 3780, 3784, 3788, 3792, 3796, 3800}, {2018, 2403, 2405, 3804, 2405, 2409, 2018}, {3806, 3814, 3823, 2715, 3829, 3833, 3838, 2735, 2742, 3843, 2760, 3851, 0}, {3806, 3814, 3823, 2715, 3829, 3833, 3838, 2735, 2742, 3843, 2760, 3851, 0}, {2778, 2782, 3860, 2791, 3829, 2795, 2799, 2803, 2807, 3864, 2815, 3868, 0}, {2778, 2782, 3860, 2791, 3829, 2795, 2799, 2803, 2807, 3864, 2815, 3868, 0}, 0, 0, 239, 241, {14812,1221,14,2835,1210,0,0,0,0,0,0,0,0,0},{2909,3672,0,0,0,0,0,0},{2947,35,274,331,0,0,0,0,0,0,0,0},{2936,23,280,323,0,0,0,0,0}},
{4342, 243, 23, 35, 947, 3985, 962, 968, {3997, 4005, 4011, 4018, 4029, 4036, 4044}, {4052, 4057, 4062, 4067, 4073, 4078, 4083}, {2692, 2411, 2403, 2403, 4089, 4091, 2018}, {4093, 4099, 4107, 4113, 4119, 4124, 4130, 4136, 4143, 4154, 4162, 4172, 0}, {4182, 4188, 4196, 1102, 4202, 4207, 4213, 4219, 4226, 1140, 4237, 4247, 0}, {4257, 4262, 4062, 4267, 4272, 4277, 4282, 4287, 4292, 4298, 4303, 4308, 0}, {4257, 4262, 4062, 4267, 4272, 4277, 4282, 4287, 4292, 4298, 4303, 4308, 0}, 0, 1, 239, 241, {243,14,1229,1236,1210,0,0,0,0,0,0,0,0,0},{4313,4342,4369,0,0,0,0,0},{35,2947,331,274,0,0,0,0,0,0,0,0},{23,2936,323,280,0,0,0,0,0}},
{36205, 243, 280, 274, 1906, 352, 1924, 1927, {4874, 4883, 4889, 4895, 4904, 4910, 4919}, {4926, 4931, 4936, 4941, 4946, 4951, 4956}, {2692, 2411, 2403, 2403, 4089, 4091, 2018}, {4961, 4969, 4978, 4983, 4989, 4993, 4998, 5006, 5012, 5022, 1148, 5030, 0}, {4961, 4969, 4978, 4983, 4989, 4993, 4998, 5006, 5012, 5022, 1148, 5030, 0}, {5040, 5046, 4978, 5053, 4989, 4993, 5058, 5006, 5064, 1195, 1200, 5070, 0}, {5040, 5046, 4978, 5053, 4989, 4993, 5058, 5006, 5064, 1195, 1200, 5070, 0}, 2, 1, 239, 241, {243,14,1245,1236,1210,0,0,0,0,0,0,0,0,0},{4857,5076,3672,0,0,0,0,0},{274,331,5085,5091,5101,0,0,0,0,0,0,0},{280,323,0,0,0,0,0,0,0}},
{1882, 2261, 323, 331, 1906, 11991, 36228, 36238, {9068, 9077, 9089, 9096, 9104, 9114, 9120}, {9127, 9131, 9135, 9139, 9143, 9148, 9152}, {0, 0, 0, 0, 0, 0, 0}, {2413, 2420, 15113, 2434, 2440, 2444, 2449, 11959, 36246, 36256, 36264, 36273, 0}, {2413, 2420, 15113, 2434, 2440, 2444, 2449, 11959, 36246, 36256, 36264, 36273, 0}, {2497, 2501, 2505, 2509, 2440, 2513, 2517, 11966, 2525, 2529, 2533, 2537, 0}, {2497, 2501, 2505, 2509, 2440, 2513, 2517, 11966, 2525, 2529, 2533, 2537, 0}, 0, 1, 754, 241, {2261,2843,1895,2587,9640,1245,11970,1210,0,0,0,0,0,0},{1882,2554,2568,0,0,0,0,0},{331,274,0,0,0,0,0,0,0,0,0,0},{323,280,0,0,0,0,0,0,0}},
diff --git a/mono/metadata/decimal.c b/mono/metadata/decimal.c
index 39d226d3b25..3bbd0058032 100644
--- a/mono/metadata/decimal.c
+++ b/mono/metadata/decimal.c
@@ -577,7 +577,7 @@ my_g_bit_nth_msf (gsize mask)
if (_BitScanReverse (&bIndex, mask))
return bIndex;
return -1;
-#elif defined(__x86_64__) && defined(_MSC_VER)
+#elif defined(_M_X64) && defined(_MSC_VER)
unsigned long bIndex = 0;
if (_BitScanReverse64 (&bIndex, mask))
return bIndex;
@@ -597,7 +597,7 @@ my_g_bit_nth_msf (gsize mask)
i = sizeof (gsize) * 8;
while (i > 0) {
i --;
- if (mask & (1UL << i))
+ if (mask & (1ULL << i))
return i;
}
return -1;
diff --git a/mono/metadata/domain-internals.h b/mono/metadata/domain-internals.h
index 119f173dd09..065e0458fa2 100644
--- a/mono/metadata/domain-internals.h
+++ b/mono/metadata/domain-internals.h
@@ -175,6 +175,7 @@ typedef struct
typedef struct
{
guint32 stack_size;
+ guint32 epilog_size;
} MonoArchEHJitInfo;
typedef struct {
@@ -187,6 +188,14 @@ typedef struct {
gboolean cas_method_permitonly:1;
} MonoMethodCasInfo;
+typedef enum {
+ JIT_INFO_NONE = 0,
+ JIT_INFO_HAS_CAS_INFO = (1 << 0),
+ JIT_INFO_HAS_GENERIC_JIT_INFO = (1 << 1),
+ JIT_INFO_HAS_TRY_BLOCK_HOLES = (1 << 2),
+ JIT_INFO_HAS_ARCH_EH_INFO = (1 << 3)
+} MonoJitInfoFlags;
+
struct _MonoJitInfo {
/* NOTE: These first two elements (method and
next_jit_code_hash) must be in the same order and at the
@@ -455,6 +464,19 @@ mono_cleanup (void) MONO_INTERNAL;
void
mono_close_exe_image (void) MONO_INTERNAL;
+int
+mono_jit_info_size (MonoJitInfoFlags flags, int num_clauses, int num_holes) MONO_INTERNAL;
+
+void
+mono_jit_info_init (MonoJitInfo *ji, MonoMethod *method, guint8 *code, int code_size,
+ MonoJitInfoFlags flags, int num_clauses, int num_holes) MONO_INTERNAL;
+
+MonoJitInfoTable *
+mono_jit_info_table_new (MonoDomain *domain) MONO_INTERNAL;
+
+void
+mono_jit_info_table_free (MonoJitInfoTable *table) MONO_INTERNAL;
+
void
mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji) MONO_INTERNAL;
diff --git a/mono/metadata/domain.c b/mono/metadata/domain.c
old mode 100644
new mode 100755
index b1b912f4e9b..e30c0345c0a
--- a/mono/metadata/domain.c
+++ b/mono/metadata/domain.c
@@ -116,8 +116,6 @@ typedef struct {
static const MonoRuntimeInfo *current_runtime = NULL;
-static MonoJitInfoFindInAot jit_info_find_in_aot_func = NULL;
-
/* This is the list of runtime versions supported by this JIT.
*/
static const MonoRuntimeInfo supported_runtimes[] = {
@@ -160,876 +158,16 @@ gint32
mono_domain_get_tls_offset (void)
{
int offset = -1;
+
+#ifdef HOST_WIN32
+ if (appdomain_thread_id)
+ offset = appdomain_thread_id;
+#else
MONO_THREAD_VAR_OFFSET (tls_appdomain, offset);
-/* __asm ("jmp 1f; .section writetext, \"awx\"; 1: movl $tls_appdomain@ntpoff, %0; jmp 2f; .previous; 2:"
- : "=r" (offset));*/
+#endif
return offset;
}
-#define JIT_INFO_TABLE_FILL_RATIO_NOM 3
-#define JIT_INFO_TABLE_FILL_RATIO_DENOM 4
-#define JIT_INFO_TABLE_FILLED_NUM_ELEMENTS (MONO_JIT_INFO_TABLE_CHUNK_SIZE * JIT_INFO_TABLE_FILL_RATIO_NOM / JIT_INFO_TABLE_FILL_RATIO_DENOM)
-
-#define JIT_INFO_TABLE_LOW_WATERMARK(n) ((n) / 2)
-#define JIT_INFO_TABLE_HIGH_WATERMARK(n) ((n) * 5 / 6)
-
-#define JIT_INFO_TOMBSTONE_MARKER ((MonoMethod*)NULL)
-#define IS_JIT_INFO_TOMBSTONE(ji) ((ji)->d.method == JIT_INFO_TOMBSTONE_MARKER)
-
-#define JIT_INFO_TABLE_HAZARD_INDEX 0
-#define JIT_INFO_HAZARD_INDEX 1
-
-static int
-jit_info_table_num_elements (MonoJitInfoTable *table)
-{
- int i;
- int num_elements = 0;
-
- for (i = 0; i < table->num_chunks; ++i) {
- MonoJitInfoTableChunk *chunk = table->chunks [i];
- int chunk_num_elements = chunk->num_elements;
- int j;
-
- for (j = 0; j < chunk_num_elements; ++j) {
- if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
- ++num_elements;
- }
- }
-
- return num_elements;
-}
-
-static MonoJitInfoTableChunk*
-jit_info_table_new_chunk (void)
-{
- MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
- chunk->refcount = 1;
-
- return chunk;
-}
-
-static MonoJitInfoTable *
-jit_info_table_new (MonoDomain *domain)
-{
- MonoJitInfoTable *table = g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
-
- table->domain = domain;
- table->num_chunks = 1;
- table->chunks [0] = jit_info_table_new_chunk ();
-
- return table;
-}
-
-static void
-jit_info_table_free (MonoJitInfoTable *table)
-{
- int i;
- int num_chunks = table->num_chunks;
- MonoDomain *domain = table->domain;
-
- mono_domain_lock (domain);
-
- table->domain->num_jit_info_tables--;
- if (table->domain->num_jit_info_tables <= 1) {
- GSList *list;
-
- for (list = table->domain->jit_info_free_queue; list; list = list->next)
- g_free (list->data);
-
- g_slist_free (table->domain->jit_info_free_queue);
- table->domain->jit_info_free_queue = NULL;
- }
-
- /* At this point we assume that there are no other threads
- still accessing the table, so we don't have to worry about
- hazardous pointers. */
-
- for (i = 0; i < num_chunks; ++i) {
- MonoJitInfoTableChunk *chunk = table->chunks [i];
- int num_elements;
- int j;
-
- if (--chunk->refcount > 0)
- continue;
-
- num_elements = chunk->num_elements;
- for (j = 0; j < num_elements; ++j) {
- MonoJitInfo *ji = chunk->data [j];
-
- if (IS_JIT_INFO_TOMBSTONE (ji))
- g_free (ji);
- }
-
- g_free (chunk);
- }
-
- mono_domain_unlock (domain);
-
- g_free (table);
-}
-
-/* The jit_info_table is sorted in ascending order by the end
- * addresses of the compiled methods. The reason why we have to do
- * this is that once we introduce tombstones, it becomes possible for
- * code ranges to overlap, and if we sort by code start and insert at
- * the back of the table, we cannot guarantee that we won't overlook
- * an entry.
- *
- * There are actually two possible ways to do the sorting and
- * inserting which work with our lock-free mechanism:
- *
- * 1. Sort by start address and insert at the front. When looking for
- * an entry, find the last one with a start address lower than the one
- * you're looking for, then work your way to the front of the table.
- *
- * 2. Sort by end address and insert at the back. When looking for an
- * entry, find the first one with an end address higher than the one
- * you're looking for, then work your way to the end of the table.
- *
- * We chose the latter out of convenience.
- */
-static int
-jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
-{
- int left = 0, right = table->num_chunks;
-
- g_assert (left < right);
-
- do {
- int pos = (left + right) / 2;
- MonoJitInfoTableChunk *chunk = table->chunks [pos];
-
- if (addr < chunk->last_code_end)
- right = pos;
- else
- left = pos + 1;
- } while (left < right);
- g_assert (left == right);
-
- if (left >= table->num_chunks)
- return table->num_chunks - 1;
- return left;
-}
-
-static int
-jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
-{
- int left = 0, right = chunk->num_elements;
-
- while (left < right) {
- int pos = (left + right) / 2;
- MonoJitInfo *ji = 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)
- right = pos;
- else
- left = pos + 1;
- }
- g_assert (left == right);
-
- return left;
-}
-
-static MonoJitInfo*
-jit_info_table_find (MonoJitInfoTable *table, MonoThreadHazardPointers *hp, gint8 *addr)
-{
- MonoJitInfo *ji;
- int chunk_pos, pos;
-
- chunk_pos = jit_info_table_index (table, (gint8*)addr);
- g_assert (chunk_pos < table->num_chunks);
-
- pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
-
- /* We now have a position that's very close to that of the
- first element whose end address is higher than the one
- we're looking for. If we don't have the exact position,
- then we have a position below that one, so we'll just
- search upward until we find our element. */
- do {
- MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
-
- while (pos < chunk->num_elements) {
- ji = get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
-
- ++pos;
-
- if (IS_JIT_INFO_TOMBSTONE (ji)) {
- mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
- continue;
- }
- if ((gint8*)addr >= (gint8*)ji->code_start
- && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
- mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
- return ji;
- }
-
- /* If we find a non-tombstone element which is already
- beyond what we're looking for, we have to end the
- search. */
- if ((gint8*)addr < (gint8*)ji->code_start)
- goto not_found;
- }
-
- ++chunk_pos;
- pos = 0;
- } while (chunk_pos < table->num_chunks);
-
- not_found:
- if (hp)
- mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
- return NULL;
-}
-
-/*
- * mono_jit_info_table_find_internal:
- *
- * If TRY_AOT is FALSE, avoid loading information for missing methods from AOT images, which is currently not async safe.
- * In this case, only those AOT methods will be found whose jit info is already loaded.
- * ASYNC SAFETY: When called in an async context (mono_thread_info_is_async_context ()), this is async safe.
- * In this case, the returned MonoJitInfo might not have metadata information, in particular,
- * mono_jit_info_get_method () could fail.
- */
-MonoJitInfo*
-mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_aot)
-{
- MonoJitInfoTable *table;
- MonoJitInfo *ji, *module_ji;
- MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
-
- ++mono_stats.jit_info_table_lookup_count;
-
- /* First we have to get the domain's jit_info_table. This is
- complicated by the fact that a writer might substitute a
- new table and free the old one. What the writer guarantees
- us is that it looks at the hazard pointers after it has
- changed the jit_info_table pointer. So, if we guard the
- 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 = 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)
- mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
- if (ji)
- return ji;
-
- /* Maybe its an AOT module */
- if (try_aot && mono_root_domain && mono_root_domain->aot_modules) {
- table = get_hazardous_pointer ((gpointer volatile*)&mono_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);
- if (hp)
- mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
- }
-
- return ji;
-}
-
-MonoJitInfo*
-mono_jit_info_table_find (MonoDomain *domain, char *addr)
-{
- return mono_jit_info_table_find_internal (domain, addr, TRUE);
-}
-
-static G_GNUC_UNUSED void
-jit_info_table_check (MonoJitInfoTable *table)
-{
- int i;
-
- for (i = 0; i < table->num_chunks; ++i) {
- MonoJitInfoTableChunk *chunk = table->chunks [i];
- int j;
-
- g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
- if (chunk->refcount > 10)
- printf("warning: chunk refcount is %d\n", chunk->refcount);
- g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
-
- for (j = 0; j < chunk->num_elements; ++j) {
- MonoJitInfo *this = chunk->data [j];
- MonoJitInfo *next;
-
- g_assert ((gint8*)this->code_start + this->code_size <= chunk->last_code_end);
-
- if (j < chunk->num_elements - 1)
- next = chunk->data [j + 1];
- else if (i < table->num_chunks - 1) {
- int k;
-
- for (k = i + 1; k < table->num_chunks; ++k)
- if (table->chunks [k]->num_elements > 0)
- break;
-
- if (k >= table->num_chunks)
- return;
-
- g_assert (table->chunks [k]->num_elements > 0);
- next = table->chunks [k]->data [0];
- } else
- return;
-
- g_assert ((gint8*)this->code_start + this->code_size <= (gint8*)next->code_start + next->code_size);
- }
- }
-}
-
-static MonoJitInfoTable*
-jit_info_table_realloc (MonoJitInfoTable *old)
-{
- int i;
- int num_elements = jit_info_table_num_elements (old);
- int required_size;
- int num_chunks;
- int new_chunk, new_element;
- MonoJitInfoTable *new;
-
- /* number of needed places for elements needed */
- required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
- num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
- if (num_chunks == 0) {
- g_assert (num_elements == 0);
- return jit_info_table_new (old->domain);
- }
- g_assert (num_chunks > 0);
-
- new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
- new->domain = old->domain;
- new->num_chunks = num_chunks;
-
- for (i = 0; i < num_chunks; ++i)
- new->chunks [i] = jit_info_table_new_chunk ();
-
- new_chunk = 0;
- new_element = 0;
- for (i = 0; i < old->num_chunks; ++i) {
- MonoJitInfoTableChunk *chunk = old->chunks [i];
- int chunk_num_elements = chunk->num_elements;
- int j;
-
- for (j = 0; j < chunk_num_elements; ++j) {
- if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
- g_assert (new_chunk < num_chunks);
- new->chunks [new_chunk]->data [new_element] = chunk->data [j];
- if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
- new->chunks [new_chunk]->num_elements = new_element;
- ++new_chunk;
- new_element = 0;
- }
- }
- }
- }
-
- if (new_chunk < num_chunks) {
- g_assert (new_chunk == num_chunks - 1);
- new->chunks [new_chunk]->num_elements = new_element;
- g_assert (new->chunks [new_chunk]->num_elements > 0);
- }
-
- for (i = 0; i < num_chunks; ++i) {
- MonoJitInfoTableChunk *chunk = new->chunks [i];
- MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
-
- new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
- }
-
- return new;
-}
-
-static void
-jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
-{
- MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
- MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
-
- g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
-
- new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
- new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
-
- memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
- memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
-
- new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
- + new1->data [new1->num_elements - 1]->code_size;
- new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
- + new2->data [new2->num_elements - 1]->code_size;
-
- *new1p = new1;
- *new2p = new2;
-}
-
-static MonoJitInfoTable*
-jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
-{
- MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
- + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
- int i, j;
-
- new_table->domain = table->domain;
- new_table->num_chunks = table->num_chunks + 1;
-
- j = 0;
- for (i = 0; i < table->num_chunks; ++i) {
- if (table->chunks [i] == chunk) {
- jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
- j += 2;
- } else {
- new_table->chunks [j] = table->chunks [i];
- ++new_table->chunks [j]->refcount;
- ++j;
- }
- }
-
- g_assert (j == new_table->num_chunks);
-
- return new_table;
-}
-
-static MonoJitInfoTableChunk*
-jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
-{
- MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
- int i, j;
-
- j = 0;
- for (i = 0; i < old->num_elements; ++i) {
- if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
- new->data [j++] = old->data [i];
- }
-
- new->num_elements = j;
- if (new->num_elements > 0)
- new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
- else
- new->last_code_end = old->last_code_end;
-
- return new;
-}
-
-static MonoJitInfoTable*
-jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
-{
- MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
- + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
- int i, j;
-
- new_table->domain = table->domain;
- new_table->num_chunks = table->num_chunks;
-
- j = 0;
- for (i = 0; i < table->num_chunks; ++i) {
- if (table->chunks [i] == chunk)
- new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
- else {
- new_table->chunks [j] = table->chunks [i];
- ++new_table->chunks [j]->refcount;
- ++j;
- }
- }
-
- g_assert (j == new_table->num_chunks);
-
- return new_table;
-}
-
-/* As we add an element to the table the case can arise that the chunk
- * to which we need to add is already full. In that case we have to
- * allocate a new table and do something about that chunk. We have
- * several strategies:
- *
- * If the number of elements in the table is below the low watermark
- * or above the high watermark, we reallocate the whole table.
- * Otherwise we only concern ourselves with the overflowing chunk:
- *
- * If there are no tombstones in the chunk then we split the chunk in
- * two, each half full.
- *
- * If the chunk does contain tombstones, we just make a new copy of
- * the chunk without the tombstones, which will have room for at least
- * the one element we have to add.
- */
-static MonoJitInfoTable*
-jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
-{
- int num_elements = jit_info_table_num_elements (table);
- int i;
-
- if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
- || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
- //printf ("reallocing table\n");
- return jit_info_table_realloc (table);
- }
-
- /* count the number of non-tombstone elements in the chunk */
- num_elements = 0;
- for (i = 0; i < chunk->num_elements; ++i) {
- if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
- ++num_elements;
- }
-
- if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
- //printf ("splitting chunk\n");
- return jit_info_table_copy_and_split_chunk (table, chunk);
- }
-
- //printf ("purifying chunk\n");
- return jit_info_table_copy_and_purify_chunk (table, chunk);
-}
-
-/* We add elements to the table by first making space for them by
- * shifting the elements at the back to the right, one at a time.
- * This results in duplicate entries during the process, but during
- * all the time the table is in a sorted state. Also, when an element
- * is replaced by another one, the element that replaces it has an end
- * address that is equal to or lower than that of the replaced
- * element. That property is necessary to guarantee that when
- * searching for an element we end up at a position not higher than
- * the one we're looking for (i.e. we either find the element directly
- * or we end up to the left of it).
- */
-static void
-jit_info_table_add (MonoDomain *domain, MonoJitInfoTable *volatile *table_ptr, MonoJitInfo *ji)
-{
- MonoJitInfoTable *table;
- MonoJitInfoTableChunk *chunk;
- int chunk_pos, pos;
- int num_elements;
- int i;
-
- table = *table_ptr;
-
- restart:
- chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
- g_assert (chunk_pos < table->num_chunks);
- chunk = table->chunks [chunk_pos];
-
- if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
- MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
-
- /* Debugging code, should be removed. */
- //jit_info_table_check (new_table);
-
- *table_ptr = new_table;
- mono_memory_barrier ();
- domain->num_jit_info_tables++;
- mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)jit_info_table_free, TRUE, FALSE);
- table = new_table;
-
- goto restart;
- }
-
- /* Debugging code, should be removed. */
- //jit_info_table_check (table);
-
- num_elements = chunk->num_elements;
-
- pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
-
- /* First we need to size up the chunk by one, by copying the
- last item, or inserting the first one, if the table is
- empty. */
- if (num_elements > 0)
- chunk->data [num_elements] = chunk->data [num_elements - 1];
- else
- chunk->data [0] = ji;
- mono_memory_write_barrier ();
- chunk->num_elements = ++num_elements;
-
- /* Shift the elements up one by one. */
- for (i = num_elements - 2; i >= pos; --i) {
- mono_memory_write_barrier ();
- chunk->data [i + 1] = chunk->data [i];
- }
-
- /* Now we have room and can insert the new item. */
- mono_memory_write_barrier ();
- chunk->data [pos] = ji;
-
- /* Set the high code end address chunk entry. */
- chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
- + chunk->data [chunk->num_elements - 1]->code_size;
-
- /* Debugging code, should be removed. */
- //jit_info_table_check (table);
-}
-
-void
-mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
-{
- g_assert (ji->d.method != NULL);
-
- mono_domain_lock (domain);
-
- ++mono_stats.jit_info_table_insert_count;
-
- jit_info_table_add (domain, &domain->jit_info_table, ji);
-
- mono_domain_unlock (domain);
-}
-
-static MonoJitInfo*
-mono_jit_info_make_tombstone (MonoJitInfo *ji)
-{
- MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
-
- tombstone->code_start = ji->code_start;
- tombstone->code_size = ji->code_size;
- tombstone->d.method = JIT_INFO_TOMBSTONE_MARKER;
-
- return tombstone;
-}
-
-/*
- * LOCKING: domain lock
- */
-static void
-mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
-{
- if (domain->num_jit_info_tables <= 1) {
- /* Can it actually happen that we only have one table
- but ji is still hazardous? */
- mono_thread_hazardous_free_or_queue (ji, g_free, TRUE, FALSE);
- } else {
- domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
- }
-}
-
-static void
-jit_info_table_remove (MonoJitInfoTable *table, MonoJitInfo *ji)
-{
- MonoJitInfoTableChunk *chunk;
- gpointer start = ji->code_start;
- int chunk_pos, pos;
-
- chunk_pos = jit_info_table_index (table, start);
- g_assert (chunk_pos < table->num_chunks);
-
- pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
-
- do {
- chunk = table->chunks [chunk_pos];
-
- while (pos < chunk->num_elements) {
- if (chunk->data [pos] == ji)
- goto found;
-
- g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
- g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
- <= (guint8*)ji->code_start + ji->code_size);
-
- ++pos;
- }
-
- ++chunk_pos;
- pos = 0;
- } while (chunk_pos < table->num_chunks);
-
- found:
- g_assert (chunk->data [pos] == ji);
-
- chunk->data [pos] = mono_jit_info_make_tombstone (ji);
-
- /* Debugging code, should be removed. */
- //jit_info_table_check (table);
-}
-
-void
-mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
-{
- MonoJitInfoTable *table;
-
- mono_domain_lock (domain);
- table = domain->jit_info_table;
-
- ++mono_stats.jit_info_table_remove_count;
-
- jit_info_table_remove (table, ji);
-
- mono_jit_info_free_or_queue (domain, ji);
-
- mono_domain_unlock (domain);
-}
-
-void
-mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
-{
- MonoJitInfo *ji;
-
- g_assert (mono_root_domain);
- mono_domain_lock (mono_root_domain);
-
- /*
- * We reuse MonoJitInfoTable to store AOT module info,
- * this gives us async-safe lookup.
- */
- if (!mono_root_domain->aot_modules) {
- mono_root_domain->num_jit_info_tables ++;
- mono_root_domain->aot_modules = jit_info_table_new (mono_root_domain);
- }
-
- ji = g_new0 (MonoJitInfo, 1);
- ji->d.image = image;
- ji->code_start = start;
- ji->code_size = (guint8*)end - (guint8*)start;
- jit_info_table_add (mono_root_domain, &mono_root_domain->aot_modules, ji);
-
- mono_domain_unlock (mono_root_domain);
-}
-
-void
-mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
-{
- jit_info_find_in_aot_func = func;
-}
-
-gpointer
-mono_jit_info_get_code_start (MonoJitInfo* ji)
-{
- return ji->code_start;
-}
-
-int
-mono_jit_info_get_code_size (MonoJitInfo* ji)
-{
- return ji->code_size;
-}
-
-MonoMethod*
-mono_jit_info_get_method (MonoJitInfo* ji)
-{
- g_assert (!ji->async);
- return ji->d.method;
-}
-
-static gpointer
-jit_info_key_extract (gpointer value)
-{
- MonoJitInfo *info = (MonoJitInfo*)value;
-
- return info->d.method;
-}
-
-static gpointer*
-jit_info_next_value (gpointer value)
-{
- MonoJitInfo *info = (MonoJitInfo*)value;
-
- return (gpointer*)&info->next_jit_code_hash;
-}
-
-void
-mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
-{
- mono_internal_hash_table_init (jit_code_hash,
- mono_aligned_addr_hash,
- jit_info_key_extract,
- jit_info_next_value);
-}
-
-MonoGenericJitInfo*
-mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
-{
- if (ji->has_generic_jit_info)
- return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
- else
- return NULL;
-}
-
-/*
- * mono_jit_info_get_generic_sharing_context:
- * @ji: a jit info
- *
- * Returns the jit info's generic sharing context, or NULL if it
- * doesn't have one.
- */
-MonoGenericSharingContext*
-mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
-{
- MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
-
- if (gi)
- return gi->generic_sharing_context;
- else
- return NULL;
-}
-
-/*
- * mono_jit_info_set_generic_sharing_context:
- * @ji: a jit info
- * @gsctx: a generic sharing context
- *
- * Sets the jit info's generic sharing context. The jit info must
- * have memory allocated for the context.
- */
-void
-mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
-{
- MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
-
- g_assert (gi);
-
- gi->generic_sharing_context = gsctx;
-}
-
-MonoTryBlockHoleTableJitInfo*
-mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
-{
- if (ji->has_try_block_holes) {
- char *ptr = (char*)&ji->clauses [ji->num_clauses];
- if (ji->has_generic_jit_info)
- ptr += sizeof (MonoGenericJitInfo);
- return (MonoTryBlockHoleTableJitInfo*)ptr;
- } else {
- return NULL;
- }
-}
-
-static int
-try_block_hole_table_size (MonoJitInfo *ji)
-{
- MonoTryBlockHoleTableJitInfo *table;
-
- table = mono_jit_info_get_try_block_hole_table_info (ji);
- g_assert (table);
- return sizeof (MonoTryBlockHoleTableJitInfo) + table->num_holes * sizeof (MonoTryBlockHoleJitInfo);
-}
-
-MonoArchEHJitInfo*
-mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
-{
- if (ji->has_arch_eh_info) {
- char *ptr = (char*)&ji->clauses [ji->num_clauses];
- if (ji->has_generic_jit_info)
- ptr += sizeof (MonoGenericJitInfo);
- if (ji->has_try_block_holes)
- ptr += try_block_hole_table_size (ji);
- return (MonoArchEHJitInfo*)ptr;
- } else {
- return NULL;
- }
-}
-
-MonoMethodCasInfo*
-mono_jit_info_get_cas_info (MonoJitInfo *ji)
-{
- if (ji->has_cas_info) {
- char *ptr = (char*)&ji->clauses [ji->num_clauses];
- if (ji->has_generic_jit_info)
- ptr += sizeof (MonoGenericJitInfo);
- if (ji->has_try_block_holes)
- ptr += try_block_hole_table_size (ji);
- if (ji->has_arch_eh_info)
- ptr += sizeof (MonoArchEHJitInfo);
- return (MonoMethodCasInfo*)ptr;
- } else {
- return NULL;
- }
-}
-
#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
#define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
@@ -1302,7 +440,7 @@ mono_domain_create (void)
mono_jit_code_hash_init (&domain->jit_code_hash);
domain->ldstr_table = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
domain->num_jit_info_tables = 1;
- domain->jit_info_table = jit_info_table_new (domain);
+ domain->jit_info_table = mono_jit_info_table_new (domain);
domain->jit_info_free_queue = NULL;
domain->finalizable_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
domain->ftnptrs_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
@@ -2094,9 +1232,9 @@ mono_domain_free (MonoDomain *domain, gboolean force)
*/
mono_thread_hazardous_try_free_all ();
if (domain->aot_modules)
- jit_info_table_free (domain->aot_modules);
+ mono_jit_info_table_free (domain->aot_modules);
g_assert (domain->num_jit_info_tables == 1);
- jit_info_table_free (domain->jit_info_table);
+ mono_jit_info_table_free (domain->jit_info_table);
domain->jit_info_table = NULL;
g_assert (!domain->jit_info_free_queue);
diff --git a/mono/metadata/exception.c b/mono/metadata/exception.c
index 24bfd6ed5ba..cf42445fa78 100644
--- a/mono/metadata/exception.c
+++ b/mono/metadata/exception.c
@@ -87,10 +87,12 @@ mono_exception_from_name_domain (MonoDomain *domain, MonoImage *image,
MonoException *
mono_exception_from_token (MonoImage *image, guint32 token)
{
+ MonoError error;
MonoClass *klass;
MonoObject *o;
- klass = mono_class_get (image, token);
+ klass = mono_class_get_checked (image, token, &error);
+ g_assert (mono_error_ok (&error)); /* FIXME handle the error. */
o = mono_object_new (mono_domain_get (), klass);
g_assert (o != NULL);
@@ -197,7 +199,9 @@ MonoException *
mono_exception_from_token_two_strings (MonoImage *image, guint32 token,
MonoString *a1, MonoString *a2)
{
- MonoClass *klass = mono_class_get (image, token);
+ MonoError error;
+ MonoClass *klass = mono_class_get_checked (image, token, &error);
+ g_assert (mono_error_ok (&error)); /* FIXME handle the error. */
return create_exception_two_strings (klass, a1, a2);
}
diff --git a/mono/metadata/gc-internal.h b/mono/metadata/gc-internal.h
index f2e59acb844..7b8836363f8 100644
--- a/mono/metadata/gc-internal.h
+++ b/mono/metadata/gc-internal.h
@@ -13,7 +13,6 @@
#include
#include
#include
-#include
#include
typedef struct {
@@ -21,14 +20,7 @@ typedef struct {
int major_gc_count;
long long minor_gc_time;
long long major_gc_time;
-#ifdef HEAVY_STATISTICS
- unsigned long long gray_queue_section_alloc;
- unsigned long long gray_queue_section_free;
- unsigned long long gray_queue_enqueue_fast_path;
- unsigned long long gray_queue_dequeue_fast_path;
- unsigned long long gray_queue_enqueue_slow_path;
- unsigned long long gray_queue_dequeue_slow_path;
-#endif
+ long long major_gc_time_concurrent;
} GCStats;
#define mono_domain_finalizers_lock(domain) mono_mutex_lock (&(domain)->finalizable_objects_hash_lock);
@@ -337,6 +329,8 @@ void mono_gc_set_skip_thread (gboolean skip) MONO_INTERNAL;
*/
gboolean mono_gc_is_disabled (void) MONO_INTERNAL;
+void mono_gc_set_string_length (MonoString *str, gint32 new_length) MONO_INTERNAL;
+
#if defined(__MACH__)
void mono_gc_register_mach_exception_thread (pthread_t thread) MONO_INTERNAL;
pthread_t mono_gc_get_mach_exception_thread (void) MONO_INTERNAL;
diff --git a/mono/metadata/gc.c b/mono/metadata/gc.c
index 03b182b99f4..4e025385b76 100644
--- a/mono/metadata/gc.c
+++ b/mono/metadata/gc.c
@@ -1154,14 +1154,7 @@ mono_gc_init (void)
mono_counters_register ("Major GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.major_gc_count);
mono_counters_register ("Minor GC time", MONO_COUNTER_GC | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &gc_stats.minor_gc_time);
mono_counters_register ("Major GC time", MONO_COUNTER_GC | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &gc_stats.major_gc_time);
-#ifdef HEAVY_STATISTICS
- mono_counters_register ("Gray Queue alloc section", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &gc_stats.gray_queue_section_alloc);
- mono_counters_register ("Gray Queue free section", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &gc_stats.gray_queue_section_free);
- mono_counters_register ("Gray Queue enqueue fast path", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &gc_stats.gray_queue_enqueue_fast_path);
- mono_counters_register ("Gray Queue dequeue fast path", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &gc_stats.gray_queue_dequeue_fast_path);
- mono_counters_register ("Gray Queue enqueue slow path", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &gc_stats.gray_queue_enqueue_slow_path);
- mono_counters_register ("Gray Queue dequeue slow path", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &gc_stats.gray_queue_dequeue_slow_path);
-#endif
+ mono_counters_register ("Major GC time concurrent", MONO_COUNTER_GC | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &gc_stats.major_gc_time_concurrent);
mono_gc_base_init ();
@@ -1231,7 +1224,7 @@ mono_gc_cleanup (void)
ret = WaitForSingleObjectEx (gc_thread->handle, INFINITE, TRUE);
g_assert (ret == WAIT_OBJECT_0);
- mono_thread_join ((gpointer)gc_thread->tid);
+ mono_thread_join (MONO_UINT_TO_NATIVE_THREAD_ID (gc_thread->tid));
}
}
gc_thread = NULL;
diff --git a/mono/metadata/icall-def.h b/mono/metadata/icall-def.h
index 103eb3c4230..257b8332f5f 100644
--- a/mono/metadata/icall-def.h
+++ b/mono/metadata/icall-def.h
@@ -797,6 +797,7 @@ ICALL(STRING_8a, "GetLOSLimit", ves_icall_System_String_GetLOSLimit)
ICALL(STRING_9, "InternalAllocateStr", ves_icall_System_String_InternalAllocateStr)
ICALL(STRING_10, "InternalIntern", ves_icall_System_String_InternalIntern)
ICALL(STRING_11, "InternalIsInterned", ves_icall_System_String_InternalIsInterned)
+ICALL(STRING_12, "InternalSetLength", ves_icall_System_String_InternalSetLength)
ICALL_TYPE(TENC, "System.Text.Encoding", TENC_1)
ICALL(TENC_1, "InternalCodePage", ves_icall_System_Text_Encoding_InternalCodePage)
diff --git a/mono/metadata/icall.c b/mono/metadata/icall.c
index ddec8e43053..763b2f638bf 100644
--- a/mono/metadata/icall.c
+++ b/mono/metadata/icall.c
@@ -907,11 +907,12 @@ ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_RunClassConstructor (Mo
ICALL_EXPORT void
ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_RunModuleConstructor (MonoImage *image)
{
- MONO_ARCH_SAVE_REGS;
+ MonoError error;
mono_image_check_for_module_cctor (image);
if (image->has_module_cctor) {
- MonoClass *module_klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | 1);
+ MonoClass *module_klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | 1, &error);
+ mono_error_raise_exception (&error);
/*It's fine to raise the exception here*/
mono_runtime_class_init (mono_class_vtable_full (mono_domain_get (), module_klass, TRUE));
}
@@ -1673,8 +1674,7 @@ ves_icall_System_Reflection_FieldInfo_GetTypeModifiers (MonoReflectionField *fie
{
MonoError error;
MonoType *type = mono_field_get_type_checked (field->field, &error);
- if (!mono_error_ok (&error))
- mono_error_raise_exception (&error);
+ mono_error_raise_exception (&error);
return type_array_from_modifiers (field->field->parent->image, type, optional);
}
@@ -5161,21 +5161,16 @@ mono_module_get_types (MonoDomain *domain, MonoImage *image, MonoArray **excepti
attrs = mono_metadata_decode_row_col (tdef, i, MONO_TYPEDEF_FLAGS);
visibility = attrs & TYPE_ATTRIBUTE_VISIBILITY_MASK;
if (!exportedOnly || (visibility == TYPE_ATTRIBUTE_PUBLIC || visibility == TYPE_ATTRIBUTE_NESTED_PUBLIC)) {
- klass = mono_class_get (image, (i + 1) | MONO_TOKEN_TYPE_DEF);
+ MonoError error;
+ klass = mono_class_get_checked (image, (i + 1) | MONO_TOKEN_TYPE_DEF, &error);
+ g_assert (!mono_loader_get_last_error ()); /* Plug any leaks */
+
if (klass) {
mono_array_setref (res, count, mono_type_get_object (domain, &klass->byval_arg));
} else {
- MonoLoaderError *error;
- MonoException *ex;
-
- error = mono_loader_get_last_error ();
- g_assert (error != NULL);
-
- ex = mono_loader_error_prepare_exception (error);
+ MonoException *ex = mono_error_convert_to_exception (&error);
mono_array_setref (*exceptions, count, ex);
}
- if (mono_loader_get_last_error ())
- mono_loader_clear_error ();
count++;
}
}
@@ -5266,7 +5261,7 @@ ves_icall_System_Reflection_Assembly_GetTypes (MonoReflectionAssembly *assembly,
mono_loader_clear_error ();
exl = mono_array_new (domain, mono_defaults.exception_class, length);
- /* Types for which mono_class_get () succeeded */
+ /* Types for which mono_class_get_checked () succeeded */
for (i = 0, tmp = list; tmp; i++, tmp = tmp->next) {
MonoException *exc = mono_class_get_exception_for_failure (tmp->data);
mono_array_setref (exl, i, exc);
@@ -5321,6 +5316,7 @@ ves_icall_System_Reflection_AssemblyName_ParseName (MonoReflectionAssemblyName *
ICALL_EXPORT MonoReflectionType*
ves_icall_System_Reflection_Module_GetGlobalType (MonoReflectionModule *module)
{
+ MonoError error;
MonoDomain *domain = mono_object_domain (module);
MonoClass *klass;
@@ -5332,7 +5328,8 @@ ves_icall_System_Reflection_Module_GetGlobalType (MonoReflectionModule *module)
/* These images do not have a global type */
return NULL;
- klass = mono_class_get (module->image, 1 | MONO_TOKEN_TYPE_DEF);
+ klass = mono_class_get_checked (module->image, 1 | MONO_TOKEN_TYPE_DEF, &error);
+ mono_error_raise_exception (&error);
return mono_type_get_object (domain, &klass->byval_arg);
}
@@ -5442,19 +5439,20 @@ init_generic_context_from_args (MonoGenericContext *context, MonoArray *type_arg
}
ICALL_EXPORT MonoType*
-ves_icall_System_Reflection_Module_ResolveTypeToken (MonoImage *image, guint32 token, MonoArray *type_args, MonoArray *method_args, MonoResolveTokenError *error)
+ves_icall_System_Reflection_Module_ResolveTypeToken (MonoImage *image, guint32 token, MonoArray *type_args, MonoArray *method_args, MonoResolveTokenError *resolve_error)
{
MonoClass *klass;
int table = mono_metadata_token_table (token);
int index = mono_metadata_token_index (token);
MonoGenericContext context;
+ MonoError error;
- *error = ResolveTokenError_Other;
+ *resolve_error = ResolveTokenError_Other;
/* Validate token */
if ((table != MONO_TABLE_TYPEDEF) && (table != MONO_TABLE_TYPEREF) &&
(table != MONO_TABLE_TYPESPEC)) {
- *error = ResolveTokenError_BadTable;
+ *resolve_error = ResolveTokenError_BadTable;
return NULL;
}
@@ -5470,15 +5468,15 @@ ves_icall_System_Reflection_Module_ResolveTypeToken (MonoImage *image, guint32 t
}
if ((index <= 0) || (index > image->tables [table].rows)) {
- *error = ResolveTokenError_OutOfRange;
+ *resolve_error = ResolveTokenError_OutOfRange;
return NULL;
}
init_generic_context_from_args (&context, type_args, method_args);
- klass = mono_class_get_full (image, token, &context);
-
- if (mono_loader_get_last_error ())
- mono_raise_exception (mono_loader_error_prepare_exception (mono_loader_get_last_error ()));
+ klass = mono_class_get_checked (image, token, &error);
+ if (klass)
+ klass = mono_class_inflate_generic_class_checked (klass, &context, &error);
+ mono_error_raise_exception (&error);
if (klass)
return &klass->byval_arg;
@@ -7415,6 +7413,8 @@ ves_icall_System_Char_GetDataTablePointers (int category_data_version,
/*
* We return NULL for no modifiers so the corlib code can return Type.EmptyTypes
* and avoid useless allocations.
+ *
+ * MAY THROW
*/
static MonoArray*
type_array_from_modifiers (MonoImage *image, MonoType *type, int optional)
@@ -7431,7 +7431,9 @@ type_array_from_modifiers (MonoImage *image, MonoType *type, int optional)
count = 0;
for (i = 0; i < type->num_mods; ++i) {
if ((optional && !type->modifiers [i].required) || (!optional && type->modifiers [i].required)) {
- MonoClass *klass = mono_class_get (image, type->modifiers [i].token);
+ MonoError error;
+ MonoClass *klass = mono_class_get_checked (image, type->modifiers [i].token, &error);
+ mono_error_raise_exception (&error); /* this is safe, no cleanup needed on callers */
mono_array_setref (res, count, mono_type_get_object (mono_domain_get (), &klass->byval_arg));
count++;
}
diff --git a/mono/metadata/jit-info.c b/mono/metadata/jit-info.c
new file mode 100644
index 00000000000..cc0b76622fb
--- /dev/null
+++ b/mono/metadata/jit-info.c
@@ -0,0 +1,946 @@
+/*
+ * jit-info.c: MonoJitInfo functionality
+ *
+ * Author:
+ * Dietmar Maurer (dietmar@ximian.com)
+ * Patrik Torstensson
+ *
+ * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
+ * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Copyright 2011-2012 Xamarin, Inc (http://www.xamarin.com)
+ */
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static MonoJitInfoFindInAot jit_info_find_in_aot_func = NULL;
+
+#define JIT_INFO_TABLE_FILL_RATIO_NOM 3
+#define JIT_INFO_TABLE_FILL_RATIO_DENOM 4
+#define JIT_INFO_TABLE_FILLED_NUM_ELEMENTS (MONO_JIT_INFO_TABLE_CHUNK_SIZE * JIT_INFO_TABLE_FILL_RATIO_NOM / JIT_INFO_TABLE_FILL_RATIO_DENOM)
+
+#define JIT_INFO_TABLE_LOW_WATERMARK(n) ((n) / 2)
+#define JIT_INFO_TABLE_HIGH_WATERMARK(n) ((n) * 5 / 6)
+
+#define JIT_INFO_TOMBSTONE_MARKER ((MonoMethod*)NULL)
+#define IS_JIT_INFO_TOMBSTONE(ji) ((ji)->d.method == JIT_INFO_TOMBSTONE_MARKER)
+
+#define JIT_INFO_TABLE_HAZARD_INDEX 0
+#define JIT_INFO_HAZARD_INDEX 1
+
+static int
+jit_info_table_num_elements (MonoJitInfoTable *table)
+{
+ int i;
+ int num_elements = 0;
+
+ for (i = 0; i < table->num_chunks; ++i) {
+ MonoJitInfoTableChunk *chunk = table->chunks [i];
+ int chunk_num_elements = chunk->num_elements;
+ int j;
+
+ for (j = 0; j < chunk_num_elements; ++j) {
+ if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j]))
+ ++num_elements;
+ }
+ }
+
+ return num_elements;
+}
+
+static MonoJitInfoTableChunk*
+jit_info_table_new_chunk (void)
+{
+ MonoJitInfoTableChunk *chunk = g_new0 (MonoJitInfoTableChunk, 1);
+ chunk->refcount = 1;
+
+ return chunk;
+}
+
+MonoJitInfoTable *
+mono_jit_info_table_new (MonoDomain *domain)
+{
+ MonoJitInfoTable *table = g_malloc0 (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*));
+
+ table->domain = domain;
+ table->num_chunks = 1;
+ table->chunks [0] = jit_info_table_new_chunk ();
+
+ return table;
+}
+
+void
+mono_jit_info_table_free (MonoJitInfoTable *table)
+{
+ int i;
+ int num_chunks = table->num_chunks;
+ MonoDomain *domain = table->domain;
+
+ mono_domain_lock (domain);
+
+ table->domain->num_jit_info_tables--;
+ if (table->domain->num_jit_info_tables <= 1) {
+ GSList *list;
+
+ for (list = table->domain->jit_info_free_queue; list; list = list->next)
+ g_free (list->data);
+
+ g_slist_free (table->domain->jit_info_free_queue);
+ table->domain->jit_info_free_queue = NULL;
+ }
+
+ /* At this point we assume that there are no other threads
+ still accessing the table, so we don't have to worry about
+ hazardous pointers. */
+
+ for (i = 0; i < num_chunks; ++i) {
+ MonoJitInfoTableChunk *chunk = table->chunks [i];
+ int num_elements;
+ int j;
+
+ if (--chunk->refcount > 0)
+ continue;
+
+ num_elements = chunk->num_elements;
+ for (j = 0; j < num_elements; ++j) {
+ MonoJitInfo *ji = chunk->data [j];
+
+ if (IS_JIT_INFO_TOMBSTONE (ji))
+ g_free (ji);
+ }
+
+ g_free (chunk);
+ }
+
+ mono_domain_unlock (domain);
+
+ g_free (table);
+}
+
+/* The jit_info_table is sorted in ascending order by the end
+ * addresses of the compiled methods. The reason why we have to do
+ * this is that once we introduce tombstones, it becomes possible for
+ * code ranges to overlap, and if we sort by code start and insert at
+ * the back of the table, we cannot guarantee that we won't overlook
+ * an entry.
+ *
+ * There are actually two possible ways to do the sorting and
+ * inserting which work with our lock-free mechanism:
+ *
+ * 1. Sort by start address and insert at the front. When looking for
+ * an entry, find the last one with a start address lower than the one
+ * you're looking for, then work your way to the front of the table.
+ *
+ * 2. Sort by end address and insert at the back. When looking for an
+ * entry, find the first one with an end address higher than the one
+ * you're looking for, then work your way to the end of the table.
+ *
+ * We chose the latter out of convenience.
+ */
+static int
+jit_info_table_index (MonoJitInfoTable *table, gint8 *addr)
+{
+ int left = 0, right = table->num_chunks;
+
+ g_assert (left < right);
+
+ do {
+ int pos = (left + right) / 2;
+ MonoJitInfoTableChunk *chunk = table->chunks [pos];
+
+ if (addr < chunk->last_code_end)
+ right = pos;
+ else
+ left = pos + 1;
+ } while (left < right);
+ g_assert (left == right);
+
+ if (left >= table->num_chunks)
+ return table->num_chunks - 1;
+ return left;
+}
+
+static int
+jit_info_table_chunk_index (MonoJitInfoTableChunk *chunk, MonoThreadHazardPointers *hp, gint8 *addr)
+{
+ int left = 0, right = chunk->num_elements;
+
+ while (left < right) {
+ int pos = (left + right) / 2;
+ MonoJitInfo *ji = 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)
+ right = pos;
+ else
+ left = pos + 1;
+ }
+ g_assert (left == right);
+
+ return left;
+}
+
+static MonoJitInfo*
+jit_info_table_find (MonoJitInfoTable *table, MonoThreadHazardPointers *hp, gint8 *addr)
+{
+ MonoJitInfo *ji;
+ int chunk_pos, pos;
+
+ chunk_pos = jit_info_table_index (table, (gint8*)addr);
+ g_assert (chunk_pos < table->num_chunks);
+
+ pos = jit_info_table_chunk_index (table->chunks [chunk_pos], hp, (gint8*)addr);
+
+ /* We now have a position that's very close to that of the
+ first element whose end address is higher than the one
+ we're looking for. If we don't have the exact position,
+ then we have a position below that one, so we'll just
+ search upward until we find our element. */
+ do {
+ MonoJitInfoTableChunk *chunk = table->chunks [chunk_pos];
+
+ while (pos < chunk->num_elements) {
+ ji = get_hazardous_pointer ((gpointer volatile*)&chunk->data [pos], hp, JIT_INFO_HAZARD_INDEX);
+
+ ++pos;
+
+ if (IS_JIT_INFO_TOMBSTONE (ji)) {
+ mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
+ continue;
+ }
+ if ((gint8*)addr >= (gint8*)ji->code_start
+ && (gint8*)addr < (gint8*)ji->code_start + ji->code_size) {
+ mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
+ return ji;
+ }
+
+ /* If we find a non-tombstone element which is already
+ beyond what we're looking for, we have to end the
+ search. */
+ if ((gint8*)addr < (gint8*)ji->code_start)
+ goto not_found;
+ }
+
+ ++chunk_pos;
+ pos = 0;
+ } while (chunk_pos < table->num_chunks);
+
+ not_found:
+ if (hp)
+ mono_hazard_pointer_clear (hp, JIT_INFO_HAZARD_INDEX);
+ return NULL;
+}
+
+/*
+ * mono_jit_info_table_find_internal:
+ *
+ * If TRY_AOT is FALSE, avoid loading information for missing methods from AOT images, which is currently not async safe.
+ * In this case, only those AOT methods will be found whose jit info is already loaded.
+ * ASYNC SAFETY: When called in an async context (mono_thread_info_is_async_context ()), this is async safe.
+ * In this case, the returned MonoJitInfo might not have metadata information, in particular,
+ * mono_jit_info_get_method () could fail.
+ */
+MonoJitInfo*
+mono_jit_info_table_find_internal (MonoDomain *domain, char *addr, gboolean try_aot)
+{
+ MonoJitInfoTable *table;
+ MonoJitInfo *ji, *module_ji;
+ MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
+
+ ++mono_stats.jit_info_table_lookup_count;
+
+ /* First we have to get the domain's jit_info_table. This is
+ complicated by the fact that a writer might substitute a
+ new table and free the old one. What the writer guarantees
+ us is that it looks at the hazard pointers after it has
+ changed the jit_info_table pointer. So, if we guard the
+ 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 = 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)
+ mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
+ if (ji)
+ return ji;
+
+ /* Maybe its an AOT module */
+ if (try_aot && mono_get_root_domain () && mono_get_root_domain ()->aot_modules) {
+ table = 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);
+ if (hp)
+ mono_hazard_pointer_clear (hp, JIT_INFO_TABLE_HAZARD_INDEX);
+ }
+
+ return ji;
+}
+
+MonoJitInfo*
+mono_jit_info_table_find (MonoDomain *domain, char *addr)
+{
+ return mono_jit_info_table_find_internal (domain, addr, TRUE);
+}
+
+static G_GNUC_UNUSED void
+jit_info_table_check (MonoJitInfoTable *table)
+{
+ int i;
+
+ for (i = 0; i < table->num_chunks; ++i) {
+ MonoJitInfoTableChunk *chunk = table->chunks [i];
+ int j;
+
+ g_assert (chunk->refcount > 0 /* && chunk->refcount <= 8 */);
+ if (chunk->refcount > 10)
+ printf("warning: chunk refcount is %d\n", chunk->refcount);
+ g_assert (chunk->num_elements <= MONO_JIT_INFO_TABLE_CHUNK_SIZE);
+
+ for (j = 0; j < chunk->num_elements; ++j) {
+ MonoJitInfo *this = chunk->data [j];
+ MonoJitInfo *next;
+
+ g_assert ((gint8*)this->code_start + this->code_size <= chunk->last_code_end);
+
+ if (j < chunk->num_elements - 1)
+ next = chunk->data [j + 1];
+ else if (i < table->num_chunks - 1) {
+ int k;
+
+ for (k = i + 1; k < table->num_chunks; ++k)
+ if (table->chunks [k]->num_elements > 0)
+ break;
+
+ if (k >= table->num_chunks)
+ return;
+
+ g_assert (table->chunks [k]->num_elements > 0);
+ next = table->chunks [k]->data [0];
+ } else
+ return;
+
+ g_assert ((gint8*)this->code_start + this->code_size <= (gint8*)next->code_start + next->code_size);
+ }
+ }
+}
+
+static MonoJitInfoTable*
+jit_info_table_realloc (MonoJitInfoTable *old)
+{
+ int i;
+ int num_elements = jit_info_table_num_elements (old);
+ int required_size;
+ int num_chunks;
+ int new_chunk, new_element;
+ MonoJitInfoTable *new;
+
+ /* number of needed places for elements needed */
+ required_size = (int)((long)num_elements * JIT_INFO_TABLE_FILL_RATIO_DENOM / JIT_INFO_TABLE_FILL_RATIO_NOM);
+ num_chunks = (required_size + MONO_JIT_INFO_TABLE_CHUNK_SIZE - 1) / MONO_JIT_INFO_TABLE_CHUNK_SIZE;
+ if (num_chunks == 0) {
+ g_assert (num_elements == 0);
+ return mono_jit_info_table_new (old->domain);
+ }
+ g_assert (num_chunks > 0);
+
+ new = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE + sizeof (MonoJitInfoTableChunk*) * num_chunks);
+ new->domain = old->domain;
+ new->num_chunks = num_chunks;
+
+ for (i = 0; i < num_chunks; ++i)
+ new->chunks [i] = jit_info_table_new_chunk ();
+
+ new_chunk = 0;
+ new_element = 0;
+ for (i = 0; i < old->num_chunks; ++i) {
+ MonoJitInfoTableChunk *chunk = old->chunks [i];
+ int chunk_num_elements = chunk->num_elements;
+ int j;
+
+ for (j = 0; j < chunk_num_elements; ++j) {
+ if (!IS_JIT_INFO_TOMBSTONE (chunk->data [j])) {
+ g_assert (new_chunk < num_chunks);
+ new->chunks [new_chunk]->data [new_element] = chunk->data [j];
+ if (++new_element >= JIT_INFO_TABLE_FILLED_NUM_ELEMENTS) {
+ new->chunks [new_chunk]->num_elements = new_element;
+ ++new_chunk;
+ new_element = 0;
+ }
+ }
+ }
+ }
+
+ if (new_chunk < num_chunks) {
+ g_assert (new_chunk == num_chunks - 1);
+ new->chunks [new_chunk]->num_elements = new_element;
+ g_assert (new->chunks [new_chunk]->num_elements > 0);
+ }
+
+ for (i = 0; i < num_chunks; ++i) {
+ MonoJitInfoTableChunk *chunk = new->chunks [i];
+ MonoJitInfo *ji = chunk->data [chunk->num_elements - 1];
+
+ new->chunks [i]->last_code_end = (gint8*)ji->code_start + ji->code_size;
+ }
+
+ return new;
+}
+
+static void
+jit_info_table_split_chunk (MonoJitInfoTableChunk *chunk, MonoJitInfoTableChunk **new1p, MonoJitInfoTableChunk **new2p)
+{
+ MonoJitInfoTableChunk *new1 = jit_info_table_new_chunk ();
+ MonoJitInfoTableChunk *new2 = jit_info_table_new_chunk ();
+
+ g_assert (chunk->num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE);
+
+ new1->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE / 2;
+ new2->num_elements = MONO_JIT_INFO_TABLE_CHUNK_SIZE - new1->num_elements;
+
+ memcpy ((void*)new1->data, (void*)chunk->data, sizeof (MonoJitInfo*) * new1->num_elements);
+ memcpy ((void*)new2->data, (void*)(chunk->data + new1->num_elements), sizeof (MonoJitInfo*) * new2->num_elements);
+
+ new1->last_code_end = (gint8*)new1->data [new1->num_elements - 1]->code_start
+ + new1->data [new1->num_elements - 1]->code_size;
+ new2->last_code_end = (gint8*)new2->data [new2->num_elements - 1]->code_start
+ + new2->data [new2->num_elements - 1]->code_size;
+
+ *new1p = new1;
+ *new2p = new2;
+}
+
+static MonoJitInfoTable*
+jit_info_table_copy_and_split_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
+{
+ MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
+ + sizeof (MonoJitInfoTableChunk*) * (table->num_chunks + 1));
+ int i, j;
+
+ new_table->domain = table->domain;
+ new_table->num_chunks = table->num_chunks + 1;
+
+ j = 0;
+ for (i = 0; i < table->num_chunks; ++i) {
+ if (table->chunks [i] == chunk) {
+ jit_info_table_split_chunk (chunk, &new_table->chunks [j], &new_table->chunks [j + 1]);
+ j += 2;
+ } else {
+ new_table->chunks [j] = table->chunks [i];
+ ++new_table->chunks [j]->refcount;
+ ++j;
+ }
+ }
+
+ g_assert (j == new_table->num_chunks);
+
+ return new_table;
+}
+
+static MonoJitInfoTableChunk*
+jit_info_table_purify_chunk (MonoJitInfoTableChunk *old)
+{
+ MonoJitInfoTableChunk *new = jit_info_table_new_chunk ();
+ int i, j;
+
+ j = 0;
+ for (i = 0; i < old->num_elements; ++i) {
+ if (!IS_JIT_INFO_TOMBSTONE (old->data [i]))
+ new->data [j++] = old->data [i];
+ }
+
+ new->num_elements = j;
+ if (new->num_elements > 0)
+ new->last_code_end = (gint8*)new->data [j - 1]->code_start + new->data [j - 1]->code_size;
+ else
+ new->last_code_end = old->last_code_end;
+
+ return new;
+}
+
+static MonoJitInfoTable*
+jit_info_table_copy_and_purify_chunk (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
+{
+ MonoJitInfoTable *new_table = g_malloc (MONO_SIZEOF_JIT_INFO_TABLE
+ + sizeof (MonoJitInfoTableChunk*) * table->num_chunks);
+ int i, j;
+
+ new_table->domain = table->domain;
+ new_table->num_chunks = table->num_chunks;
+
+ j = 0;
+ for (i = 0; i < table->num_chunks; ++i) {
+ if (table->chunks [i] == chunk)
+ new_table->chunks [j++] = jit_info_table_purify_chunk (table->chunks [i]);
+ else {
+ new_table->chunks [j] = table->chunks [i];
+ ++new_table->chunks [j]->refcount;
+ ++j;
+ }
+ }
+
+ g_assert (j == new_table->num_chunks);
+
+ return new_table;
+}
+
+/* As we add an element to the table the case can arise that the chunk
+ * to which we need to add is already full. In that case we have to
+ * allocate a new table and do something about that chunk. We have
+ * several strategies:
+ *
+ * If the number of elements in the table is below the low watermark
+ * or above the high watermark, we reallocate the whole table.
+ * Otherwise we only concern ourselves with the overflowing chunk:
+ *
+ * If there are no tombstones in the chunk then we split the chunk in
+ * two, each half full.
+ *
+ * If the chunk does contain tombstones, we just make a new copy of
+ * the chunk without the tombstones, which will have room for at least
+ * the one element we have to add.
+ */
+static MonoJitInfoTable*
+jit_info_table_chunk_overflow (MonoJitInfoTable *table, MonoJitInfoTableChunk *chunk)
+{
+ int num_elements = jit_info_table_num_elements (table);
+ int i;
+
+ if (num_elements < JIT_INFO_TABLE_LOW_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)
+ || num_elements > JIT_INFO_TABLE_HIGH_WATERMARK (table->num_chunks * MONO_JIT_INFO_TABLE_CHUNK_SIZE)) {
+ //printf ("reallocing table\n");
+ return jit_info_table_realloc (table);
+ }
+
+ /* count the number of non-tombstone elements in the chunk */
+ num_elements = 0;
+ for (i = 0; i < chunk->num_elements; ++i) {
+ if (!IS_JIT_INFO_TOMBSTONE (chunk->data [i]))
+ ++num_elements;
+ }
+
+ if (num_elements == MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
+ //printf ("splitting chunk\n");
+ return jit_info_table_copy_and_split_chunk (table, chunk);
+ }
+
+ //printf ("purifying chunk\n");
+ return jit_info_table_copy_and_purify_chunk (table, chunk);
+}
+
+/* We add elements to the table by first making space for them by
+ * shifting the elements at the back to the right, one at a time.
+ * This results in duplicate entries during the process, but during
+ * all the time the table is in a sorted state. Also, when an element
+ * is replaced by another one, the element that replaces it has an end
+ * address that is equal to or lower than that of the replaced
+ * element. That property is necessary to guarantee that when
+ * searching for an element we end up at a position not higher than
+ * the one we're looking for (i.e. we either find the element directly
+ * or we end up to the left of it).
+ */
+static void
+jit_info_table_add (MonoDomain *domain, MonoJitInfoTable *volatile *table_ptr, MonoJitInfo *ji)
+{
+ MonoJitInfoTable *table;
+ MonoJitInfoTableChunk *chunk;
+ int chunk_pos, pos;
+ int num_elements;
+ int i;
+
+ table = *table_ptr;
+
+ restart:
+ chunk_pos = jit_info_table_index (table, (gint8*)ji->code_start + ji->code_size);
+ g_assert (chunk_pos < table->num_chunks);
+ chunk = table->chunks [chunk_pos];
+
+ if (chunk->num_elements >= MONO_JIT_INFO_TABLE_CHUNK_SIZE) {
+ MonoJitInfoTable *new_table = jit_info_table_chunk_overflow (table, chunk);
+
+ /* Debugging code, should be removed. */
+ //jit_info_table_check (new_table);
+
+ *table_ptr = new_table;
+ mono_memory_barrier ();
+ domain->num_jit_info_tables++;
+ mono_thread_hazardous_free_or_queue (table, (MonoHazardousFreeFunc)mono_jit_info_table_free, TRUE, FALSE);
+ table = new_table;
+
+ goto restart;
+ }
+
+ /* Debugging code, should be removed. */
+ //jit_info_table_check (table);
+
+ num_elements = chunk->num_elements;
+
+ pos = jit_info_table_chunk_index (chunk, NULL, (gint8*)ji->code_start + ji->code_size);
+
+ /* First we need to size up the chunk by one, by copying the
+ last item, or inserting the first one, if the table is
+ empty. */
+ if (num_elements > 0)
+ chunk->data [num_elements] = chunk->data [num_elements - 1];
+ else
+ chunk->data [0] = ji;
+ mono_memory_write_barrier ();
+ chunk->num_elements = ++num_elements;
+
+ /* Shift the elements up one by one. */
+ for (i = num_elements - 2; i >= pos; --i) {
+ mono_memory_write_barrier ();
+ chunk->data [i + 1] = chunk->data [i];
+ }
+
+ /* Now we have room and can insert the new item. */
+ mono_memory_write_barrier ();
+ chunk->data [pos] = ji;
+
+ /* Set the high code end address chunk entry. */
+ chunk->last_code_end = (gint8*)chunk->data [chunk->num_elements - 1]->code_start
+ + chunk->data [chunk->num_elements - 1]->code_size;
+
+ /* Debugging code, should be removed. */
+ //jit_info_table_check (table);
+}
+
+void
+mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
+{
+ g_assert (ji->d.method != NULL);
+
+ mono_domain_lock (domain);
+
+ ++mono_stats.jit_info_table_insert_count;
+
+ jit_info_table_add (domain, &domain->jit_info_table, ji);
+
+ mono_domain_unlock (domain);
+}
+
+static MonoJitInfo*
+mono_jit_info_make_tombstone (MonoJitInfo *ji)
+{
+ MonoJitInfo *tombstone = g_new0 (MonoJitInfo, 1);
+
+ tombstone->code_start = ji->code_start;
+ tombstone->code_size = ji->code_size;
+ tombstone->d.method = JIT_INFO_TOMBSTONE_MARKER;
+
+ return tombstone;
+}
+
+/*
+ * LOCKING: domain lock
+ */
+static void
+mono_jit_info_free_or_queue (MonoDomain *domain, MonoJitInfo *ji)
+{
+ if (domain->num_jit_info_tables <= 1) {
+ /* Can it actually happen that we only have one table
+ but ji is still hazardous? */
+ mono_thread_hazardous_free_or_queue (ji, g_free, TRUE, FALSE);
+ } else {
+ domain->jit_info_free_queue = g_slist_prepend (domain->jit_info_free_queue, ji);
+ }
+}
+
+static void
+jit_info_table_remove (MonoJitInfoTable *table, MonoJitInfo *ji)
+{
+ MonoJitInfoTableChunk *chunk;
+ gpointer start = ji->code_start;
+ int chunk_pos, pos;
+
+ chunk_pos = jit_info_table_index (table, start);
+ g_assert (chunk_pos < table->num_chunks);
+
+ pos = jit_info_table_chunk_index (table->chunks [chunk_pos], NULL, start);
+
+ do {
+ chunk = table->chunks [chunk_pos];
+
+ while (pos < chunk->num_elements) {
+ if (chunk->data [pos] == ji)
+ goto found;
+
+ g_assert (IS_JIT_INFO_TOMBSTONE (chunk->data [pos]));
+ g_assert ((guint8*)chunk->data [pos]->code_start + chunk->data [pos]->code_size
+ <= (guint8*)ji->code_start + ji->code_size);
+
+ ++pos;
+ }
+
+ ++chunk_pos;
+ pos = 0;
+ } while (chunk_pos < table->num_chunks);
+
+ found:
+ g_assert (chunk->data [pos] == ji);
+
+ chunk->data [pos] = mono_jit_info_make_tombstone (ji);
+
+ /* Debugging code, should be removed. */
+ //jit_info_table_check (table);
+}
+
+void
+mono_jit_info_table_remove (MonoDomain *domain, MonoJitInfo *ji)
+{
+ MonoJitInfoTable *table;
+
+ mono_domain_lock (domain);
+ table = domain->jit_info_table;
+
+ ++mono_stats.jit_info_table_remove_count;
+
+ jit_info_table_remove (table, ji);
+
+ mono_jit_info_free_or_queue (domain, ji);
+
+ mono_domain_unlock (domain);
+}
+
+void
+mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end)
+{
+ MonoJitInfo *ji;
+ MonoDomain *domain = mono_get_root_domain ();
+
+ g_assert (domain);
+ mono_domain_lock (domain);
+
+ /*
+ * We reuse MonoJitInfoTable to store AOT module info,
+ * this gives us async-safe lookup.
+ */
+ if (!domain->aot_modules) {
+ domain->num_jit_info_tables ++;
+ domain->aot_modules = mono_jit_info_table_new (domain);
+ }
+
+ ji = g_new0 (MonoJitInfo, 1);
+ ji->d.image = image;
+ ji->code_start = start;
+ ji->code_size = (guint8*)end - (guint8*)start;
+ jit_info_table_add (domain, &domain->aot_modules, ji);
+
+ mono_domain_unlock (domain);
+}
+
+void
+mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func)
+{
+ jit_info_find_in_aot_func = func;
+}
+
+int
+mono_jit_info_size (MonoJitInfoFlags flags, int num_clauses, int num_holes)
+{
+ int size = MONO_SIZEOF_JIT_INFO;
+
+ size += num_clauses * sizeof (MonoJitExceptionInfo);
+ if (flags & JIT_INFO_HAS_CAS_INFO)
+ size += sizeof (MonoMethodCasInfo);
+ if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
+ size += sizeof (MonoGenericJitInfo);
+ if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
+ size += sizeof (MonoTryBlockHoleTableJitInfo) + num_holes * sizeof (MonoTryBlockHoleJitInfo);
+ if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
+ size += sizeof (MonoArchEHJitInfo);
+ return size;
+}
+
+void
+mono_jit_info_init (MonoJitInfo *ji, MonoMethod *method, guint8 *code, int code_size,
+ MonoJitInfoFlags flags, int num_clauses, int num_holes)
+{
+ ji->d.method = method;
+ ji->code_start = code;
+ ji->code_size = code_size;
+ ji->num_clauses = num_clauses;
+ if (flags & JIT_INFO_HAS_CAS_INFO)
+ ji->has_cas_info = 1;
+ if (flags & JIT_INFO_HAS_GENERIC_JIT_INFO)
+ ji->has_generic_jit_info = 1;
+ if (flags & JIT_INFO_HAS_TRY_BLOCK_HOLES)
+ ji->has_try_block_holes = 1;
+ if (flags & JIT_INFO_HAS_ARCH_EH_INFO)
+ ji->has_arch_eh_info = 1;
+}
+
+gpointer
+mono_jit_info_get_code_start (MonoJitInfo* ji)
+{
+ return ji->code_start;
+}
+
+int
+mono_jit_info_get_code_size (MonoJitInfo* ji)
+{
+ return ji->code_size;
+}
+
+MonoMethod*
+mono_jit_info_get_method (MonoJitInfo* ji)
+{
+ g_assert (!ji->async);
+ return ji->d.method;
+}
+
+static gpointer
+jit_info_key_extract (gpointer value)
+{
+ MonoJitInfo *info = (MonoJitInfo*)value;
+
+ return info->d.method;
+}
+
+static gpointer*
+jit_info_next_value (gpointer value)
+{
+ MonoJitInfo *info = (MonoJitInfo*)value;
+
+ return (gpointer*)&info->next_jit_code_hash;
+}
+
+void
+mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash)
+{
+ mono_internal_hash_table_init (jit_code_hash,
+ mono_aligned_addr_hash,
+ jit_info_key_extract,
+ jit_info_next_value);
+}
+
+MonoGenericJitInfo*
+mono_jit_info_get_generic_jit_info (MonoJitInfo *ji)
+{
+ if (ji->has_generic_jit_info)
+ return (MonoGenericJitInfo*)&ji->clauses [ji->num_clauses];
+ else
+ return NULL;
+}
+
+/*
+ * mono_jit_info_get_generic_sharing_context:
+ * @ji: a jit info
+ *
+ * Returns the jit info's generic sharing context, or NULL if it
+ * doesn't have one.
+ */
+MonoGenericSharingContext*
+mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji)
+{
+ MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
+
+ if (gi)
+ return gi->generic_sharing_context;
+ else
+ return NULL;
+}
+
+/*
+ * mono_jit_info_set_generic_sharing_context:
+ * @ji: a jit info
+ * @gsctx: a generic sharing context
+ *
+ * Sets the jit info's generic sharing context. The jit info must
+ * have memory allocated for the context.
+ */
+void
+mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx)
+{
+ MonoGenericJitInfo *gi = mono_jit_info_get_generic_jit_info (ji);
+
+ g_assert (gi);
+
+ gi->generic_sharing_context = gsctx;
+}
+
+MonoTryBlockHoleTableJitInfo*
+mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji)
+{
+ if (ji->has_try_block_holes) {
+ char *ptr = (char*)&ji->clauses [ji->num_clauses];
+ if (ji->has_generic_jit_info)
+ ptr += sizeof (MonoGenericJitInfo);
+ return (MonoTryBlockHoleTableJitInfo*)ptr;
+ } else {
+ return NULL;
+ }
+}
+
+static int
+try_block_hole_table_size (MonoJitInfo *ji)
+{
+ MonoTryBlockHoleTableJitInfo *table;
+
+ table = mono_jit_info_get_try_block_hole_table_info (ji);
+ g_assert (table);
+ return sizeof (MonoTryBlockHoleTableJitInfo) + table->num_holes * sizeof (MonoTryBlockHoleJitInfo);
+}
+
+MonoArchEHJitInfo*
+mono_jit_info_get_arch_eh_info (MonoJitInfo *ji)
+{
+ if (ji->has_arch_eh_info) {
+ char *ptr = (char*)&ji->clauses [ji->num_clauses];
+ if (ji->has_generic_jit_info)
+ ptr += sizeof (MonoGenericJitInfo);
+ if (ji->has_try_block_holes)
+ ptr += try_block_hole_table_size (ji);
+ return (MonoArchEHJitInfo*)ptr;
+ } else {
+ return NULL;
+ }
+}
+
+MonoMethodCasInfo*
+mono_jit_info_get_cas_info (MonoJitInfo *ji)
+{
+ if (ji->has_cas_info) {
+ char *ptr = (char*)&ji->clauses [ji->num_clauses];
+ if (ji->has_generic_jit_info)
+ ptr += sizeof (MonoGenericJitInfo);
+ if (ji->has_try_block_holes)
+ ptr += try_block_hole_table_size (ji);
+ if (ji->has_arch_eh_info)
+ ptr += sizeof (MonoArchEHJitInfo);
+ return (MonoMethodCasInfo*)ptr;
+ } else {
+ return NULL;
+ }
+}
diff --git a/mono/metadata/loader.c b/mono/metadata/loader.c
index 7cbc0810c00..f7dc1497a01 100644
--- a/mono/metadata/loader.c
+++ b/mono/metadata/loader.c
@@ -395,9 +395,9 @@ find_cached_memberref_sig (MonoImage *image, guint32 sig_idx)
{
gpointer res;
- mono_loader_lock ();
+ mono_image_lock (image);
res = g_hash_table_lookup (image->memberref_signatures, GUINT_TO_POINTER (sig_idx));
- mono_loader_unlock ();
+ mono_image_unlock (image);
return res;
}
@@ -407,7 +407,7 @@ cache_memberref_sig (MonoImage *image, guint32 sig_idx, gpointer sig)
{
gpointer prev_sig;
- mono_loader_lock ();
+ mono_image_lock (image);
prev_sig = g_hash_table_lookup (image->memberref_signatures, GUINT_TO_POINTER (sig_idx));
if (prev_sig) {
/* Somebody got in before us */
@@ -418,8 +418,7 @@ cache_memberref_sig (MonoImage *image, guint32 sig_idx, gpointer sig)
/* An approximation based on glib 2.18 */
memberref_sig_cache_size += sizeof (gpointer) * 4;
}
-
- mono_loader_unlock ();
+ mono_image_unlock (image);
return sig;
}
@@ -437,6 +436,7 @@ field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass,
const char *fname;
const char *ptr;
guint32 idx = mono_metadata_token_index (token);
+ MonoError error;
mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], idx-1, cols, MONO_MEMBERREF_SIZE);
nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
@@ -452,15 +452,29 @@ field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass,
switch (class) {
case MONO_MEMBERREF_PARENT_TYPEDEF:
class_table = MONO_TOKEN_TYPE_DEF;
- klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | nindex);
+ klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | nindex, &error);
+ if (!mono_error_ok (&error)) {
+ /*FIXME don't swallow the error message*/
+ mono_error_cleanup (&error);
+ }
+
break;
case MONO_MEMBERREF_PARENT_TYPEREF:
class_table = MONO_TOKEN_TYPE_REF;
- klass = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | nindex);
+ klass = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | nindex, &error);
+ if (!mono_error_ok (&error)) {
+ /*FIXME don't swallow the error message*/
+ mono_error_cleanup (&error);
+ }
+
break;
case MONO_MEMBERREF_PARENT_TYPESPEC:
class_table = MONO_TOKEN_TYPE_SPEC;
- klass = mono_class_get_full (image, MONO_TOKEN_TYPE_SPEC | nindex, context);
+ klass = mono_class_get_and_inflate_typespec_checked (image, MONO_TOKEN_TYPE_SPEC | nindex, context, &error);
+ if (!mono_error_ok (&error)) {
+ /*FIXME don't swallow the error message*/
+ mono_error_cleanup (&error);
+ }
break;
default:
/*FIXME this must set a loader error!*/
@@ -513,6 +527,7 @@ MonoClassField*
mono_field_from_token (MonoImage *image, guint32 token, MonoClass **retklass,
MonoGenericContext *context)
{
+ MonoError error;
MonoClass *k;
guint32 type;
MonoClassField *field;
@@ -543,9 +558,12 @@ mono_field_from_token (MonoImage *image, guint32 token, MonoClass **retklass,
type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
if (!type)
return NULL;
- k = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
- if (!k)
+ k = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | type, &error);
+ if (!k) {
+ mono_loader_set_error_from_mono_error (&error);
+ mono_error_cleanup (&error); /*FIXME don't swallow the error message*/
return NULL;
+ }
mono_class_init (k);
if (retklass)
*retklass = k;
@@ -941,6 +959,7 @@ method_from_memberref (MonoImage *image, guint32 idx, MonoGenericContext *typesp
const char *mname;
MonoMethodSignature *sig;
const char *ptr;
+ MonoError error;
mono_metadata_decode_row (&tables [MONO_TABLE_MEMBERREF], idx-1, cols, 3);
nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
@@ -960,12 +979,10 @@ method_from_memberref (MonoImage *image, guint32 idx, MonoGenericContext *typesp
switch (class) {
case MONO_MEMBERREF_PARENT_TYPEREF:
- klass = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | nindex);
+ klass = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | nindex, &error);
if (!klass) {
- char *name = mono_class_name_from_token (image, MONO_TOKEN_TYPE_REF | nindex);
- g_warning ("Missing method %s in assembly %s, type %s", mname, image->name, name);
- mono_loader_set_error_type_load (name, image->assembly_name);
- g_free (name);
+ mono_loader_set_error_from_mono_error (&error);
+ mono_error_cleanup (&error); /* FIXME Don't swallow the error */
return NULL;
}
break;
@@ -973,22 +990,18 @@ method_from_memberref (MonoImage *image, guint32 idx, MonoGenericContext *typesp
/*
* Parse the TYPESPEC in the parent's context.
*/
- klass = mono_class_get_full (image, MONO_TOKEN_TYPE_SPEC | nindex, typespec_context);
+ klass = mono_class_get_and_inflate_typespec_checked (image, MONO_TOKEN_TYPE_SPEC | nindex, typespec_context, &error);
if (!klass) {
- char *name = mono_class_name_from_token (image, MONO_TOKEN_TYPE_SPEC | nindex);
- g_warning ("Missing method %s in assembly %s, type %s", mname, image->name, name);
- mono_loader_set_error_type_load (name, image->assembly_name);
- g_free (name);
+ mono_loader_set_error_from_mono_error (&error);
+ mono_error_cleanup (&error); /*FIXME don't swallow the error message*/
return NULL;
}
break;
case MONO_MEMBERREF_PARENT_TYPEDEF:
- klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | nindex);
+ klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | nindex, &error);
if (!klass) {
- char *name = mono_class_name_from_token (image, MONO_TOKEN_TYPE_DEF | nindex);
- g_warning ("Missing method %s in assembly %s, type %s", mname, image->name, name);
- mono_loader_set_error_type_load (name, image->assembly_name);
- g_free (name);
+ mono_loader_set_error_from_mono_error (&error);
+ mono_error_cleanup (&error); /*FIXME don't swallow the error message*/
return NULL;
}
break;
@@ -1230,27 +1243,29 @@ mono_dllmap_insert (MonoImage *assembly, const char *dll, const char *func, cons
mono_loader_init ();
- mono_loader_lock ();
-
if (!assembly) {
entry = g_malloc0 (sizeof (MonoDllMap));
entry->dll = dll? g_strdup (dll): NULL;
entry->target = tdll? g_strdup (tdll): NULL;
entry->func = func? g_strdup (func): NULL;
entry->target_func = tfunc? g_strdup (tfunc): NULL;
+
+ mono_loader_lock ();
entry->next = global_dll_map;
global_dll_map = entry;
+ mono_loader_unlock ();
} else {
entry = mono_image_alloc0 (assembly, sizeof (MonoDllMap));
entry->dll = dll? mono_image_strdup (assembly, dll): NULL;
entry->target = tdll? mono_image_strdup (assembly, tdll): NULL;
entry->func = func? mono_image_strdup (assembly, func): NULL;
entry->target_func = tfunc? mono_image_strdup (assembly, tfunc): NULL;
+
+ mono_image_lock (assembly);
entry->next = assembly->dll_map;
assembly->dll_map = entry;
+ mono_image_unlock (assembly);
}
-
- mono_loader_unlock ();
}
static void
@@ -1369,14 +1384,14 @@ mono_lookup_pinvoke_call (MonoMethod *method, const char **exc_class, const char
mono_dllmap_lookup (image, orig_scope, import, &new_scope, &import);
if (!module) {
- mono_loader_lock ();
+ mono_image_lock (image);
if (!image->pinvoke_scopes) {
image->pinvoke_scopes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
image->pinvoke_scope_filenames = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
}
module = g_hash_table_lookup (image->pinvoke_scopes, new_scope);
found_name = g_hash_table_lookup (image->pinvoke_scope_filenames, new_scope);
- mono_loader_unlock ();
+ mono_image_unlock (image);
if (module)
cached = TRUE;
if (found_name)
@@ -1542,12 +1557,12 @@ mono_lookup_pinvoke_call (MonoMethod *method, const char **exc_class, const char
if (!cached) {
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
"DllImport loaded library '%s'.", found_name);
- mono_loader_lock ();
+ mono_image_lock (image);
if (!g_hash_table_lookup (image->pinvoke_scopes, new_scope)) {
g_hash_table_insert (image->pinvoke_scopes, g_strdup (new_scope), module);
g_hash_table_insert (image->pinvoke_scope_filenames, g_strdup (new_scope), g_strdup (found_name));
}
- mono_loader_unlock ();
+ mono_image_unlock (image);
}
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
@@ -1676,6 +1691,7 @@ static MonoMethod *
mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass,
MonoGenericContext *context, gboolean *used_context)
{
+ MonoError error;
MonoMethod *result;
int table = mono_metadata_token_table (token);
int idx = mono_metadata_token_index (token);
@@ -1717,6 +1733,18 @@ mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass,
return NULL;
}
+ if (!klass) {
+ guint32 type = mono_metadata_typedef_from_method (image, token);
+ if (!type)
+ return NULL;
+ klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | type, &error);
+ if (klass == NULL) {
+ mono_loader_set_error_from_mono_error (&error);
+ mono_error_cleanup (&error); /*FIXME don't swallow the error message*/
+ return NULL;
+ }
+ }
+
mono_metadata_decode_row (&image->tables [MONO_TABLE_METHOD], idx - 1, cols, 6);
if ((cols [2] & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
@@ -1729,15 +1757,6 @@ mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass,
mono_stats.method_count ++;
- if (!klass) { /*FIXME put this before the image alloc*/
- guint32 type = mono_metadata_typedef_from_method (image, token);
- if (!type)
- return NULL;
- klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
- if (klass == NULL)
- return NULL;
- }
-
result->slot = -1;
result->klass = klass;
result->flags = cols [2];
@@ -1758,11 +1777,15 @@ mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass,
if (*sig & 0x10)
generic_container = mono_metadata_load_generic_params (image, token, container);
if (generic_container) {
+ MonoError error;
result->is_generic = TRUE;
generic_container->owner.method = result;
/*FIXME put this before the image alloc*/
- if (!mono_metadata_load_generic_param_constraints_full (image, token, generic_container))
+ if (!mono_metadata_load_generic_param_constraints_checked (image, token, generic_container, &error)) {
+ mono_loader_set_error_from_mono_error (&error);
+ mono_error_cleanup (&error); /*FIXME don't swallow the error message*/
return NULL;
+ }
container = generic_container;
}
@@ -1917,17 +1940,11 @@ MonoMethod *
mono_get_method_constrained_with_method (MonoImage *image, MonoMethod *method, MonoClass *constrained_class,
MonoGenericContext *context)
{
- MonoMethod *result;
-
g_assert (method);
- mono_loader_lock ();
-
- result = get_method_constrained (image, method, constrained_class, context);
-
- mono_loader_unlock ();
- return result;
+ return get_method_constrained (image, method, constrained_class, context);
}
+
/**
* mono_get_method_constrained:
*
@@ -1943,17 +1960,12 @@ mono_get_method_constrained (MonoImage *image, guint32 token, MonoClass *constra
{
MonoMethod *result;
- mono_loader_lock ();
-
*cil_method = mono_get_method_from_token (image, token, NULL, context, NULL);
- if (!*cil_method) {
- mono_loader_unlock ();
+ if (!*cil_method)
return NULL;
- }
result = get_method_constrained (image, *cil_method, constrained_class, context);
- mono_loader_unlock ();
return result;
}
@@ -2266,6 +2278,18 @@ mono_stack_walk_no_il (MonoStackWalk func, gpointer user_data)
mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (stack_walk_adapter, NULL, MONO_UNWIND_DEFAULT, &ud);
}
+/*
+ * mono_stack_walk_async_safe:
+ *
+ * Async safe version callable from signal handlers.
+ */
+void
+mono_stack_walk_async_safe (MonoStackWalk func, gpointer user_data)
+{
+ StackWalkUserData ud = { func, user_data };
+ mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (stack_walk_adapter, NULL, MONO_UNWIND_NONE, &ud);
+}
+
static gboolean
last_managed (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
{
@@ -2370,7 +2394,7 @@ mono_method_signature_checked (MonoMethod *m, MonoError *error)
const char *sig;
gboolean can_cache_signature;
MonoGenericContainer *container;
- MonoMethodSignature *signature = NULL;
+ MonoMethodSignature *signature = NULL, *sig2;
guint32 sig_offset;
/* We need memory barriers below because of the double-checked locking pattern */
@@ -2380,34 +2404,31 @@ mono_method_signature_checked (MonoMethod *m, MonoError *error)
if (m->signature)
return m->signature;
- mono_loader_lock ();
-
- if (m->signature) {
- mono_loader_unlock ();
- return m->signature;
- }
+ img = m->klass->image;
if (m->is_inflated) {
MonoMethodInflated *imethod = (MonoMethodInflated *) m;
/* the lock is recursive */
signature = mono_method_signature (imethod->declaring);
signature = inflate_generic_signature_checked (imethod->declaring->klass->image, signature, mono_method_get_context (m), error);
- if (!mono_error_ok (error)) {
- mono_loader_unlock ();
+ if (!mono_error_ok (error))
return NULL;
- }
inflated_signatures_size += mono_metadata_signature_size (signature);
+ mono_image_lock (img);
+
mono_memory_barrier ();
- m->signature = signature;
- mono_loader_unlock ();
+ if (!m->signature)
+ m->signature = signature;
+
+ mono_image_unlock (img);
+
return m->signature;
}
g_assert (mono_metadata_token_table (m->token) == MONO_TABLE_METHOD);
idx = mono_metadata_token_index (m->token);
- img = m->klass->image;
sig = mono_metadata_blob_heap (img, sig_offset = mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_SIGNATURE));
@@ -2424,28 +2445,33 @@ mono_method_signature_checked (MonoMethod *m, MonoError *error)
if (mono_metadata_method_has_param_attrs (img, idx))
can_cache_signature = FALSE;
- if (can_cache_signature)
+ if (can_cache_signature) {
+ mono_image_lock (img);
signature = g_hash_table_lookup (img->method_signatures, sig);
+ mono_image_unlock (img);
+ }
if (!signature) {
const char *sig_body;
/*TODO we should cache the failure result somewhere*/
- if (!mono_verifier_verify_method_signature (img, sig_offset, error)) {
- mono_loader_unlock ();
+ if (!mono_verifier_verify_method_signature (img, sig_offset, error))
return NULL;
- }
size = mono_metadata_decode_blob_size (sig, &sig_body);
signature = mono_metadata_parse_method_signature_full (img, container, idx, sig_body, NULL);
if (!signature) {
mono_error_set_from_loader_error (error);
- mono_loader_unlock ();
return NULL;
}
- if (can_cache_signature)
- g_hash_table_insert (img->method_signatures, (gpointer)sig, signature);
+ if (can_cache_signature) {
+ mono_image_lock (img);
+ sig2 = g_hash_table_lookup (img->method_signatures, sig);
+ if (!sig2)
+ g_hash_table_insert (img->method_signatures, (gpointer)sig, signature);
+ mono_image_unlock (img);
+ }
signatures_size += mono_metadata_signature_size (signature);
}
@@ -2453,17 +2479,14 @@ mono_method_signature_checked (MonoMethod *m, MonoError *error)
/* Verify metadata consistency */
if (signature->generic_param_count) {
if (!container || !container->is_method) {
- mono_loader_unlock ();
mono_error_set_method_load (error, m->klass, m->name, "Signature claims method has generic parameters, but generic_params table says it doesn't for method 0x%08x from image %s", idx, img->name);
return NULL;
}
if (container->type_argc != signature->generic_param_count) {
- mono_loader_unlock ();
mono_error_set_method_load (error, m->klass, m->name, "Inconsistent generic parameter count. Signature says %d, generic_params table says %d for method 0x%08x from image %s", signature->generic_param_count, container->type_argc, idx, img->name);
return NULL;
}
} else if (container && container->is_method && container->type_argc) {
- mono_loader_unlock ();
mono_error_set_method_load (error, m->klass, m->name, "generic_params table claims method has generic parameters, but signature says it doesn't for method 0x%08x from image %s", idx, img->name);
return NULL;
}
@@ -2494,17 +2517,20 @@ mono_method_signature_checked (MonoMethod *m, MonoError *error)
case PINVOKE_ATTRIBUTE_CALL_CONV_GENERIC:
case PINVOKE_ATTRIBUTE_CALL_CONV_GENERICINST:
default:
- mono_loader_unlock ();
mono_error_set_method_load (error, m->klass, m->name, "unsupported calling convention : 0x%04x for method 0x%08x from image %s", piinfo->piflags, idx, img->name);
return NULL;
}
signature->call_convention = conv;
}
+ mono_image_lock (img);
+
mono_memory_barrier ();
- m->signature = signature;
+ if (!m->signature)
+ m->signature = signature;
+
+ mono_image_unlock (img);
- mono_loader_unlock ();
return m->signature;
}
@@ -2561,26 +2587,32 @@ mono_method_get_header (MonoMethod *method)
if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
return NULL;
+ img = method->klass->image;
+
if (method->is_inflated) {
MonoMethodInflated *imethod = (MonoMethodInflated *) method;
- MonoMethodHeader *header;
+ MonoMethodHeader *header, *iheader;
- mono_loader_lock ();
+ header = mono_method_get_header (imethod->declaring);
+ if (!header)
+ return NULL;
+
+ iheader = inflate_generic_header (header, mono_method_get_context (method));
+ mono_metadata_free_mh (header);
+
+ mono_image_lock (img);
if (imethod->header) {
- mono_loader_unlock ();
+ mono_metadata_free_mh (iheader);
+ mono_image_unlock (img);
return imethod->header;
}
- header = mono_method_get_header (imethod->declaring);
- if (!header) {
- mono_loader_unlock ();
- return NULL;
- }
+ mono_memory_barrier ();
+ imethod->header = iheader;
+
+ mono_image_unlock (img);
- imethod->header = inflate_generic_header (header, mono_method_get_context (method));
- mono_loader_unlock ();
- mono_metadata_free_mh (header);
return imethod->header;
}
@@ -2596,7 +2628,6 @@ mono_method_get_header (MonoMethod *method)
*/
g_assert (mono_metadata_token_table (method->token) == MONO_TABLE_METHOD);
idx = mono_metadata_token_index (method->token);
- img = method->klass->image;
rva = mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_RVA);
if (!mono_verifier_verify_method_header (img, rva, NULL))
@@ -2630,7 +2661,8 @@ mono_method_get_flags (MonoMethod *method, guint32 *iflags)
* Find the method index in the metadata methodDef table.
*/
guint32
-mono_method_get_index (MonoMethod *method) {
+mono_method_get_index (MonoMethod *method)
+{
MonoClass *klass = method->klass;
int i;
@@ -2654,4 +2686,3 @@ mono_method_get_index (MonoMethod *method) {
}
return 0;
}
-
diff --git a/mono/metadata/loader.h b/mono/metadata/loader.h
index b159dee727a..ae0ca441773 100644
--- a/mono/metadata/loader.h
+++ b/mono/metadata/loader.h
@@ -90,6 +90,9 @@ mono_stack_walk (MonoStackWalk func, void* user_data);
MONO_API void
mono_stack_walk_no_il (MonoStackWalk func, void* user_data);
+MONO_API void
+mono_stack_walk_async_safe (MonoStackWalk func, void* user_data);
+
MONO_END_DECLS
#endif
diff --git a/mono/metadata/marshal.c b/mono/metadata/marshal.c
index 88bbaeb7a02..0c8fe33f219 100644
--- a/mono/metadata/marshal.c
+++ b/mono/metadata/marshal.c
@@ -2739,6 +2739,7 @@ mono_wrapper_info_create (MonoMethodBuilder *mb, WrapperSubtype subtype)
static MonoClass*
get_wrapper_target_class (MonoImage *image)
{
+ MonoError error;
MonoClass *klass;
/*
@@ -2754,10 +2755,12 @@ get_wrapper_target_class (MonoImage *image)
* To avoid these problems, we put the wrappers into the class of
* the image.
*/
- if (image_is_dynamic (image))
+ if (image_is_dynamic (image)) {
klass = ((MonoDynamicImage*)image)->wrappers_type;
- else
- klass = mono_class_get (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, 1));
+ } else {
+ klass = mono_class_get_checked (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, 1), &error);
+ g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+ }
g_assert (klass);
return klass;
@@ -9490,8 +9493,9 @@ mono_marshal_set_callconv_from_modopt (MonoMethod *method, MonoMethodSignature *
/* Why is this a modopt ? */
if (sig->ret && sig->ret->num_mods) {
for (i = 0; i < sig->ret->num_mods; ++i) {
- MonoClass *cmod_class = mono_class_get (method->klass->image, sig->ret->modifiers [i].token);
- g_assert (cmod_class);
+ MonoError error;
+ MonoClass *cmod_class = mono_class_get_checked (method->klass->image, sig->ret->modifiers [i].token, &error);
+ g_assert (mono_error_ok (&error));
if ((cmod_class->image == mono_defaults.corlib) && !strcmp (cmod_class->name_space, "System.Runtime.CompilerServices")) {
if (!strcmp (cmod_class->name, "CallConvCdecl"))
csig->call_convention = MONO_CALL_C;
diff --git a/mono/metadata/metadata-internals.h b/mono/metadata/metadata-internals.h
index c577c64e278..c738d53654e 100644
--- a/mono/metadata/metadata-internals.h
+++ b/mono/metadata/metadata-internals.h
@@ -228,7 +228,7 @@ struct _MonoImage {
MonoConcurrentHashTable *field_cache; /*protected by the image lock*/
/* indexed by typespec tokens. */
- GHashTable *typespec_cache;
+ GHashTable *typespec_cache; /* protected by the image lock */
/* indexed by token */
GHashTable *memberref_signatures;
GHashTable *helper_signatures;
@@ -317,6 +317,7 @@ struct _MonoImage {
MonoDllMap *dll_map;
/* interfaces IDs from this image */
+ /* protected by the classes lock */
MonoBitSet *interface_bitset;
/* when the image is being closed, this is abused as a list of
@@ -528,7 +529,13 @@ struct _MonoMethodSignature {
* Doesn't really belong here.
*/
typedef struct {
+ /*
+ * Enable aot caching for applications whose main assemblies are in
+ * this list.
+ */
+ GSList *apps;
GSList *assemblies;
+ char *aot_options;
} MonoAotCacheConfig;
#define MONO_SIZEOF_METHOD_SIGNATURE (sizeof (struct _MonoMethodSignature) - MONO_ZERO_LEN_ARRAY * SIZEOF_VOID_P)
@@ -794,6 +801,8 @@ MonoMethod *mono_get_method_constrained_with_method (MonoImage *image, MonoMetho
void mono_type_set_alignment (MonoTypeEnum type, int align) MONO_INTERNAL;
MonoAotCacheConfig *mono_get_aot_cache_config (void) MONO_INTERNAL;
+MonoType *
+mono_type_create_from_typespec_checked (MonoImage *image, guint32 type_spec, MonoError *error) MONO_INTERNAL;
#endif /* __MONO_METADATA_INTERNALS_H__ */
diff --git a/mono/metadata/metadata.c b/mono/metadata/metadata.c
index 091ab5046e3..6b598020f03 100644
--- a/mono/metadata/metadata.c
+++ b/mono/metadata/metadata.c
@@ -3200,11 +3200,15 @@ do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContainer
case MONO_TYPE_CLASS: {
guint32 token;
MonoClass *class;
+ MonoError error;
token = mono_metadata_parse_typedef_or_ref (m, ptr, &ptr);
- class = mono_class_get (m, token);
+ class = mono_class_get_checked (m, token, &error);
type->data.klass = class;
- if (!class)
+ if (!class) {
+ mono_loader_set_error_from_mono_error (&error);
+ mono_error_cleanup (&error); /*FIXME don't swallow the error message*/
return FALSE;
+ }
if (!compare_type_literals (class->byval_arg.type, type->type))
return FALSE;
break;
@@ -3377,7 +3381,16 @@ parse_section_data (MonoImage *m, int *num_clauses, const unsigned char *ptr)
if (ec->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
ec->data.filter_offset = tof_value;
} else if (ec->flags == MONO_EXCEPTION_CLAUSE_NONE) {
- ec->data.catch_class = tof_value? mono_class_get (m, tof_value): 0;
+ ec->data.catch_class = NULL;
+ if (tof_value) {
+ MonoError error;
+ ec->data.catch_class = mono_class_get_checked (m, tof_value, &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_cleanup (&error); /* FIXME don't swallow the error */
+ g_free (clauses);
+ return NULL;
+ }
+ }
} else {
ec->data.catch_class = NULL;
}
@@ -3480,7 +3493,7 @@ mono_method_get_header_summary (MonoMethod *method, MonoMethodHeaderSummary *sum
MonoMethodHeader *
mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, const char *ptr)
{
- MonoMethodHeader *mh;
+ MonoMethodHeader *mh = NULL;
unsigned char flags = *(const unsigned char *) ptr;
unsigned char format = flags & METHOD_HEADER_FORMAT_MASK;
guint16 fat_flags;
@@ -3536,11 +3549,11 @@ mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, cons
if (local_var_sig_tok) {
int idx = (local_var_sig_tok & 0xffffff)-1;
if (idx >= t->rows || idx < 0)
- return NULL;
+ goto fail;
mono_metadata_decode_row (t, idx, cols, 1);
if (!mono_verifier_verify_standalone_signature (m, cols [MONO_STAND_ALONE_SIGNATURE], NULL))
- return NULL;
+ goto fail;
}
if (fat_flags & METHOD_HEADER_MORE_SECTS)
clauses = parse_section_data (m, &num_clauses, (const unsigned char*)ptr);
@@ -3559,11 +3572,8 @@ mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, cons
for (i = 0; i < len; ++i) {
mh->locals [i] = mono_metadata_parse_type_internal (m, container,
MONO_PARSE_LOCAL, 0, TRUE, locals_ptr, &locals_ptr);
- if (!mh->locals [i]) {
- g_free (clauses);
- g_free (mh);
- return NULL;
- }
+ if (!mh->locals [i])
+ goto fail;
}
} else {
mh = g_malloc0 (MONO_SIZEOF_METHOD_HEADER + num_clauses * sizeof (MonoExceptionClause));
@@ -3581,6 +3591,11 @@ mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, cons
mh->num_clauses = num_clauses;
}
return mh;
+fail:
+ g_free (clauses);
+ g_free (mh);
+ return NULL;
+
}
/*
@@ -4042,15 +4057,19 @@ mono_metadata_interfaces_from_typedef_full (MonoImage *meta, guint32 index, Mono
pos = start;
while (pos < tdef->rows) {
+ MonoError error;
MonoClass *iface;
mono_metadata_decode_row (tdef, pos, cols, MONO_INTERFACEIMPL_SIZE);
if (cols [MONO_INTERFACEIMPL_CLASS] != loc.idx)
break;
- iface = mono_class_get_full (
- meta, mono_metadata_token_from_dor (cols [MONO_INTERFACEIMPL_INTERFACE]), context);
- if (iface == NULL)
+ iface = mono_class_get_and_inflate_typespec_checked (
+ meta, mono_metadata_token_from_dor (cols [MONO_INTERFACEIMPL_INTERFACE]), context, &error);
+ if (iface == NULL) {
+ mono_loader_set_error_from_mono_error (&error);
+ mono_error_cleanup (&error); /* FIXME Don't swallow the error */
return FALSE;
+ }
result [pos - start] = iface;
++pos;
}
@@ -5279,12 +5298,26 @@ mono_metadata_implmap_from_method (MonoImage *meta, guint32 method_idx)
/**
* @image: context where the image is created
* @type_spec: typespec token
+ * @deprecated use mono_type_create_from_typespec_checked that has proper error handling
*
* Creates a MonoType representing the TypeSpec indexed by the @type_spec
* token.
*/
MonoType *
mono_type_create_from_typespec (MonoImage *image, guint32 type_spec)
+{
+ MonoError error;
+ MonoType *type = mono_type_create_from_typespec_checked (image, type_spec, &error);
+ if (!type) {
+ mono_loader_set_error_from_mono_error (&error);
+ mono_error_cleanup (&error); /* FIXME don't swallow error*/
+ }
+ return type;
+}
+
+MonoType *
+mono_type_create_from_typespec_checked (MonoImage *image, guint32 type_spec, MonoError *error)
+
{
guint32 idx = mono_metadata_token_index (type_spec);
MonoTableInfo *t;
@@ -5293,13 +5326,13 @@ mono_type_create_from_typespec (MonoImage *image, guint32 type_spec)
guint32 len;
MonoType *type, *type2;
- mono_loader_lock ();
+ mono_error_init (error);
+ mono_image_lock (image);
type = g_hash_table_lookup (image->typespec_cache, GUINT_TO_POINTER (type_spec));
- if (type) {
- mono_loader_unlock ();
+ mono_image_unlock (image);
+ if (type)
return type;
- }
t = &image->tables [MONO_TABLE_TYPESPEC];
@@ -5307,7 +5340,7 @@ mono_type_create_from_typespec (MonoImage *image, guint32 type_spec)
ptr = mono_metadata_blob_heap (image, cols [MONO_TYPESPEC_SIGNATURE]);
if (!mono_verifier_verify_typespec_signature (image, cols [MONO_TYPESPEC_SIGNATURE], type_spec, NULL)) {
- mono_loader_unlock ();
+ mono_error_set_bad_image (error, image, "Could not verify type spec %08x.", type_spec);
return NULL;
}
@@ -5315,24 +5348,26 @@ mono_type_create_from_typespec (MonoImage *image, guint32 type_spec)
type = mono_metadata_parse_type_internal (image, NULL, MONO_PARSE_TYPE, 0, TRUE, ptr, &ptr);
if (!type) {
- mono_loader_unlock ();
+ if (mono_loader_get_last_error ())
+ mono_error_set_from_loader_error (error);
+ else
+ mono_error_set_bad_image (error, image, "Could not parse type spec %08x.", type_spec);
return NULL;
}
- type2 = g_hash_table_lookup (image->typespec_cache, GUINT_TO_POINTER (type_spec));
-
- if (type2) {
- mono_loader_unlock ();
- return type2;
- }
-
type2 = mono_metadata_type_dup (image, type);
- g_hash_table_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type2);
mono_metadata_free_type (type);
- mono_loader_unlock ();
+ mono_image_lock (image);
+ type = g_hash_table_lookup (image->typespec_cache, GUINT_TO_POINTER (type_spec));
+ /* We might leak some data in the image mempool if found */
+ if (!type) {
+ g_hash_table_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type2);
+ type = type2;
+ }
+ mono_image_unlock (image);
- return type2;
+ return type;
}
@@ -5779,7 +5814,7 @@ mono_guid_to_string (const guint8 *guid)
}
static gboolean
-get_constraints (MonoImage *image, int owner, MonoClass ***constraints, MonoGenericContainer *container)
+get_constraints (MonoImage *image, int owner, MonoClass ***constraints, MonoGenericContainer *container, MonoError *error)
{
MonoTableInfo *tdef = &image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
guint32 cols [MONO_GENPARCONSTRAINT_SIZE];
@@ -5788,13 +5823,15 @@ get_constraints (MonoImage *image, int owner, MonoClass ***constraints, MonoGene
GSList *cons = NULL, *tmp;
MonoGenericContext *context = &container->context;
+ mono_error_init (error);
+
*constraints = NULL;
found = 0;
for (i = 0; i < tdef->rows; ++i) {
mono_metadata_decode_row (tdef, i, cols, MONO_GENPARCONSTRAINT_SIZE);
if (cols [MONO_GENPARCONSTRAINT_GENERICPAR] == owner) {
token = mono_metadata_token_from_dor (cols [MONO_GENPARCONSTRAINT_CONSTRAINT]);
- klass = mono_class_get_full (image, token, context);
+ klass = mono_class_get_and_inflate_typespec_checked (image, token, context, error);
if (!klass) {
g_slist_free (cons);
return FALSE;
@@ -5873,40 +5910,24 @@ mono_metadata_has_generic_params (MonoImage *image, guint32 token)
* Memory is allocated from IMAGE's mempool.
*/
gboolean
-mono_metadata_load_generic_param_constraints_full (MonoImage *image, guint32 token,
- MonoGenericContainer *container)
+mono_metadata_load_generic_param_constraints_checked (MonoImage *image, guint32 token,
+ MonoGenericContainer *container, MonoError *error)
{
guint32 start_row, i, owner;
+ mono_error_init (error);
+
if (! (start_row = mono_metadata_get_generic_param_row (image, token, &owner)))
return TRUE;
for (i = 0; i < container->type_argc; i++) {
- if (!get_constraints (image, start_row + i, &mono_generic_container_get_param_info (container, i)->constraints, container))
+ if (!get_constraints (image, start_row + i, &mono_generic_container_get_param_info (container, i)->constraints, container, error)) {
+ g_assert (!mono_loader_get_last_error ());
return FALSE;
+ }
}
return TRUE;
}
-/*
- * mono_metadata_load_generic_param_constraints:
- *
- * @image: metadata context
- * @token: metadata token to load the contraints, can be methodef or typedef.
- * @container: generic container to load into.
- *
- * Load the generic parameter constraints for the newly created generic type or method
- * represented by @token and @container. The @container is the new container which has
- * been returned by a call to mono_metadata_load_generic_params() with this @token.
- * Memory is allocated from IMAGE's mempool.
- */
-void
-mono_metadata_load_generic_param_constraints (MonoImage *image, guint32 token,
- MonoGenericContainer *container)
-{
- mono_metadata_load_generic_param_constraints_full (image, token, container);
- /*FIXME this function can potentially exit with a pending loader error and cause all sort of havok */
-}
-
/*
* mono_metadata_load_generic_params:
*
diff --git a/mono/metadata/mono-config.c b/mono/metadata/mono-config.c
index ac148b08d6f..c9e9e030b8c 100644
--- a/mono/metadata/mono-config.c
+++ b/mono/metadata/mono-config.c
@@ -371,6 +371,14 @@ aot_cache_start (gpointer user_data,
config = mono_get_aot_cache_config ();
+ /* Per-app configuration */
+ for (i = 0; attribute_names [i]; ++i) {
+ if (!strcmp (attribute_names [i], "app")) {
+ config->apps = g_slist_prepend (config->apps, g_strdup (attribute_values [i]));
+ }
+ }
+
+ /* Global configuration */
for (i = 0; attribute_names [i]; ++i) {
if (!strcmp (attribute_names [i], "assemblies")) {
char **parts, **ptr;
@@ -382,6 +390,8 @@ aot_cache_start (gpointer user_data,
config->assemblies = g_slist_prepend (config->assemblies, g_strdup (part));
}
g_strfreev (parts);
+ } else if (!strcmp (attribute_names [i], "options")) {
+ config->aot_options = g_strdup (attribute_values [i]);
}
}
}
diff --git a/mono/metadata/mono-wsq.c b/mono/metadata/mono-wsq.c
index 7a9d2258d12..859fb69c55b 100644
--- a/mono/metadata/mono-wsq.c
+++ b/mono/metadata/mono-wsq.c
@@ -24,6 +24,7 @@ struct _MonoWSQ {
volatile gint tail;
MonoArray *queue;
gint32 mask;
+ gint32 suspended;
MonoSemType lock;
};
@@ -61,6 +62,7 @@ mono_wsq_create ()
wsq = g_new0 (MonoWSQ, 1);
wsq->mask = INITIAL_LENGTH - 1;
+ wsq->suspended = 0;
MONO_GC_REGISTER_ROOT_SINGLE (wsq->queue);
root = mono_get_root_domain ();
wsq->queue = mono_array_new_cached (root, mono_defaults.object_class, INITIAL_LENGTH);
@@ -72,6 +74,12 @@ mono_wsq_create ()
return wsq;
}
+gboolean
+mono_wsq_suspend (MonoWSQ *wsq)
+{
+ return InterlockedCompareExchange (&wsq->suspended, 1, 0) == 0;
+}
+
void
mono_wsq_destroy (MonoWSQ *wsq)
{
@@ -112,6 +120,11 @@ mono_wsq_local_push (void *obj)
return FALSE;
}
+ if (wsq->suspended) {
+ WSQ_DEBUG ("local_push: wsq suspended\n");
+ return FALSE;
+ }
+
tail = wsq->tail;
if (tail < wsq->head + wsq->mask) {
mono_array_setref (wsq->queue, tail & wsq->mask, (MonoObject *) obj);
diff --git a/mono/metadata/mono-wsq.h b/mono/metadata/mono-wsq.h
index 7208dadb6b9..ccb064d4f18 100644
--- a/mono/metadata/mono-wsq.h
+++ b/mono/metadata/mono-wsq.h
@@ -20,6 +20,7 @@ gboolean mono_wsq_local_push (void *obj) MONO_INTERNAL;
gboolean mono_wsq_local_pop (void **ptr) MONO_INTERNAL;
void mono_wsq_try_steal (MonoWSQ *wsq, void **ptr, guint32 ms_timeout) MONO_INTERNAL;
gint mono_wsq_count (MonoWSQ *wsq) MONO_INTERNAL;
+gboolean mono_wsq_suspend (MonoWSQ *wsq) MONO_INTERNAL;
G_END_DECLS
diff --git a/mono/metadata/object.c b/mono/metadata/object.c
index daa72aec6f2..b9abf073f05 100644
--- a/mono/metadata/object.c
+++ b/mono/metadata/object.c
@@ -287,8 +287,19 @@ mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
if (!klass->image->checked_module_cctor) {
mono_image_check_for_module_cctor (klass->image);
if (klass->image->has_module_cctor) {
- MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
- MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
+ MonoError error;
+ MonoClass *module_klass;
+ MonoVTable *module_vtable;
+
+ module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error);
+ if (!module_klass) {
+ exc = mono_error_convert_to_exception (&error);
+ if (raise_exception)
+ mono_raise_exception (exc);
+ return exc;
+ }
+
+ module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
if (!module_vtable)
return NULL;
exc = mono_runtime_class_init_full (module_vtable, raise_exception);
@@ -4596,9 +4607,11 @@ mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *p
MonoObject *
mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
{
+ MonoError error;
MonoClass *class;
- class = mono_class_get (image, token);
+ class = mono_class_get_checked (image, token, &error);
+ g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
return mono_object_new (domain, class);
}
@@ -5028,10 +5041,10 @@ mono_string_new_size (MonoDomain *domain, gint32 len)
size_t size;
/* check for overflow */
- if (len < 0 || len > ((SIZE_MAX - sizeof (MonoString) - 2) / 2))
+ if (len < 0 || len > ((SIZE_MAX - offsetof (MonoString, chars) - 2) / 2))
mono_gc_out_of_memory (-1);
- size = (sizeof (MonoString) + ((len + 1) * 2));
+ size = (offsetof (MonoString, chars) + ((len + 1) * 2));
g_assert (size > 0);
vtable = mono_class_vtable (domain, mono_defaults.string_class);
diff --git a/mono/metadata/process.c b/mono/metadata/process.c
index c9e0f8bf63b..d7cc110aec6 100644
--- a/mono/metadata/process.c
+++ b/mono/metadata/process.c
@@ -23,18 +23,7 @@
#include
#include
#include
-#ifndef HAVE_GETPROCESSID
-#if defined(_MSC_VER) || defined(HAVE_WINTERNL_H)
-#include
-#ifndef NT_SUCCESS
-#define NT_SUCCESS(status) ((NTSTATUS) (status) >= 0)
-#endif /* !NT_SUCCESS */
-#else /* ! (defined(_MSC_VER) || defined(HAVE_WINTERNL_H)) */
-#include
-#include
-#endif /* (defined(_MSC_VER) || defined(HAVE_WINTERNL_H)) */
-#endif /* !HAVE_GETPROCESSID */
-/* FIXME: fix this code to not depend so much on the inetrnals */
+/* FIXME: fix this code to not depend so much on the internals */
#include
#define LOGDEBUG(...)
@@ -60,11 +49,12 @@ HANDLE ves_icall_System_Diagnostics_Process_GetProcess_internal (guint32 pid)
return(handle);
}
-guint32 ves_icall_System_Diagnostics_Process_GetPid_internal (void)
+guint32
+ves_icall_System_Diagnostics_Process_GetPid_internal (void)
{
MONO_ARCH_SAVE_REGS;
- return(GetCurrentProcessId ());
+ return mono_process_current_pid ();
}
void ves_icall_System_Diagnostics_Process_Process_free_internal (MonoObject *this,
@@ -525,76 +515,6 @@ complete_path (const gunichar2 *appname, gchar **completed)
return TRUE;
}
-#ifndef HAVE_GETPROCESSID
-/* Run-time GetProcessId detection for Windows */
-#ifdef TARGET_WIN32
-#define HAVE_GETPROCESSID
-
-typedef DWORD (WINAPI *GETPROCESSID_PROC) (HANDLE);
-typedef DWORD (WINAPI *NTQUERYINFORMATIONPROCESS_PROC) (HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
-typedef DWORD (WINAPI *RTLNTSTATUSTODOSERROR_PROC) (NTSTATUS);
-
-static DWORD WINAPI GetProcessId_detect (HANDLE process);
-
-static GETPROCESSID_PROC GetProcessId = &GetProcessId_detect;
-static NTQUERYINFORMATIONPROCESS_PROC NtQueryInformationProcess_proc = NULL;
-static RTLNTSTATUSTODOSERROR_PROC RtlNtStatusToDosError_proc = NULL;
-
-static DWORD WINAPI GetProcessId_ntdll (HANDLE process)
-{
- PROCESS_BASIC_INFORMATION pi;
- NTSTATUS status;
-
- status = NtQueryInformationProcess_proc (process, ProcessBasicInformation, &pi, sizeof (pi), NULL);
- if (NT_SUCCESS (status)) {
- return pi.UniqueProcessId;
- } else {
- SetLastError (RtlNtStatusToDosError_proc (status));
- return 0;
- }
-}
-
-static DWORD WINAPI GetProcessId_stub (HANDLE process)
-{
- SetLastError (ERROR_CALL_NOT_IMPLEMENTED);
- return 0;
-}
-
-static DWORD WINAPI GetProcessId_detect (HANDLE process)
-{
- HMODULE module_handle;
- GETPROCESSID_PROC GetProcessId_kernel;
-
- /* Windows XP SP1 and above have GetProcessId API */
- module_handle = GetModuleHandle (L"kernel32.dll");
- if (module_handle != NULL) {
- GetProcessId_kernel = (GETPROCESSID_PROC) GetProcAddress (module_handle, "GetProcessId");
- if (GetProcessId_kernel != NULL) {
- GetProcessId = GetProcessId_kernel;
- return GetProcessId (process);
- }
- }
-
- /* Windows 2000 and above have deprecated NtQueryInformationProcess API */
- module_handle = GetModuleHandle (L"ntdll.dll");
- if (module_handle != NULL) {
- NtQueryInformationProcess_proc = (NTQUERYINFORMATIONPROCESS_PROC) GetProcAddress (module_handle, "NtQueryInformationProcess");
- if (NtQueryInformationProcess_proc != NULL) {
- RtlNtStatusToDosError_proc = (RTLNTSTATUSTODOSERROR_PROC) GetProcAddress (module_handle, "RtlNtStatusToDosError");
- if (RtlNtStatusToDosError_proc != NULL) {
- GetProcessId = &GetProcessId_ntdll;
- return GetProcessId (process);
- }
- }
- }
-
- /* Fall back to ERROR_CALL_NOT_IMPLEMENTED */
- GetProcessId = &GetProcessId_stub;
- return GetProcessId (process);
-}
-#endif /* HOST_WIN32 */
-#endif /* !HAVE_GETPROCESSID */
-
MonoBoolean ves_icall_System_Diagnostics_Process_ShellExecuteEx_internal (MonoProcessStartInfo *proc_start_info, MonoProcInfo *process_info)
{
SHELLEXECUTEINFO shellex = {0};
@@ -891,14 +811,33 @@ MonoString *ves_icall_System_Diagnostics_Process_ProcessName_internal (HANDLE pr
/* Returns an array of pids */
MonoArray *ves_icall_System_Diagnostics_Process_GetProcesses_internal (void)
{
+#if !defined(HOST_WIN32)
+ MonoArray *procs;
+ gpointer *pidarray;
+ int i, count;
+
+ MONO_ARCH_SAVE_REGS;
+
+ pidarray = mono_process_list (&count);
+ if (!pidarray)
+ mono_raise_exception (mono_get_exception_not_supported ("This system does not support EnumProcesses"));
+ procs = mono_array_new (mono_domain_get (), mono_get_int32_class (), count);
+ if (sizeof (guint32) == sizeof (gpointer)) {
+ memcpy (mono_array_addr (procs, guint32, 0), pidarray, count);
+ } else {
+ for (i = 0; i < count; ++i)
+ *(mono_array_addr (procs, guint32, i)) = GPOINTER_TO_UINT (pidarray [i]);
+ }
+ g_free (pidarray);
+
+ return procs;
+#else
MonoArray *procs;
gboolean ret;
DWORD needed;
- guint32 count;
+ int count;
guint32 *pids;
- MONO_ARCH_SAVE_REGS;
-
count = 512;
do {
pids = g_new0 (guint32, count);
@@ -926,6 +865,7 @@ MonoArray *ves_icall_System_Diagnostics_Process_GetProcesses_internal (void)
pids = NULL;
return procs;
+#endif
}
MonoBoolean ves_icall_System_Diagnostics_Process_GetWorkingSet_internal (HANDLE process, guint32 *min, guint32 *max)
diff --git a/mono/metadata/profiler-private.h b/mono/metadata/profiler-private.h
index 18ec96b7aea..ed8a32f44fe 100644
--- a/mono/metadata/profiler-private.h
+++ b/mono/metadata/profiler-private.h
@@ -77,5 +77,8 @@ void mono_profiler_code_buffer_new (gpointer buffer, int size, MonoProfilerCodeB
void mono_profiler_runtime_initialized (void) MONO_INTERNAL;
+int64_t mono_profiler_get_sampling_rate (void) MONO_INTERNAL;
+MonoProfileSamplingMode mono_profiler_get_sampling_mode (void) MONO_INTERNAL;
+
#endif /* __MONO_PROFILER_PRIVATE_H__ */
diff --git a/mono/metadata/profiler.c b/mono/metadata/profiler.c
index 53f8ff0c907..dccf0930711 100644
--- a/mono/metadata/profiler.c
+++ b/mono/metadata/profiler.c
@@ -273,6 +273,28 @@ mono_profiler_install_monitor (MonoProfileMonitorFunc callback)
prof_list->monitor_event_cb = callback;
}
+static MonoProfileSamplingMode sampling_mode = MONO_PROFILER_STAT_MODE_PROCESS;
+static int64_t sampling_frequency = 1000; //1ms
+
+/**
+ * mono_profiler_set_statistical_mode:
+ * @mode the sampling mode used.
+ * @sample_frequency_is_us the sampling frequency in microseconds.
+ *
+ * Set the sampling parameters for the profiler. Sampling mode affects the effective sampling rate as in samples/s you'll witness.
+ * The default sampling mode is process mode, which only reports samples when there's activity in the process.
+ *
+ * Sampling frequency should be interpreted as a suggestion that can't always be honored due to how most kernels expose alarms.
+ *
+ * Said that, when using statistical sampling, always assume variable rate sampling as all sort of external factors can interfere.
+ */
+void
+mono_profiler_set_statistical_mode (MonoProfileSamplingMode mode, int64_t sampling_frequency_is_us)
+{
+ sampling_mode = mode;
+ sampling_frequency = sampling_frequency_is_us;
+}
+
void
mono_profiler_install_statistical (MonoProfileStatFunc callback)
{
@@ -281,6 +303,18 @@ mono_profiler_install_statistical (MonoProfileStatFunc callback)
prof_list->statistical_cb = callback;
}
+int64_t
+mono_profiler_get_sampling_rate (void)
+{
+ return sampling_frequency;
+}
+
+MonoProfileSamplingMode
+mono_profiler_get_sampling_mode (void)
+{
+ return sampling_mode;
+}
+
void
mono_profiler_install_statistical_call_chain (MonoProfileStatCallChainFunc callback, int call_chain_depth, MonoProfilerCallChainStrategy call_chain_strategy) {
if (!prof_list)
diff --git a/mono/metadata/profiler.h b/mono/metadata/profiler.h
index c7b8f6d8a88..408cac8ba31 100644
--- a/mono/metadata/profiler.h
+++ b/mono/metadata/profiler.h
@@ -193,6 +193,15 @@ MONO_API void mono_profiler_install_iomap (MonoProfileIomapFunc callback);
MONO_API void mono_profiler_load (const char *desc);
+typedef enum {
+ /* Elapsed time is tracked by user+kernel time of the process - this is the default*/
+ MONO_PROFILER_STAT_MODE_PROCESS = 0,
+ /* Elapsed time is tracked by wallclock time */
+ MONO_PROFILER_STAT_MODE_REAL = 1,
+} MonoProfileSamplingMode;
+
+MONO_API void mono_profiler_set_statistical_mode (MonoProfileSamplingMode mode, int64_t sampling_frequency_is_us);
+
MONO_END_DECLS
#endif /* __MONO_PROFILER_H__ */
diff --git a/mono/metadata/reflection.c b/mono/metadata/reflection.c
index 3691da1b5dd..6614b01e1e9 100644
--- a/mono/metadata/reflection.c
+++ b/mono/metadata/reflection.c
@@ -1702,8 +1702,10 @@ fieldref_encode_signature (MonoDynamicImage *assembly, MonoImage *field_image, M
if (type->num_mods) {
for (i = 0; i < type->num_mods; ++i) {
if (field_image) {
- MonoClass *class = mono_class_get (field_image, type->modifiers [i].token);
- g_assert (class);
+ MonoError error;
+ MonoClass *class = mono_class_get_checked (field_image, type->modifiers [i].token, &error);
+ g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+
token = mono_image_typedef_or_ref (assembly, &class->byval_arg);
} else {
token = type->modifiers [i].token;
@@ -2254,8 +2256,8 @@ resolution_scope_from_image (MonoDynamicImage *assembly, MonoImage *image)
values = table->values + token * MONO_MODULEREF_SIZE;
values [MONO_MODULEREF_NAME] = string_heap_insert (&assembly->sheap, image->module_name);
- token <<= MONO_RESOLTION_SCOPE_BITS;
- token |= MONO_RESOLTION_SCOPE_MODULEREF;
+ token <<= MONO_RESOLUTION_SCOPE_BITS;
+ token |= MONO_RESOLUTION_SCOPE_MODULEREF;
g_hash_table_insert (assembly->handleref, image, GUINT_TO_POINTER (token));
return token;
@@ -2297,8 +2299,8 @@ resolution_scope_from_image (MonoDynamicImage *assembly, MonoImage *image)
} else {
values [MONO_ASSEMBLYREF_PUBLIC_KEY] = 0;
}
- token <<= MONO_RESOLTION_SCOPE_BITS;
- token |= MONO_RESOLTION_SCOPE_ASSEMBLYREF;
+ token <<= MONO_RESOLUTION_SCOPE_BITS;
+ token |= MONO_RESOLUTION_SCOPE_ASSEMBLYREF;
g_hash_table_insert (assembly->handleref, image, GUINT_TO_POINTER (token));
return token;
}
@@ -2388,7 +2390,7 @@ mono_image_typedef_or_ref_full (MonoDynamicImage *assembly, MonoType *type, gboo
enclosing = mono_image_typedef_or_ref_full (assembly, &klass->nested_in->byval_arg, FALSE);
/* get the typeref idx of the enclosing type */
enclosing >>= MONO_TYPEDEFORREF_BITS;
- scope = (enclosing << MONO_RESOLTION_SCOPE_BITS) | MONO_RESOLTION_SCOPE_TYPEREF;
+ scope = (enclosing << MONO_RESOLUTION_SCOPE_BITS) | MONO_RESOLUTION_SCOPE_TYPEREF;
} else {
scope = resolution_scope_from_image (assembly, klass->image);
}
@@ -3798,7 +3800,9 @@ mono_image_fill_export_table_from_module (MonoDomain *domain, MonoReflectionModu
t = &image->tables [MONO_TABLE_TYPEDEF];
for (i = 0; i < t->rows; ++i) {
- MonoClass *klass = mono_class_get (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, i + 1));
+ MonoError error;
+ MonoClass *klass = mono_class_get_checked (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, i + 1), &error);
+ g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
if (klass->flags & TYPE_ATTRIBUTE_PUBLIC)
mono_image_fill_export_table_from_class (domain, klass, module_index, 0, assembly);
@@ -3820,8 +3824,8 @@ add_exported_type (MonoReflectionAssemblyBuilder *assemblyb, MonoDynamicImage *a
forwarder = FALSE;
} else {
scope = resolution_scope_from_image (assembly, klass->image);
- g_assert ((scope & MONO_RESOLTION_SCOPE_MASK) == MONO_RESOLTION_SCOPE_ASSEMBLYREF);
- scope_idx = scope >> MONO_RESOLTION_SCOPE_BITS;
+ g_assert ((scope & MONO_RESOLUTION_SCOPE_MASK) == MONO_RESOLUTION_SCOPE_ASSEMBLYREF);
+ scope_idx = scope >> MONO_RESOLUTION_SCOPE_BITS;
impl = (scope_idx << MONO_IMPLEMENTATION_BITS) + MONO_IMPLEMENTATION_ASSEMBLYREF;
}
@@ -7487,10 +7491,13 @@ mono_reflection_get_type_internal (MonoImage *rootimage, MonoImage* image, MonoT
if (!image)
image = mono_defaults.corlib;
- if (ignorecase)
- klass = mono_class_from_name_case (image, info->name_space, info->name);
- else
+ if (ignorecase) {
+ MonoError error;
+ klass = mono_class_from_name_case_checked (image, info->name_space, info->name, &error);
+ g_assert (mono_error_ok (&error)); /* FIXME Don't swallow the error */
+ } else {
klass = mono_class_from_name (image, info->name_space, info->name);
+ }
if (!klass)
return NULL;
for (mod = info->nested; mod; mod = mod->next) {
@@ -7501,14 +7508,52 @@ mono_reflection_get_type_internal (MonoImage *rootimage, MonoImage* image, MonoT
mono_class_init (parent);
while ((klass = mono_class_get_nested_types (parent, &iter))) {
- if (ignorecase) {
- if (mono_utf8_strcasecmp (klass->name, mod->data) == 0)
- break;
+ char *lastp;
+ char *nested_name, *nested_nspace;
+ gboolean match = TRUE;
+
+ lastp = strrchr (mod->data, '.');
+ if (lastp) {
+ /* Nested classes can have namespaces */
+ int nspace_len;
+
+ nested_name = g_strdup (lastp + 1);
+ nspace_len = lastp - (char*)mod->data;
+ nested_nspace = g_malloc (nspace_len + 1);
+ memcpy (nested_nspace, mod->data, nspace_len);
+ nested_nspace [nspace_len] = '\0';
+
} else {
- if (strcmp (klass->name, mod->data) == 0)
- break;
+ nested_name = mod->data;
+ nested_nspace = NULL;
+ }
+
+ if (nested_nspace) {
+ if (ignorecase) {
+ if (!(klass->name_space && mono_utf8_strcasecmp (klass->name_space, nested_nspace) == 0))
+ match = FALSE;
+ } else {
+ if (!(klass->name_space && strcmp (klass->name_space, nested_nspace) == 0))
+ match = FALSE;
+ }
+ }
+ if (match) {
+ if (ignorecase) {
+ if (mono_utf8_strcasecmp (klass->name, nested_name) != 0)
+ match = FALSE;
+ } else {
+ if (strcmp (klass->name, nested_name) != 0)
+ match = FALSE;
+ }
}
+ if (lastp) {
+ g_free (nested_name);
+ g_free (nested_nspace);
+ }
+ if (match)
+ break;
}
+
if (!klass)
break;
}
@@ -7757,12 +7802,15 @@ mono_reflection_get_token (MonoObject *obj)
if (is_field_on_inst (f->field)) {
MonoDynamicGenericClass *dgclass = (MonoDynamicGenericClass*)f->field->parent->generic_class;
- int field_index = f->field - dgclass->fields;
- MonoObject *obj;
- g_assert (field_index >= 0 && field_index < dgclass->count_fields);
- obj = dgclass->field_objects [field_index];
- return mono_reflection_get_token (obj);
+ if (f->field >= dgclass->fields && f->field < dgclass->fields + dgclass->count_fields) {
+ int field_index = f->field - dgclass->fields;
+ MonoObject *obj;
+
+ g_assert (field_index >= 0 && field_index < dgclass->count_fields);
+ obj = dgclass->field_objects [field_index];
+ return mono_reflection_get_token (obj);
+ }
}
token = mono_class_get_field_token (f->field);
} else if (strcmp (klass->name, "MonoProperty") == 0) {
@@ -9970,7 +10018,7 @@ mono_reflection_setup_internal_class (MonoReflectionTypeBuilder *tb)
mono_class_set_ref_info (klass, tb);
- /* Put into cache so mono_class_get () will find it.
+ /* Put into cache so mono_class_get_checked () will find it.
Skip nested types as those should not be available on the global scope. */
if (!tb->nesting_type)
mono_image_add_to_name_cache (klass->image, klass->name_space, klass->name, tb->table_idx);
diff --git a/mono/metadata/row-indexes.h b/mono/metadata/row-indexes.h
index 4b4ca6dbc96..74fbf6b35c5 100644
--- a/mono/metadata/row-indexes.h
+++ b/mono/metadata/row-indexes.h
@@ -419,6 +419,16 @@ enum {
MONO_CUSTOM_ATTR_TYPE_MASK = 7
};
+enum {
+ MONO_RESOLUTION_SCOPE_MODULE,
+ MONO_RESOLUTION_SCOPE_MODULEREF,
+ MONO_RESOLUTION_SCOPE_ASSEMBLYREF,
+ MONO_RESOLUTION_SCOPE_TYPEREF,
+ MONO_RESOLUTION_SCOPE_BITS = 2,
+ MONO_RESOLUTION_SCOPE_MASK = 3
+};
+
+/* Kept for compatibility since this is a public header file */
enum {
MONO_RESOLTION_SCOPE_MODULE,
MONO_RESOLTION_SCOPE_MODULEREF,
diff --git a/mono/metadata/security.c b/mono/metadata/security.c
index c61eab99f7b..65a562da72c 100644
--- a/mono/metadata/security.c
+++ b/mono/metadata/security.c
@@ -701,9 +701,10 @@ IsUserProtected (gunichar2 *path)
gboolean success = FALSE;
PACL pDACL = NULL;
PSID pEveryoneSid = NULL;
+ PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
DWORD dwRes = GetNamedSecurityInfoW (path, SE_FILE_OBJECT,
- DACL_SECURITY_INFORMATION, NULL, NULL, &pDACL, NULL, NULL);
+ DACL_SECURITY_INFORMATION, NULL, NULL, &pDACL, NULL, &pSecurityDescriptor);
if (dwRes != ERROR_SUCCESS)
return FALSE;
@@ -720,8 +721,8 @@ IsUserProtected (gunichar2 *path)
/* Note: we don't need to check our own access -
we'll know soon enough when reading the file */
- if (pDACL)
- LocalFree (pDACL);
+ if (pSecurityDescriptor)
+ LocalFree (pSecurityDescriptor);
return success;
}
diff --git a/mono/metadata/sgen-alloc.c b/mono/metadata/sgen-alloc.c
index d9a52e9b195..368388a5dab 100644
--- a/mono/metadata/sgen-alloc.c
+++ b/mono/metadata/sgen-alloc.c
@@ -189,9 +189,12 @@ mono_gc_alloc_obj_nolock (MonoVTable *vtable, size_t size)
void **p;
char *new_next;
TLAB_ACCESS_INIT;
+ size_t real_size = size;
+
+ CANARIFY_SIZE(size);
HEAVY_STAT (++stat_objects_alloced);
- if (size <= SGEN_MAX_SMALL_OBJ_SIZE)
+ if (real_size <= SGEN_MAX_SMALL_OBJ_SIZE)
HEAVY_STAT (stat_bytes_alloced += size);
else
HEAVY_STAT (stat_bytes_alloced_los += size);
@@ -207,7 +210,7 @@ mono_gc_alloc_obj_nolock (MonoVTable *vtable, size_t size)
if (collect_before_allocs) {
if (((current_alloc % collect_before_allocs) == 0) && nursery_section) {
sgen_perform_collection (0, GENERATION_NURSERY, "collect-before-alloc-triggered", TRUE);
- if (!degraded_mode && sgen_can_alloc_size (size) && size <= SGEN_MAX_SMALL_OBJ_SIZE) {
+ if (!degraded_mode && sgen_can_alloc_size (size) && real_size <= SGEN_MAX_SMALL_OBJ_SIZE) {
// FIXME:
g_assert_not_reached ();
}
@@ -229,8 +232,8 @@ mono_gc_alloc_obj_nolock (MonoVTable *vtable, size_t size)
* specially by the world-stopping code.
*/
- if (size > SGEN_MAX_SMALL_OBJ_SIZE) {
- p = sgen_los_alloc_large_inner (vtable, size);
+ if (real_size > SGEN_MAX_SMALL_OBJ_SIZE) {
+ p = sgen_los_alloc_large_inner (vtable, ALIGN_UP (real_size));
} else {
/* tlab_next and tlab_temp_end are TLS vars so accessing them might be expensive */
@@ -247,6 +250,7 @@ mono_gc_alloc_obj_nolock (MonoVTable *vtable, size_t size)
* visible before the vtable store.
*/
+ CANARIFY_ALLOC(p,real_size);
SGEN_LOG (6, "Allocated object %p, vtable: %p (%s), size: %zd", p, vtable, vtable->klass->name, size);
binary_protocol_alloc (p , vtable, size);
if (G_UNLIKELY (MONO_GC_NURSERY_OBJ_ALLOC_ENABLED ()))
@@ -287,20 +291,30 @@ mono_gc_alloc_obj_nolock (MonoVTable *vtable, size_t size)
available_in_tlab = (int)(TLAB_REAL_END - TLAB_NEXT);//We'll never have tlabs > 2Gb
if (size > tlab_size || available_in_tlab > SGEN_MAX_NURSERY_WASTE) {
/* Allocate directly from the nursery */
- do {
- p = sgen_nursery_alloc (size);
- if (!p) {
- sgen_ensure_free_space (size);
- if (degraded_mode)
- return alloc_degraded (vtable, size, FALSE);
- else
- p = sgen_nursery_alloc (size);
- }
- } while (!p);
+ p = sgen_nursery_alloc (size);
if (!p) {
- // no space left
- g_assert (0);
+ /*
+ * We couldn't allocate from the nursery, so we try
+ * collecting. Even after the collection, we might
+ * still not have enough memory to allocate the
+ * object. The reason will most likely be that we've
+ * run out of memory, but there is the theoretical
+ * possibility that other threads might have consumed
+ * the freed up memory ahead of us, so doing another
+ * collection and trying again might actually help.
+ * Of course the same thing might happen again.
+ *
+ * Ideally we'd like to detect that case and loop (if
+ * we always loop we will loop endlessly in the case of
+ * OOM). What we do here is give up right away.
+ */
+ sgen_ensure_free_space (real_size);
+ if (degraded_mode)
+ return alloc_degraded (vtable, size, FALSE);
+ else
+ p = sgen_nursery_alloc (size);
}
+ SGEN_ASSERT (0, p, "Out of memory");
zero_tlab_if_necessary (p, size);
} else {
@@ -309,21 +323,16 @@ mono_gc_alloc_obj_nolock (MonoVTable *vtable, size_t size)
SGEN_LOG (3, "Retire TLAB: %p-%p [%ld]", TLAB_START, TLAB_REAL_END, (long)(TLAB_REAL_END - TLAB_NEXT - size));
sgen_nursery_retire_region (p, available_in_tlab);
- do {
- p = sgen_nursery_alloc_range (tlab_size, size, &alloc_size);
- if (!p) {
- sgen_ensure_free_space (tlab_size);
- if (degraded_mode)
- return alloc_degraded (vtable, size, FALSE);
- else
- p = sgen_nursery_alloc_range (tlab_size, size, &alloc_size);
- }
- } while (!p);
-
+ p = sgen_nursery_alloc_range (tlab_size, size, &alloc_size);
if (!p) {
- // no space left
- g_assert (0);
+ /* See comment above in similar case. */
+ sgen_ensure_free_space (tlab_size);
+ if (degraded_mode)
+ return alloc_degraded (vtable, size, FALSE);
+ else
+ p = sgen_nursery_alloc_range (tlab_size, size, &alloc_size);
}
+ SGEN_ASSERT (0, p, "Out of memory");
/* Allocate a new TLAB from the current nursery fragment */
TLAB_START = (char*)p;
@@ -347,13 +356,14 @@ mono_gc_alloc_obj_nolock (MonoVTable *vtable, size_t size)
TLAB_TEMP_END = MIN (TLAB_REAL_END, TLAB_NEXT + SGEN_SCAN_START_SIZE);
SGEN_LOG (5, "Expanding local alloc: %p-%p", TLAB_NEXT, TLAB_TEMP_END);
}
+ CANARIFY_ALLOC(p,real_size);
}
if (G_LIKELY (p)) {
SGEN_LOG (6, "Allocated object %p, vtable: %p (%s), size: %zd", p, vtable, vtable->klass->name, size);
binary_protocol_alloc (p, vtable, size);
if (G_UNLIKELY (MONO_GC_MAJOR_OBJ_ALLOC_LARGE_ENABLED ()|| MONO_GC_NURSERY_OBJ_ALLOC_ENABLED ())) {
- if (size > SGEN_MAX_SMALL_OBJ_SIZE)
+ if (real_size > SGEN_MAX_SMALL_OBJ_SIZE)
MONO_GC_MAJOR_OBJ_ALLOC_LARGE ((mword)p, size, vtable->klass->name_space, vtable->klass->name);
else
MONO_GC_NURSERY_OBJ_ALLOC ((mword)p, size, vtable->klass->name_space, vtable->klass->name);
@@ -370,12 +380,15 @@ mono_gc_try_alloc_obj_nolock (MonoVTable *vtable, size_t size)
void **p;
char *new_next;
TLAB_ACCESS_INIT;
+ size_t real_size = size;
+
+ CANARIFY_SIZE(size);
size = ALIGN_UP (size);
- SGEN_ASSERT (9, size >= sizeof (MonoObject), "Object too small");
+ SGEN_ASSERT (9, real_size >= sizeof (MonoObject), "Object too small");
g_assert (vtable->gc_descr);
- if (size > SGEN_MAX_SMALL_OBJ_SIZE)
+ if (real_size > SGEN_MAX_SMALL_OBJ_SIZE)
return NULL;
if (G_UNLIKELY (size > tlab_size)) {
@@ -440,6 +453,7 @@ mono_gc_try_alloc_obj_nolock (MonoVTable *vtable, size_t size)
HEAVY_STAT (++stat_objects_alloced);
HEAVY_STAT (stat_bytes_alloced += size);
+ CANARIFY_ALLOC(p,real_size);
SGEN_LOG (6, "Allocated object %p, vtable: %p (%s), size: %zd", p, vtable, vtable->klass->name, size);
binary_protocol_alloc (p, vtable, size);
if (G_UNLIKELY (MONO_GC_NURSERY_OBJ_ALLOC_ENABLED ()))
@@ -887,7 +901,7 @@ create_allocator (int atype)
/*
* a string allocator method takes the args: (vtable, len)
*
- * bytes = sizeof (MonoString) + ((len + 1) * 2)
+ * bytes = offsetof (MonoString, chars) + ((len + 1) * 2)
*
* condition:
*
@@ -895,11 +909,11 @@ create_allocator (int atype)
*
* therefore:
*
- * sizeof (MonoString) + ((len + 1) * 2) <= INT32_MAX - (SGEN_ALLOC_ALIGN - 1)
- * len <= (INT32_MAX - (SGEN_ALLOC_ALIGN - 1) - sizeof (MonoString)) / 2 - 1
+ * offsetof (MonoString, chars) + ((len + 1) * 2) <= INT32_MAX - (SGEN_ALLOC_ALIGN - 1)
+ * len <= (INT32_MAX - (SGEN_ALLOC_ALIGN - 1) - offsetof (MonoString, chars)) / 2 - 1
*/
mono_mb_emit_ldarg (mb, 1);
- mono_mb_emit_icon (mb, (INT32_MAX - (SGEN_ALLOC_ALIGN - 1) - sizeof (MonoString)) / 2 - 1);
+ mono_mb_emit_icon (mb, (INT32_MAX - (SGEN_ALLOC_ALIGN - 1) - MONO_STRUCT_OFFSET (MonoString, chars)) / 2 - 1);
pos = mono_mb_emit_short_branch (mb, MONO_CEE_BLE_UN_S);
mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
@@ -911,7 +925,7 @@ create_allocator (int atype)
mono_mb_emit_icon (mb, 1);
mono_mb_emit_byte (mb, MONO_CEE_SHL);
//WE manually fold the above + 2 here
- mono_mb_emit_icon (mb, sizeof (MonoString) + 2);
+ mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoString, chars) + 2);
mono_mb_emit_byte (mb, CEE_ADD);
mono_mb_emit_stloc (mb, size_var);
} else {
diff --git a/mono/metadata/sgen-archdep.h b/mono/metadata/sgen-archdep.h
index b86ec318c7c..420dc96e47d 100644
--- a/mono/metadata/sgen-archdep.h
+++ b/mono/metadata/sgen-archdep.h
@@ -21,7 +21,14 @@
#ifndef __MONO_SGENARCHDEP_H__
#define __MONO_SGENARCHDEP_H__
-#include
+#include
+
+/*
+ * Define either USE_MONO_CTX, or
+ * ARCH_SIGCTX_SP/ARCH_SIGCTX_IP/ARCH_STORE_REGS/ARCH_COPY_SIGCTX_REGS.
+ * Define ARCH_NUM_REGS to be the number of general registers in MonoContext, or the
+ * number of registers stored by ARCH_STORE_REGS.
+ */
#if defined(MONO_CROSS_COMPILE)
@@ -35,35 +42,23 @@
#elif defined(TARGET_X86)
-#include
-
#define REDZONE_SIZE 0
#define ARCH_NUM_REGS 8
-#ifdef MONO_ARCH_HAS_MONO_CONTEXT
-#define USE_MONO_CTX
-#else
+#ifndef MONO_ARCH_HAS_MONO_CONTEXT
#error 0
#endif
-/*FIXME, move this to mono-sigcontext as this is generaly useful.*/
-#define ARCH_SIGCTX_SP(ctx) (UCONTEXT_REG_ESP ((ctx)))
-#define ARCH_SIGCTX_IP(ctx) (UCONTEXT_REG_EIP ((ctx)))
+#define USE_MONO_CTX
#elif defined(TARGET_AMD64)
-#include
-
#define REDZONE_SIZE 128
#define ARCH_NUM_REGS 16
#define USE_MONO_CTX
-/*FIXME, move this to mono-sigcontext as this is generaly useful.*/
-#define ARCH_SIGCTX_SP(ctx) (UCONTEXT_REG_RSP (ctx))
-#define ARCH_SIGCTX_IP(ctx) (UCONTEXT_REG_RIP (ctx))
-
#elif defined(TARGET_POWERPC)
#define REDZONE_SIZE 224
@@ -99,39 +94,9 @@
/* We dont store ip, sp */
#define ARCH_NUM_REGS 14
-#define ARCH_STORE_REGS(ptr) \
- __asm__ __volatile__( \
- "push {lr}\n" \
- "mov lr, %0\n" \
- "stmia lr!, {r0-r12}\n" \
- "pop {lr}\n" \
- : \
- : "r" (ptr) \
- )
-
-#define ARCH_SIGCTX_SP(ctx) (UCONTEXT_REG_SP((ctx)))
-#define ARCH_SIGCTX_IP(ctx) (UCONTEXT_REG_PC((ctx)))
-#define ARCH_COPY_SIGCTX_REGS(a,ctx) do { \
- ((a)[0]) = (gpointer) (UCONTEXT_REG_R0((ctx))); \
- ((a)[1]) = (gpointer) (UCONTEXT_REG_R1((ctx))); \
- ((a)[2]) = (gpointer) (UCONTEXT_REG_R2((ctx))); \
- ((a)[3]) = (gpointer) (UCONTEXT_REG_R3((ctx))); \
- ((a)[4]) = (gpointer) (UCONTEXT_REG_R4((ctx))); \
- ((a)[5]) = (gpointer) (UCONTEXT_REG_R5((ctx))); \
- ((a)[6]) = (gpointer) (UCONTEXT_REG_R6((ctx))); \
- ((a)[7]) = (gpointer) (UCONTEXT_REG_R7((ctx))); \
- ((a)[8]) = (gpointer) (UCONTEXT_REG_R8((ctx))); \
- ((a)[9]) = (gpointer) (UCONTEXT_REG_R9((ctx))); \
- ((a)[10]) = (gpointer) (UCONTEXT_REG_R10((ctx))); \
- ((a)[11]) = (gpointer) (UCONTEXT_REG_R11((ctx))); \
- ((a)[12]) = (gpointer) (UCONTEXT_REG_R12((ctx))); \
- ((a)[13]) = (gpointer) (UCONTEXT_REG_LR((ctx))); \
- } while (0)
#elif defined(TARGET_ARM64)
-#include
-
#ifdef __linux__
#define REDZONE_SIZE 0
#elif defined(__APPLE__)
@@ -142,12 +107,6 @@
#define USE_MONO_CTX
#define ARCH_NUM_REGS 31
-#define ARCH_STORE_REGS(ptr) do { g_assert_not_reached (); } while (0)
-
-#define ARCH_SIGCTX_SP(ctx) UCONTEXT_REG_SP (ctx)
-#define ARCH_SIGCTX_IP(ctx) UCONTEXT_REG_PC (ctx)
-#define ARCH_COPY_SIGCTX_REGS(a,ctx) do { g_assert_not_reached (); } while (0)
-
#elif defined(__mips__)
#define REDZONE_SIZE 0
@@ -155,23 +114,12 @@
#define USE_MONO_CTX
#define ARCH_NUM_REGS 32
-/*
- * These casts are necessary since glibc always makes the
- * gregs 64-bit values in userland.
- */
-#define ARCH_SIGCTX_SP(ctx) ((gsize) UCONTEXT_GREGS((ctx))[29])
-#define ARCH_SIGCTX_IP(ctx) ((gsize) UCONTEXT_REG_PC((ctx)))
-
#elif defined(__s390x__)
#define REDZONE_SIZE 0
-#include
-
#define USE_MONO_CTX
#define ARCH_NUM_REGS 16
-#define ARCH_SIGCTX_SP(ctx) ((UCONTEXT_GREGS((ctx))) [15])
-#define ARCH_SIGCTX_IP(ctx) ((ucontext_t *) (ctx))->uc_mcontext.psw.addr
#elif defined(__sparc__)
diff --git a/mono/metadata/sgen-cardtable.c b/mono/metadata/sgen-cardtable.c
index aab3bcb6153..6dd91e24442 100644
--- a/mono/metadata/sgen-cardtable.c
+++ b/mono/metadata/sgen-cardtable.c
@@ -455,6 +455,9 @@ sgen_card_table_finish_scan_remsets (void *start_nursery, void *end_nursery, Sge
guint8*
mono_gc_get_card_table (int *shift_bits, gpointer *mask)
{
+#ifndef MANAGED_WBARRIER
+ return NULL;
+#else
if (!sgen_cardtable)
return NULL;
@@ -466,6 +469,7 @@ mono_gc_get_card_table (int *shift_bits, gpointer *mask)
#endif
return sgen_cardtable;
+#endif
}
gboolean
@@ -475,22 +479,6 @@ mono_gc_card_table_nursery_check (void)
}
#if 0
-static void
-collect_faulted_cards (void)
-{
-#define CARD_PAGES (CARD_COUNT_IN_BYTES / 4096)
- int i, count = 0;
- unsigned char faulted [CARD_PAGES] = { 0 };
- mincore (sgen_cardtable, CARD_COUNT_IN_BYTES, faulted);
-
- for (i = 0; i < CARD_PAGES; ++i) {
- if (faulted [i])
- ++count;
- }
-
- printf ("TOTAL card pages %d faulted %d\n", CARD_PAGES, count);
-}
-
void
sgen_card_table_dump_obj_card (char *object, size_t size, void *dummy)
{
@@ -683,9 +671,9 @@ sgen_cardtable_scan_object (char *obj, mword block_obj_size, guint8 *cards, gboo
HEAVY_STAT (++bloby_objects);
if (cards) {
if (sgen_card_table_is_range_marked (cards, (mword)obj, block_obj_size))
- sgen_get_current_object_ops ()->scan_object (obj, queue);
+ sgen_get_current_object_ops ()->scan_object (obj, sgen_obj_get_descriptor (obj), queue);
} else if (sgen_card_table_region_begin_scanning ((mword)obj, block_obj_size)) {
- sgen_get_current_object_ops ()->scan_object (obj, queue);
+ sgen_get_current_object_ops ()->scan_object (obj, sgen_obj_get_descriptor (obj), queue);
}
binary_protocol_card_scan (obj, sgen_safe_object_get_size ((MonoObject*)obj));
diff --git a/mono/metadata/sgen-conf.h b/mono/metadata/sgen-conf.h
index 009d0f66ee2..babee94026e 100644
--- a/mono/metadata/sgen-conf.h
+++ b/mono/metadata/sgen-conf.h
@@ -41,6 +41,12 @@ typedef guint64 mword;
*/
// #define HEAVY_STATISTICS
+#ifdef HEAVY_STATISTICS
+#define HEAVY_STAT(x) x
+#else
+#define HEAVY_STAT(x)
+#endif
+
/*
* Define this to allow the user to change the nursery size by
* specifying its value in the MONO_GC_PARAMS environmental
diff --git a/mono/metadata/sgen-copy-object.h b/mono/metadata/sgen-copy-object.h
index dec0d073fe0..21331c18f06 100644
--- a/mono/metadata/sgen-copy-object.h
+++ b/mono/metadata/sgen-copy-object.h
@@ -18,6 +18,9 @@
* License 2.0 along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
+#include "mono/utils/mono-compiler.h"
+
extern long long stat_copy_object_called_nursery;
extern long long stat_objects_copied_nursery;
@@ -31,13 +34,9 @@ extern long long stat_slots_allocated_in_vain;
* This function can be used even if the vtable of obj is not valid
* anymore, which is the case in the parallel collector.
*/
-static inline void
+static MONO_ALWAYS_INLINE void
par_copy_object_no_checks (char *destination, MonoVTable *vt, void *obj, mword objsize, SgenGrayQueue *queue)
{
-#ifdef __GNUC__
- static const void *copy_labels [] = { &&LAB_0, &&LAB_1, &&LAB_2, &&LAB_3, &&LAB_4, &&LAB_5, &&LAB_6, &&LAB_7, &&LAB_8 };
-#endif
-
SGEN_ASSERT (9, vt->klass->inited, "vtable %p for class %s:%s was not initialized", vt, vt->klass->name_space, vt->klass->name);
SGEN_LOG (9, " (to %p, %s size: %lu)", destination, ((MonoObject*)obj)->vtable->klass->name, (unsigned long)objsize);
binary_protocol_copy (obj, destination, vt, objsize);
@@ -50,35 +49,8 @@ par_copy_object_no_checks (char *destination, MonoVTable *vt, void *obj, mword o
}
#endif
-#ifdef __GNUC__
- if (objsize <= sizeof (gpointer) * 8) {
- mword *dest = (mword*)destination;
- goto *copy_labels [objsize / sizeof (gpointer)];
- LAB_8:
- (dest) [7] = ((mword*)obj) [7];
- LAB_7:
- (dest) [6] = ((mword*)obj) [6];
- LAB_6:
- (dest) [5] = ((mword*)obj) [5];
- LAB_5:
- (dest) [4] = ((mword*)obj) [4];
- LAB_4:
- (dest) [3] = ((mword*)obj) [3];
- LAB_3:
- (dest) [2] = ((mword*)obj) [2];
- LAB_2:
- (dest) [1] = ((mword*)obj) [1];
- LAB_1:
- ;
- LAB_0:
- ;
- } else {
- /*can't trust memcpy doing word copies */
- mono_gc_memmove_aligned (destination + sizeof (mword), (char*)obj + sizeof (mword), objsize - sizeof (mword));
- }
-#else
- mono_gc_memmove_aligned (destination + sizeof (mword), (char*)obj + sizeof (mword), objsize - sizeof (mword));
-#endif
+ memcpy (destination + sizeof (mword), (char*)obj + sizeof (mword), objsize - sizeof (mword));
+
/* adjust array->bounds */
SGEN_ASSERT (9, vt->gc_descr, "vtable %p for class %s:%s has no gc descriptor", vt, vt->klass->name_space, vt->klass->name);
@@ -92,18 +64,14 @@ par_copy_object_no_checks (char *destination, MonoVTable *vt, void *obj, mword o
obj = destination;
if (queue) {
SGEN_LOG (9, "Enqueuing gray object %p (%s)", obj, sgen_safe_name (obj));
- GRAY_OBJECT_ENQUEUE (queue, obj);
+ GRAY_OBJECT_ENQUEUE (queue, obj, sgen_vtable_get_descriptor (vt));
}
}
/*
* This can return OBJ itself on OOM.
*/
-#ifdef _MSC_VER
-static __declspec(noinline) void*
-#else
-static G_GNUC_UNUSED void* __attribute__((noinline))
-#endif
+static MONO_NEVER_INLINE void*
copy_object_no_checks (void *obj, SgenGrayQueue *queue)
{
MonoVTable *vt = ((MonoObject*)obj)->vtable;
diff --git a/mono/metadata/sgen-debug.c b/mono/metadata/sgen-debug.c
index 1387676c758..113078c1839 100644
--- a/mono/metadata/sgen-debug.c
+++ b/mono/metadata/sgen-debug.c
@@ -174,7 +174,8 @@ static gboolean missing_remsets;
static void
check_consistency_callback (char *start, size_t size, void *dummy)
{
- GCVTable *vt = (GCVTable*)LOAD_VTABLE (start);
+ MonoVTable *vt = (MonoVTable*)LOAD_VTABLE (start);
+ mword desc = sgen_vtable_get_descriptor (vt);
SGEN_LOG (8, "Scanning object %p, vtable: %p (%s)", start, vt, vt->klass->name);
#include "sgen-scan-object.h"
@@ -230,7 +231,8 @@ static void
check_mod_union_callback (char *start, size_t size, void *dummy)
{
gboolean in_los = (gboolean) (size_t) dummy;
- GCVTable *vt = (GCVTable*)LOAD_VTABLE (start);
+ MonoVTable *vt = (MonoVTable*)LOAD_VTABLE (start);
+ mword desc = sgen_vtable_get_descriptor (vt);
guint8 *cards;
SGEN_LOG (8, "Scanning object %p, vtable: %p (%s)", start, vt, vt->klass->name);
@@ -269,6 +271,8 @@ sgen_check_mod_union_consistency (void)
static void
check_major_refs_callback (char *start, size_t size, void *dummy)
{
+ mword desc = sgen_obj_get_descriptor (start);
+
#include "sgen-scan-object.h"
}
@@ -296,9 +300,13 @@ sgen_check_major_refs (void)
void
check_object (char *start)
{
+ mword desc;
+
if (!start)
return;
+ desc = sgen_obj_get_descriptor (start);
+
#include "sgen-scan-object.h"
}
@@ -425,6 +433,7 @@ static void
verify_object_pointers_callback (char *start, size_t size, void *data)
{
gboolean allow_missing_pinned = (gboolean) (size_t) data;
+ mword desc = sgen_obj_get_descriptor (start);
#include "sgen-scan-object.h"
}
@@ -548,6 +557,7 @@ static void
check_marked_callback (char *start, size_t size, void *dummy)
{
gboolean is_los = (gboolean) (size_t) dummy;
+ mword desc;
if (is_los) {
if (!sgen_los_object_is_pinned (start))
@@ -557,6 +567,8 @@ check_marked_callback (char *start, size_t size, void *dummy)
return;
}
+ desc = sgen_obj_get_descriptor (start);
+
#include "sgen-scan-object.h"
}
@@ -608,6 +620,7 @@ scan_object_for_specific_ref (char *start, MonoObject *key)
start = forwarded;
if (scan_object_for_specific_ref_precise) {
+ mword desc = sgen_obj_get_descriptor (start);
#include "sgen-scan-object.h"
} else {
mword *words = (mword*)start;
@@ -896,7 +909,9 @@ check_reference_for_xdomain (gpointer *ptr, char *obj, MonoDomain *domain)
static void
scan_object_for_xdomain_refs (char *start, mword size, void *data)
{
- MonoDomain *domain = ((MonoObject*)start)->vtable->domain;
+ MonoVTable *vt = (MonoVTable*)SGEN_LOAD_VTABLE (start);
+ MonoDomain *domain = vt->domain;
+ mword desc = sgen_vtable_get_descriptor (vt);
#include "sgen-scan-object.h"
}
diff --git a/mono/metadata/sgen-descriptor.c b/mono/metadata/sgen-descriptor.c
index c578a91cfb2..6da8f7290d9 100644
--- a/mono/metadata/sgen-descriptor.c
+++ b/mono/metadata/sgen-descriptor.c
@@ -43,6 +43,7 @@
#define _XOPEN_SOURCE
#endif
+#include "utils/mono-counters.h"
#include "metadata/sgen-gc.h"
#define MAX_USER_DESCRIPTORS 16
@@ -58,6 +59,9 @@ static MonoGCRootMarkFunc user_descriptors [MAX_USER_DESCRIPTORS];
static int user_descriptors_next = 0;
static void *all_ref_root_descrs [32];
+#ifdef HEAVY_STATISTICS
+static long long stat_scanned_count_per_descriptor [DESC_TYPE_MAX];
+#endif
static int
alloc_complex_descriptor (gsize *bitmap, int numbits)
@@ -348,4 +352,28 @@ sgen_get_user_descriptor_func (mword desc)
return user_descriptors [desc >> ROOT_DESC_TYPE_SHIFT];
}
+#ifdef HEAVY_STATISTICS
+void
+sgen_descriptor_count_scanned_object (mword desc)
+{
+ int type = desc & 7;
+ SGEN_ASSERT (0, type, "Descriptor type can't be zero");
+ ++stat_scanned_count_per_descriptor [type - 1];
+}
+#endif
+
+void
+sgen_init_descriptors (void)
+{
+#ifdef HEAVY_STATISTICS
+ mono_counters_register ("# scanned RUN_LENGTH", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_scanned_count_per_descriptor [DESC_TYPE_RUN_LENGTH - 1]);
+ mono_counters_register ("# scanned SMALL_BITMAP", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_scanned_count_per_descriptor [DESC_TYPE_SMALL_BITMAP - 1]);
+ mono_counters_register ("# scanned COMPLEX", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_scanned_count_per_descriptor [DESC_TYPE_COMPLEX - 1]);
+ mono_counters_register ("# scanned VECTOR", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_scanned_count_per_descriptor [DESC_TYPE_VECTOR - 1]);
+ mono_counters_register ("# scanned LARGE_BITMAP", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_scanned_count_per_descriptor [DESC_TYPE_LARGE_BITMAP - 1]);
+ mono_counters_register ("# scanned COMPLEX_ARR", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_scanned_count_per_descriptor [DESC_TYPE_COMPLEX_ARR - 1]);
+ mono_counters_register ("# scanned COMPLEX_PTRFREE", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_scanned_count_per_descriptor [DESC_TYPE_COMPLEX_PTRFREE - 1]);
+#endif
+}
+
#endif
diff --git a/mono/metadata/sgen-descriptor.h b/mono/metadata/sgen-descriptor.h
index 366c7667778..c06354dd958 100644
--- a/mono/metadata/sgen-descriptor.h
+++ b/mono/metadata/sgen-descriptor.h
@@ -82,13 +82,14 @@ enum {
* copy_object_no_checks(), without having to fetch the
* object's class.
*/
- DESC_TYPE_RUN_LENGTH = 1, /* 16 bits aligned byte size | 1-3 (offset, numptr) bytes tuples */
- DESC_TYPE_SMALL_BITMAP, /* 16 bits aligned byte size | 16-48 bit bitmap */
- DESC_TYPE_COMPLEX, /* index for bitmap into complex_descriptors */
- DESC_TYPE_VECTOR, /* 10 bits element size | 1 bit kind | 2 bits desc | element desc */
- DESC_TYPE_LARGE_BITMAP, /* | 29-61 bitmap bits */
- DESC_TYPE_COMPLEX_ARR, /* index for bitmap into complex_descriptors */
- DESC_TYPE_COMPLEX_PTRFREE, /*Nothing, used to encode large ptr objects. */
+ DESC_TYPE_RUN_LENGTH = 1, /* 16 bits aligned byte size | 1-3 (offset, numptr) bytes tuples */
+ DESC_TYPE_SMALL_BITMAP = 2, /* 16 bits aligned byte size | 16-48 bit bitmap */
+ DESC_TYPE_COMPLEX = 3, /* index for bitmap into complex_descriptors */
+ DESC_TYPE_VECTOR = 4, /* 10 bits element size | 1 bit kind | 2 bits desc | element desc */
+ DESC_TYPE_LARGE_BITMAP = 5, /* | 29-61 bitmap bits */
+ DESC_TYPE_COMPLEX_ARR = 6, /* index for bitmap into complex_descriptors */
+ DESC_TYPE_COMPLEX_PTRFREE = 7, /*Nothing, used to encode large ptr objects. */
+ DESC_TYPE_MAX = 7,
/* values for array kind */
DESC_TYPE_V_SZARRAY = 0, /*vector with no bounds data */
DESC_TYPE_V_ARRAY = 1, /* array with bounds data */
@@ -117,6 +118,11 @@ gsize* sgen_get_complex_descriptor (mword desc) MONO_INTERNAL;
void* sgen_get_complex_descriptor_bitmap (mword desc) MONO_INTERNAL;
MonoGCRootMarkFunc sgen_get_user_descriptor_func (mword desc) MONO_INTERNAL;
+void sgen_init_descriptors (void) MONO_INTERNAL;
+
+#ifdef HEAVY_STATISTICS
+void sgen_descriptor_count_scanned_object (mword desc) MONO_INTERNAL;
+#endif
static inline gboolean
sgen_gc_descr_has_references (mword desc)
@@ -168,8 +174,6 @@ sgen_gc_descr_has_references (mword desc)
void **_objptr = (void**)(obj); \
_objptr += ((desc) >> 16) & 0xff; \
_objptr_end = _objptr + (((desc) >> 24) & 0xff); \
- HANDLE_PTR (_objptr, (obj)); \
- _objptr ++; \
while (_objptr < _objptr_end) { \
HANDLE_PTR (_objptr, (obj)); \
_objptr++; \
@@ -183,20 +187,13 @@ sgen_gc_descr_has_references (mword desc)
void **_objptr = (void**)(obj); \
gsize _bmap = (desc) >> 16; \
_objptr += OBJECT_HEADER_WORDS; \
- { \
- int _index = GNUC_BUILTIN_CTZ (_bmap); \
- _objptr += _index; \
- _bmap >>= (_index + 1); \
- HANDLE_PTR (_objptr, (obj)); \
- _objptr ++; \
- } \
- while (_bmap) { \
+ do { \
int _index = GNUC_BUILTIN_CTZ (_bmap); \
_objptr += _index; \
_bmap >>= (_index + 1); \
HANDLE_PTR (_objptr, (obj)); \
_objptr ++; \
- } \
+ } while (_bmap); \
} while (0)
#else
#define OBJ_BITMAP_FOREACH_PTR(desc,obj) do { \
@@ -258,15 +255,16 @@ sgen_gc_descr_has_references (mword desc)
} while (0)
/* this one is untested */
-#define OBJ_COMPLEX_ARR_FOREACH_PTR(vt,obj) do { \
+#define OBJ_COMPLEX_ARR_FOREACH_PTR(desc,obj) do { \
/* there are pointers */ \
- gsize *mbitmap_data = sgen_get_complex_descriptor ((vt)->desc); \
+ GCVTable *vt = (GCVTable*)SGEN_LOAD_VTABLE (obj); \
+ gsize *mbitmap_data = sgen_get_complex_descriptor ((desc)); \
gsize mbwords = (*mbitmap_data++) - 1; \
gsize el_size = mono_array_element_size (vt->klass); \
char *e_start = (char*)(obj) + G_STRUCT_OFFSET (MonoArray, vector); \
char *e_end = e_start + el_size * mono_array_length_fast ((MonoArray*)(obj)); \
if (0) \
- g_print ("found %d at %p (0x%zx): %s.%s\n", mbwords, (obj), (vt)->desc, vt->klass->name_space, vt->klass->name); \
+ g_print ("found %d at %p (0x%zx): %s.%s\n", mbwords, (obj), (desc), (vt)->klass->name_space, (vt)->klass->name); \
while (e_start < e_end) { \
void **_objptr = (void**)e_start; \
gsize *bitmap_data = mbitmap_data; \
diff --git a/mono/metadata/sgen-gc.c b/mono/metadata/sgen-gc.c
index 8e1d05e1663..c9a0792c519 100644
--- a/mono/metadata/sgen-gc.c
+++ b/mono/metadata/sgen-gc.c
@@ -285,12 +285,12 @@ static gboolean do_scan_starts_check = FALSE;
* GC.Collect().
*/
static gboolean allow_synchronous_major = TRUE;
-static gboolean nursery_collection_is_parallel = FALSE;
static gboolean disable_minor_collections = FALSE;
static gboolean disable_major_collections = FALSE;
gboolean do_pin_stats = FALSE;
static gboolean do_verify_nursery = FALSE;
static gboolean do_dump_nursery_content = FALSE;
+static gboolean enable_nursery_canaries = FALSE;
#ifdef HEAVY_STATISTICS
long long stat_objects_alloced_degraded = 0;
@@ -347,6 +347,14 @@ static long long time_major_los_sweep = 0;
static long long time_major_sweep = 0;
static long long time_major_fragment_creation = 0;
+static long long time_max = 0;
+
+static SGEN_TV_DECLARE (time_major_conc_collection_start);
+static SGEN_TV_DECLARE (time_major_conc_collection_end);
+
+static SGEN_TV_DECLARE (last_minor_collection_start_tv);
+static SGEN_TV_DECLARE (last_minor_collection_end_tv);
+
int gc_debug_level = 0;
FILE* gc_debug_file;
@@ -387,6 +395,12 @@ safe_name (void* obj)
return vt->klass->name;
}
+gboolean
+nursery_canaries_enabled (void)
+{
+ return enable_nursery_canaries;
+}
+
#define safe_object_get_size sgen_safe_object_get_size
const char*
@@ -597,8 +611,7 @@ gray_queue_redirect (SgenGrayQueue *queue)
}
if (wake) {
- g_assert (concurrent_collection_in_progress ||
- (current_collection_generation == GENERATION_OLD && major_collector.is_parallel));
+ g_assert (concurrent_collection_in_progress);
if (sgen_workers_have_started ()) {
sgen_workers_wake_up_all ();
} else {
@@ -627,10 +640,14 @@ sgen_scan_area_with_callback (char *start, char *end, IterateObjectCallbackFunc
obj = start;
}
- size = ALIGN_UP (safe_object_get_size ((MonoObject*)obj));
-
- if ((MonoVTable*)SGEN_LOAD_VTABLE (obj) != array_fill_vtable)
+ if ((MonoVTable*)SGEN_LOAD_VTABLE (obj) != array_fill_vtable) {
+ CHECK_CANARY_FOR_OBJECT (obj);
+ size = ALIGN_UP (safe_object_get_size ((MonoObject*)obj));
callback (obj, size, data);
+ CANARIFY_SIZE (size);
+ } else {
+ size = ALIGN_UP (safe_object_get_size ((MonoObject*)obj));
+ }
start += size;
}
@@ -689,8 +706,10 @@ clear_domain_process_object (char *obj, MonoDomain *domain)
static void
clear_domain_process_minor_object_callback (char *obj, size_t size, MonoDomain *domain)
{
- if (clear_domain_process_object (obj, domain))
+ if (clear_domain_process_object (obj, domain)) {
+ CANARIFY_SIZE (size);
memset (obj, 0, size);
+ }
}
static void
@@ -857,36 +876,29 @@ sgen_add_to_global_remset (gpointer ptr, gpointer obj)
* Scan objects in the gray stack until the stack is empty. This should be called
* frequently after each object is copied, to achieve better locality and cache
* usage.
+ *
+ * max_objs is the maximum number of objects to scan, or -1 to scan until the stack is
+ * empty.
*/
gboolean
sgen_drain_gray_stack (int max_objs, ScanCopyContext ctx)
{
- char *obj;
ScanObjectFunc scan_func = ctx.scan_func;
GrayQueue *queue = ctx.queue;
- if (max_objs == -1) {
- for (;;) {
- GRAY_OBJECT_DEQUEUE (queue, &obj);
+ do {
+ int i;
+ for (i = 0; i != max_objs; ++i) {
+ char *obj;
+ mword desc;
+ GRAY_OBJECT_DEQUEUE (queue, &obj, &desc);
if (!obj)
return TRUE;
SGEN_LOG (9, "Precise gray object scan %p (%s)", obj, safe_name (obj));
- scan_func (obj, queue);
+ scan_func (obj, desc, queue);
}
- } else {
- int i;
-
- do {
- for (i = 0; i != max_objs; ++i) {
- GRAY_OBJECT_DEQUEUE (queue, &obj);
- if (!obj)
- return TRUE;
- SGEN_LOG (9, "Precise gray object scan %p (%s)", obj, safe_name (obj));
- scan_func (obj, queue);
- }
- } while (max_objs < 0);
- return FALSE;
- }
+ } while (max_objs < 0);
+ return FALSE;
}
/*
@@ -900,8 +912,8 @@ static int
pin_objects_from_nursery_pin_queue (ScanCopyContext ctx)
{
GCMemSection *section = nursery_section;
- void **start = section->pin_queue_start;
- void **end = start + section->pin_queue_num_entries;
+ void **start = sgen_pinning_get_entry (section->pin_queue_first_entry);
+ void **end = sgen_pinning_get_entry (section->pin_queue_last_entry);
void *start_nursery = section->data;
void *end_nursery = section->next_data;
void *last = NULL;
@@ -919,6 +931,7 @@ pin_objects_from_nursery_pin_queue (ScanCopyContext ctx)
while (start < end) {
void *obj_to_pin = NULL;
size_t obj_to_pin_size = 0;
+ mword desc;
addr = *start;
@@ -988,6 +1001,11 @@ pin_objects_from_nursery_pin_queue (ScanCopyContext ctx)
}
/* Skip to the next object */
+ if (((MonoObject*)search_start)->synchronisation != GINT_TO_POINTER (-1)) {
+ CHECK_CANARY_FOR_OBJECT (search_start);
+ CANARIFY_SIZE (obj_size);
+ CANARIFY_SIZE (obj_to_pin_size);
+ }
search_start = (void*)((char*)search_start + obj_size);
} while (search_start <= addr);
@@ -1013,8 +1031,9 @@ pin_objects_from_nursery_pin_queue (ScanCopyContext ctx)
/*
* Finally - pin the object!
*/
+ desc = sgen_obj_get_descriptor_safe (obj_to_pin);
if (scan_func) {
- scan_func (obj_to_pin, queue);
+ scan_func (obj_to_pin, desc, queue);
} else {
SGEN_LOG (4, "Pinned object %p, vtable %p (%s), count %d\n",
obj_to_pin, *(void**)obj_to_pin, safe_name (obj_to_pin), count);
@@ -1033,7 +1052,7 @@ pin_objects_from_nursery_pin_queue (ScanCopyContext ctx)
#endif
pin_object (obj_to_pin);
- GRAY_OBJECT_ENQUEUE (queue, obj_to_pin);
+ GRAY_OBJECT_ENQUEUE (queue, obj_to_pin, desc);
if (G_UNLIKELY (do_pin_stats))
sgen_pin_stats_register_object (obj_to_pin, obj_to_pin_size);
definitely_pinned [count] = obj_to_pin;
@@ -1061,13 +1080,11 @@ pin_objects_in_nursery (ScanCopyContext ctx)
{
size_t reduced_to;
- if (!nursery_section->pin_queue_num_entries)
+ if (nursery_section->pin_queue_first_entry == nursery_section->pin_queue_last_entry)
return;
reduced_to = pin_objects_from_nursery_pin_queue (ctx);
- nursery_section->pin_queue_num_entries = reduced_to;
- if (!reduced_to)
- nursery_section->pin_queue_start = NULL;
+ nursery_section->pin_queue_last_entry = nursery_section->pin_queue_first_entry + reduced_to;
}
@@ -1076,20 +1093,13 @@ sgen_pin_object (void *object, GrayQueue *queue)
{
g_assert (!concurrent_collection_in_progress);
- if (sgen_collection_is_parallel ()) {
- LOCK_PIN_QUEUE;
- /*object arrives pinned*/
- sgen_pin_stage_ptr (object);
- ++objects_pinned ;
- UNLOCK_PIN_QUEUE;
- } else {
- SGEN_PIN_OBJECT (object);
- sgen_pin_stage_ptr (object);
- ++objects_pinned;
- if (G_UNLIKELY (do_pin_stats))
- sgen_pin_stats_register_object (object, safe_object_get_size (object));
- }
- GRAY_OBJECT_ENQUEUE (queue, object);
+ SGEN_PIN_OBJECT (object);
+ sgen_pin_stage_ptr (object);
+ ++objects_pinned;
+ if (G_UNLIKELY (do_pin_stats))
+ sgen_pin_stats_register_object (object, safe_object_get_size (object));
+
+ GRAY_OBJECT_ENQUEUE (queue, object, sgen_obj_get_descriptor_safe (object));
binary_protocol_pin (object, (gpointer)LOAD_VTABLE (object), safe_object_get_size (object));
#ifdef ENABLE_DTRACE
@@ -1109,7 +1119,7 @@ sgen_parallel_pin_or_update (void **ptr, void *obj, MonoVTable *vt, SgenGrayQueu
gboolean major_pinned = FALSE;
if (sgen_ptr_in_nursery (obj)) {
- if (SGEN_CAS_PTR (obj, (void*)((mword)vt | SGEN_PINNED_BIT), vt) == vt) {
+ if (SGEN_CAS_PTR (obj, SGEN_POINTER_TAG_PINNED (vt), vt) == vt) {
sgen_pin_object (obj, queue);
break;
}
@@ -1120,13 +1130,13 @@ sgen_parallel_pin_or_update (void **ptr, void *obj, MonoVTable *vt, SgenGrayQueu
vtable_word = *(mword*)obj;
/*someone else forwarded it, update the pointer and bail out*/
- if (vtable_word & SGEN_FORWARDED_BIT) {
- *ptr = (void*)(vtable_word & ~SGEN_VTABLE_BITS_MASK);
+ if (SGEN_POINTER_IS_TAGGED_FORWARDED (vtable_word)) {
+ *ptr = SGEN_POINTER_UNTAG_VTABLE (vtable_word);
break;
}
/*someone pinned it, nothing to do.*/
- if (vtable_word & SGEN_PINNED_BIT || major_pinned)
+ if (SGEN_POINTER_IS_TAGGED_PINNED (vtable_word) || major_pinned)
break;
}
}
@@ -1264,7 +1274,8 @@ unpin_objects_from_queue (SgenGrayQueue *queue)
{
for (;;) {
char *addr;
- GRAY_OBJECT_DEQUEUE (queue, &addr);
+ mword desc;
+ GRAY_OBJECT_DEQUEUE (queue, &addr, &desc);
if (!addr)
break;
g_assert (SGEN_OBJECT_IS_PINNED (addr));
@@ -1735,6 +1746,8 @@ finish_gray_stack (int generation, GrayQueue *queue)
}
g_assert (sgen_gray_object_queue_is_empty (queue));
+
+ sgen_gray_object_queue_trim_free_list (queue);
}
void
@@ -1899,9 +1912,6 @@ sgen_register_moved_object (void *obj, void *destination)
{
g_assert (mono_profiler_events & MONO_PROFILE_GC_MOVES);
- /* FIXME: handle this for parallel collector */
- g_assert (!sgen_collection_is_parallel ());
-
if (moved_objects_idx == MOVED_OBJECTS_NUM) {
mono_profiler_gc_moves (moved_objects, moved_objects_idx);
moved_objects_idx = 0;
@@ -1918,6 +1928,8 @@ init_stats (void)
if (inited)
return;
+ mono_counters_register ("Collection max time", MONO_COUNTER_GC | MONO_COUNTER_LONG | MONO_COUNTER_TIME | MONO_COUNTER_MONOTONIC, &time_max);
+
mono_counters_register ("Minor fragment clear", MONO_COUNTER_GC | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &time_minor_pre_collection_fragment_clear);
mono_counters_register ("Minor pinning", MONO_COUNTER_GC | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &time_minor_pinning);
mono_counters_register ("Minor scan remembered set", MONO_COUNTER_GC | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &time_minor_scan_remsets);
@@ -1992,19 +2004,6 @@ sgen_set_pinned_from_failed_allocation (mword objsize)
bytes_pinned_from_failed_allocation += objsize;
}
-gboolean
-sgen_collection_is_parallel (void)
-{
- switch (current_collection_generation) {
- case GENERATION_NURSERY:
- return nursery_collection_is_parallel;
- case GENERATION_OLD:
- return major_collector.is_parallel;
- default:
- g_error ("Invalid current generation %d", current_collection_generation);
- }
-}
-
gboolean
sgen_collection_is_concurrent (void)
{
@@ -2075,19 +2074,13 @@ job_scan_thread_data (WorkerData *worker_data, void *job_data_untyped)
sgen_free_internal_dynamic (job_data, sizeof (ScanThreadDataJobData), INTERNAL_MEM_WORKER_JOB_DATA);
}
-typedef struct
-{
- FinalizeReadyEntry *list;
-} ScanFinalizerEntriesJobData;
-
static void
job_scan_finalizer_entries (WorkerData *worker_data, void *job_data_untyped)
{
- ScanFinalizerEntriesJobData *job_data = job_data_untyped;
+ FinalizeReadyEntry *list = job_data_untyped;
ScanCopyContext ctx = { NULL, current_object_ops.copy_or_mark_object, sgen_workers_get_job_gray_queue (worker_data) };
- scan_finalizer_entries (job_data->list, ctx);
- sgen_free_internal_dynamic (job_data, sizeof (ScanFinalizerEntriesJobData), INTERNAL_MEM_WORKER_JOB_DATA);
+ scan_finalizer_entries (list, ctx);
}
static void
@@ -2123,6 +2116,9 @@ verify_nursery (void)
if (!do_verify_nursery)
return;
+
+ if (nursery_canaries_enabled ())
+ SGEN_LOG (1, "Checking nursery canaries...");
/*This cleans up unused fragments */
sgen_nursery_allocator_prepare_for_pinning ();
@@ -2151,6 +2147,10 @@ verify_nursery (void)
SGEN_LOG (1, "HOLE [%p %p %d]", hole_start, cur, (int)(cur - hole_start));
SGEN_LOG (1, "OBJ [%p %p %d %d %s %d]", cur, cur + size, (int)size, (int)ss, sgen_safe_name ((MonoObject*)cur), (gpointer)LOAD_VTABLE (cur) == sgen_get_array_fill_vtable ());
}
+ if (nursery_canaries_enabled () && (MonoVTable*)SGEN_LOAD_VTABLE (cur) != array_fill_vtable) {
+ CHECK_CANARY_FOR_OBJECT (cur);
+ CANARIFY_SIZE (size);
+ }
cur += size;
hole_start = cur;
}
@@ -2192,7 +2192,7 @@ check_nursery_is_clean (void)
static void
init_gray_queue (void)
{
- if (sgen_collection_is_parallel () || sgen_collection_is_concurrent ()) {
+ if (sgen_collection_is_concurrent ()) {
sgen_workers_init_distribute_gray_queue ();
sgen_gray_object_queue_init_with_alloc_prepare (&gray_queue, NULL,
gray_queue_redirect, sgen_workers_get_distribute_section_gray_queue ());
@@ -2201,13 +2201,6 @@ init_gray_queue (void)
}
}
-static void
-pin_stage_object_callback (char *obj, size_t size, void *data)
-{
- sgen_pin_stage_ptr (obj);
- /* FIXME: do pin stats if enabled */
-}
-
/*
* Collect objects in the nursery. Returns whether to trigger a major
* collection.
@@ -2220,18 +2213,18 @@ collect_nursery (SgenGrayQueue *unpin_queue, gboolean finish_up_concurrent_mark)
char *nursery_next;
FinishRememberedSetScanJobData *frssjd;
ScanFromRegisteredRootsJobData *scrrjd_normal, *scrrjd_wbarrier;
- ScanFinalizerEntriesJobData *sfejd_fin_ready, *sfejd_critical_fin;
ScanThreadDataJobData *stdjd;
mword fragment_total;
ScanCopyContext ctx;
- TV_DECLARE (all_atv);
- TV_DECLARE (all_btv);
TV_DECLARE (atv);
TV_DECLARE (btv);
if (disable_minor_collections)
return TRUE;
+ TV_GETTIME (last_minor_collection_start_tv);
+ atv = last_minor_collection_start_tv;
+
MONO_GC_BEGIN (GENERATION_NURSERY);
binary_protocol_collection_begin (gc_stats.minor_gc_count, GENERATION_NURSERY);
@@ -2242,11 +2235,8 @@ collect_nursery (SgenGrayQueue *unpin_queue, gboolean finish_up_concurrent_mark)
#endif
current_collection_generation = GENERATION_NURSERY;
- if (sgen_collection_is_parallel ())
- current_object_ops = sgen_minor_collector.parallel_ops;
- else
- current_object_ops = sgen_minor_collector.serial_ops;
-
+ current_object_ops = sgen_minor_collector.serial_ops;
+
reset_pinned_from_failed_allocation ();
check_scan_starts ();
@@ -2264,9 +2254,6 @@ collect_nursery (SgenGrayQueue *unpin_queue, gboolean finish_up_concurrent_mark)
g_assert (nursery_section->size >= max_garbage_amount);
/* world must be stopped already */
- TV_GETTIME (all_atv);
- atv = all_atv;
-
TV_GETTIME (btv);
time_minor_pre_collection_fragment_clear += TV_ELAPSED (atv, btv);
@@ -2297,9 +2284,9 @@ collect_nursery (SgenGrayQueue *unpin_queue, gboolean finish_up_concurrent_mark)
mono_profiler_gc_event (MONO_GC_EVENT_MARK_START, 0);
pin_from_roots (sgen_get_nursery_start (), nursery_next, WORKERS_DISTRIBUTE_GRAY_QUEUE);
/* pin cemented objects */
- sgen_cement_iterate (pin_stage_object_callback, NULL);
+ sgen_pin_cemented_objects ();
/* identify pinned objects */
- sgen_optimize_pin_queue (0);
+ sgen_optimize_pin_queue ();
sgen_pinning_setup_section (nursery_section);
ctx.scan_func = NULL;
ctx.copy_func = NULL;
@@ -2336,12 +2323,11 @@ collect_nursery (SgenGrayQueue *unpin_queue, gboolean finish_up_concurrent_mark)
MONO_GC_CHECKPOINT_4 (GENERATION_NURSERY);
- if (!sgen_collection_is_parallel ()) {
- ctx.scan_func = current_object_ops.scan_object;
- ctx.copy_func = NULL;
- ctx.queue = &gray_queue;
- sgen_drain_gray_stack (-1, ctx);
- }
+ /* FIXME: why is this here? */
+ ctx.scan_func = current_object_ops.scan_object;
+ ctx.copy_func = NULL;
+ ctx.queue = &gray_queue;
+ sgen_drain_gray_stack (-1, ctx);
if (mono_profiler_get_events () & MONO_PROFILE_GC_ROOTS)
report_registered_roots ();
@@ -2386,19 +2372,11 @@ collect_nursery (SgenGrayQueue *unpin_queue, gboolean finish_up_concurrent_mark)
MONO_GC_CHECKPOINT_7 (GENERATION_NURSERY);
- g_assert (!sgen_collection_is_parallel () && !sgen_collection_is_concurrent ());
-
- if (sgen_collection_is_parallel () || sgen_collection_is_concurrent ())
- g_assert (sgen_gray_object_queue_is_empty (&gray_queue));
+ g_assert (!sgen_collection_is_concurrent ());
/* Scan the list of objects ready for finalization. If */
- sfejd_fin_ready = sgen_alloc_internal_dynamic (sizeof (ScanFinalizerEntriesJobData), INTERNAL_MEM_WORKER_JOB_DATA, TRUE);
- sfejd_fin_ready->list = fin_ready_list;
- sgen_workers_enqueue_job (job_scan_finalizer_entries, sfejd_fin_ready);
-
- sfejd_critical_fin = sgen_alloc_internal_dynamic (sizeof (ScanFinalizerEntriesJobData), INTERNAL_MEM_WORKER_JOB_DATA, TRUE);
- sfejd_critical_fin->list = critical_fin_list;
- sgen_workers_enqueue_job (job_scan_finalizer_entries, sfejd_critical_fin);
+ sgen_workers_enqueue_job (job_scan_finalizer_entries, fin_ready_list);
+ sgen_workers_enqueue_job (job_scan_finalizer_entries, critical_fin_list);
MONO_GC_CHECKPOINT_8 (GENERATION_NURSERY);
@@ -2418,7 +2396,7 @@ collect_nursery (SgenGrayQueue *unpin_queue, gboolean finish_up_concurrent_mark)
sgen_workers_reset_data ();
if (objects_pinned) {
- sgen_optimize_pin_queue (0);
+ sgen_optimize_pin_queue ();
sgen_pinning_setup_section (nursery_section);
}
@@ -2427,9 +2405,7 @@ collect_nursery (SgenGrayQueue *unpin_queue, gboolean finish_up_concurrent_mark)
* next allocations.
*/
mono_profiler_gc_event (MONO_GC_EVENT_RECLAIM_START, 0);
- fragment_total = sgen_build_nursery_fragments (nursery_section,
- nursery_section->pin_queue_start, nursery_section->pin_queue_num_entries,
- unpin_queue);
+ fragment_total = sgen_build_nursery_fragments (nursery_section, unpin_queue);
if (!fragment_total)
degraded_mode = 1;
@@ -2446,8 +2422,8 @@ collect_nursery (SgenGrayQueue *unpin_queue, gboolean finish_up_concurrent_mark)
major_collector.finish_nursery_collection ();
- TV_GETTIME (all_btv);
- gc_stats.minor_gc_time += TV_ELAPSED (all_atv, all_btv);
+ TV_GETTIME (last_minor_collection_end_tv);
+ gc_stats.minor_gc_time += TV_ELAPSED (last_minor_collection_start_tv, last_minor_collection_end_tv);
if (heap_dump_file)
dump_heap ("minor", gc_stats.minor_gc_count - 1, NULL);
@@ -2489,7 +2465,11 @@ collect_nursery (SgenGrayQueue *unpin_queue, gboolean finish_up_concurrent_mark)
static void
scan_nursery_objects_callback (char *obj, size_t size, ScanCopyContext *ctx)
{
- ctx->scan_func (obj, ctx->queue);
+ /*
+ * This is called on all objects in the nursery, including pinned ones, so we need
+ * to use sgen_obj_get_descriptor_safe(), which masks out the vtable tag bits.
+ */
+ ctx->scan_func (obj, sgen_obj_get_descriptor_safe (obj), ctx->queue);
}
static void
@@ -2514,7 +2494,6 @@ major_copy_or_mark_from_roots (size_t *old_next_pin_slot, gboolean finish_up_con
GCRootReport root_report = { 0 };
ScanFromRegisteredRootsJobData *scrrjd_normal, *scrrjd_wbarrier;
ScanThreadDataJobData *stdjd;
- ScanFinalizerEntriesJobData *sfejd_fin_ready, *sfejd_critical_fin;
ScanCopyContext ctx;
if (concurrent_collection_in_progress) {
@@ -2577,14 +2556,14 @@ major_copy_or_mark_from_roots (size_t *old_next_pin_slot, gboolean finish_up_con
*
* FIXME: We could evict now!
*/
- sgen_cement_iterate (pin_stage_object_callback, NULL);
+ sgen_pin_cemented_objects ();
}
if (!concurrent_collection_in_progress)
sgen_cement_reset ();
}
- sgen_optimize_pin_queue (0);
+ sgen_optimize_pin_queue ();
/*
* The concurrent collector doesn't move objects, neither on
@@ -2617,7 +2596,7 @@ major_copy_or_mark_from_roots (size_t *old_next_pin_slot, gboolean finish_up_con
SGEN_LOG (6, "Pinning from large objects");
for (bigobj = los_object_list; bigobj; bigobj = bigobj->next) {
size_t dummy;
- if (sgen_find_optimized_pin_queue_area (bigobj->data, (char*)bigobj->data + sgen_los_object_size (bigobj), &dummy)) {
+ if (sgen_find_optimized_pin_queue_area (bigobj->data, (char*)bigobj->data + sgen_los_object_size (bigobj), &dummy, &dummy)) {
binary_protocol_pin (bigobj->data, (gpointer)LOAD_VTABLE (bigobj->data), safe_object_get_size (((MonoObject*)(bigobj->data))));
#ifdef ENABLE_DTRACE
@@ -2633,7 +2612,7 @@ major_copy_or_mark_from_roots (size_t *old_next_pin_slot, gboolean finish_up_con
}
sgen_los_pin_object (bigobj->data);
if (SGEN_OBJECT_HAS_REFERENCES (bigobj->data))
- GRAY_OBJECT_ENQUEUE (WORKERS_DISTRIBUTE_GRAY_QUEUE, bigobj->data);
+ GRAY_OBJECT_ENQUEUE (WORKERS_DISTRIBUTE_GRAY_QUEUE, bigobj->data, sgen_obj_get_descriptor (bigobj->data));
if (G_UNLIKELY (do_pin_stats))
sgen_pin_stats_register_object ((char*) bigobj->data, safe_object_get_size ((MonoObject*) bigobj->data));
SGEN_LOG (6, "Marked large object %p (%s) size: %lu from roots", bigobj->data, safe_name (bigobj->data), (unsigned long)sgen_los_object_size (bigobj));
@@ -2692,11 +2671,6 @@ major_copy_or_mark_from_roots (size_t *old_next_pin_slot, gboolean finish_up_con
main_gc_thread = mono_native_thread_self ();
#endif
- if (!concurrent_collection_in_progress && major_collector.is_parallel) {
- sgen_workers_start_all_workers ();
- sgen_workers_start_marking ();
- }
-
if (mono_profiler_get_events () & MONO_PROFILE_GC_ROOTS)
report_registered_roots ();
TV_GETTIME (atv);
@@ -2738,13 +2712,8 @@ major_copy_or_mark_from_roots (size_t *old_next_pin_slot, gboolean finish_up_con
report_finalizer_roots ();
/* scan the list of objects ready for finalization */
- sfejd_fin_ready = sgen_alloc_internal_dynamic (sizeof (ScanFinalizerEntriesJobData), INTERNAL_MEM_WORKER_JOB_DATA, TRUE);
- sfejd_fin_ready->list = fin_ready_list;
- sgen_workers_enqueue_job (job_scan_finalizer_entries, sfejd_fin_ready);
-
- sfejd_critical_fin = sgen_alloc_internal_dynamic (sizeof (ScanFinalizerEntriesJobData), INTERNAL_MEM_WORKER_JOB_DATA, TRUE);
- sfejd_critical_fin->list = critical_fin_list;
- sgen_workers_enqueue_job (job_scan_finalizer_entries, sfejd_critical_fin);
+ sgen_workers_enqueue_job (job_scan_finalizer_entries, fin_ready_list);
+ sgen_workers_enqueue_job (job_scan_finalizer_entries, critical_fin_list);
if (scan_mod_union) {
g_assert (finish_up_concurrent_mark);
@@ -2825,7 +2794,7 @@ wait_for_workers_to_finish (void)
static void
join_workers (void)
{
- if (concurrent_collection_in_progress || major_collector.is_parallel) {
+ if (concurrent_collection_in_progress) {
gray_queue_redirect (&gray_queue);
sgen_workers_join ();
}
@@ -2846,7 +2815,7 @@ major_finish_collection (const char *reason, size_t old_next_pin_slot, gboolean
TV_GETTIME (btv);
- if (concurrent_collection_in_progress || major_collector.is_parallel)
+ if (concurrent_collection_in_progress)
join_workers ();
if (concurrent_collection_in_progress) {
@@ -2887,9 +2856,21 @@ major_finish_collection (const char *reason, size_t old_next_pin_slot, gboolean
if (objects_pinned) {
g_assert (!concurrent_collection_in_progress);
- /*This is slow, but we just OOM'd*/
+ /*
+ * This is slow, but we just OOM'd.
+ *
+ * See comment at `sgen_pin_queue_clear_discarded_entries` for how the pin
+ * queue is laid out at this point.
+ */
sgen_pin_queue_clear_discarded_entries (nursery_section, old_next_pin_slot);
- sgen_optimize_pin_queue (0);
+ /*
+ * We need to reestablish all pinned nursery objects in the pin queue
+ * because they're needed for fragment creation. Unpinning happens by
+ * walking the whole queue, so it's not necessary to reestablish where major
+ * heap block pins are - all we care is that they're still in there
+ * somewhere.
+ */
+ sgen_optimize_pin_queue ();
sgen_find_section_pin_queue_start_end (nursery_section);
objects_pinned = 0;
}
@@ -2945,7 +2926,7 @@ major_finish_collection (const char *reason, size_t old_next_pin_slot, gboolean
* pinned objects as we go, memzero() the empty fragments so they are ready for the
* next allocations.
*/
- if (!sgen_build_nursery_fragments (nursery_section, nursery_section->pin_queue_start, nursery_section->pin_queue_num_entries, NULL))
+ if (!sgen_build_nursery_fragments (nursery_section, NULL))
degraded_mode = 1;
/* prepare the pin queue for the next collection */
@@ -2997,8 +2978,8 @@ major_finish_collection (const char *reason, size_t old_next_pin_slot, gboolean
static gboolean
major_do_collection (const char *reason)
{
- TV_DECLARE (all_atv);
- TV_DECLARE (all_btv);
+ TV_DECLARE (time_start);
+ TV_DECLARE (time_end);
size_t old_next_pin_slot;
if (disable_major_collections)
@@ -3010,13 +2991,13 @@ major_do_collection (const char *reason)
}
/* world must be stopped already */
- TV_GETTIME (all_atv);
+ TV_GETTIME (time_start);
major_start_collection (FALSE, &old_next_pin_slot);
major_finish_collection (reason, old_next_pin_slot, FALSE);
- TV_GETTIME (all_btv);
- gc_stats.major_gc_time += TV_ELAPSED (all_atv, all_btv);
+ TV_GETTIME (time_end);
+ gc_stats.major_gc_time += TV_ELAPSED (time_start, time_end);
/* FIXME: also report this to the user, preferably in gc-end. */
if (major_collector.get_and_reset_num_major_objects_marked)
@@ -3028,11 +3009,16 @@ major_do_collection (const char *reason)
static void
major_start_concurrent_collection (const char *reason)
{
+ TV_DECLARE (time_start);
+ TV_DECLARE (time_end);
long long num_objects_marked;
if (disable_major_collections)
return;
+ TV_GETTIME (time_start);
+ SGEN_TV_GETTIME (time_major_conc_collection_start);
+
num_objects_marked = major_collector.get_and_reset_num_major_objects_marked ();
g_assert (num_objects_marked == 0);
@@ -3048,15 +3034,22 @@ major_start_concurrent_collection (const char *reason)
num_objects_marked = major_collector.get_and_reset_num_major_objects_marked ();
MONO_GC_CONCURRENT_START_END (GENERATION_OLD, num_objects_marked);
+ TV_GETTIME (time_end);
+ gc_stats.major_gc_time += TV_ELAPSED (time_start, time_end);
+
current_collection_generation = -1;
}
static gboolean
major_update_or_finish_concurrent_collection (gboolean force_finish)
{
+ TV_DECLARE (total_start);
+ TV_DECLARE (total_end);
SgenGrayQueue unpin_queue;
memset (&unpin_queue, 0, sizeof (unpin_queue));
+ TV_GETTIME (total_start);
+
MONO_GC_CONCURRENT_UPDATE_FINISH_BEGIN (GENERATION_OLD, major_collector.get_and_reset_num_major_objects_marked ());
binary_protocol_concurrent_update_finish ();
@@ -3067,6 +3060,10 @@ major_update_or_finish_concurrent_collection (gboolean force_finish)
sgen_los_update_cardtable_mod_union ();
MONO_GC_CONCURRENT_UPDATE_END (GENERATION_OLD, major_collector.get_and_reset_num_major_objects_marked ());
+
+ TV_GETTIME (total_end);
+ gc_stats.major_gc_time += TV_ELAPSED (total_start, total_end);
+
return FALSE;
}
@@ -3078,6 +3075,9 @@ major_update_or_finish_concurrent_collection (gboolean force_finish)
*/
wait_for_workers_to_finish ();
+ SGEN_TV_GETTIME (time_major_conc_collection_end);
+ gc_stats.major_gc_time_concurrent += SGEN_TV_ELAPSED (time_major_conc_collection_start, time_major_conc_collection_end);
+
major_collector.update_cardtable_mod_union ();
sgen_los_update_cardtable_mod_union ();
@@ -3097,6 +3097,9 @@ major_update_or_finish_concurrent_collection (gboolean force_finish)
MONO_GC_CONCURRENT_FINISH_END (GENERATION_OLD, major_collector.get_and_reset_num_major_objects_marked ());
+ TV_GETTIME (total_end);
+ gc_stats.major_gc_time += TV_ELAPSED (total_start, total_end) - TV_ELAPSED (last_minor_collection_start_tv, last_minor_collection_end_tv);
+
current_collection_generation = -1;
return TRUE;
@@ -3153,6 +3156,8 @@ void
sgen_perform_collection (size_t requested_size, int generation_to_collect, const char *reason, gboolean wait_to_finish)
{
TV_DECLARE (gc_end);
+ TV_DECLARE (gc_total_start);
+ TV_DECLARE (gc_total_end);
GGTimingInfo infos [2];
int overflow_generation_to_collect = -1;
int oldest_generation_collected = generation_to_collect;
@@ -3175,6 +3180,8 @@ sgen_perform_collection (size_t requested_size, int generation_to_collect, const
sgen_stop_world (generation_to_collect);
+ TV_GETTIME (gc_total_start);
+
if (concurrent_collection_in_progress) {
if (major_update_or_finish_concurrent_collection (wait_to_finish && generation_to_collect == GENERATION_OLD)) {
oldest_generation_collected = GENERATION_OLD;
@@ -3254,6 +3261,9 @@ sgen_perform_collection (size_t requested_size, int generation_to_collect, const
done:
g_assert (sgen_gray_object_queue_is_empty (&gray_queue));
+ TV_GETTIME (gc_total_end);
+ time_max = MAX (time_max, TV_ELAPSED (gc_total_start, gc_total_end));
+
sgen_restart_world (oldest_generation_collected, infos);
mono_profiler_gc_event (MONO_GC_EVENT_END, generation_to_collect);
@@ -3835,11 +3845,11 @@ sgen_thread_register (SgenThreadInfo* info, void *addr)
binary_protocol_thread_register ((gpointer)mono_thread_info_get_tid (info));
/* On win32, stack_start_limit should be 0, since the stack can grow dynamically */
-#ifndef HOST_WIN32
mono_thread_info_get_stack_bounds (&staddr, &stsize);
-#endif
if (staddr) {
+#ifndef HOST_WIN32
info->stack_start_limit = staddr;
+#endif
info->stack_end = staddr + stsize;
} else {
gsize stack_bottom = (gsize)addr;
@@ -4272,6 +4282,8 @@ typedef struct {
static void
collect_references (HeapWalkInfo *hwi, char *start, size_t size)
{
+ mword desc = sgen_obj_get_descriptor (start);
+
#include "sgen-scan-object.h"
}
@@ -4366,6 +4378,25 @@ mono_gc_get_los_limit (void)
return MAX_SMALL_OBJ_SIZE;
}
+void
+mono_gc_set_string_length (MonoString *str, gint32 new_length)
+{
+ mono_unichar2 *new_end = str->chars + new_length;
+
+ /* zero the discarded string. This null-delimits the string and allows
+ * the space to be reclaimed by SGen. */
+
+ if (nursery_canaries_enabled () && sgen_ptr_in_nursery (str)) {
+ CHECK_CANARY_FOR_OBJECT (str);
+ memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2) + CANARY_SIZE);
+ memcpy (new_end + 1 , CANARY_STRING, CANARY_SIZE);
+ } else {
+ memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2));
+ }
+
+ str->length = new_length;
+}
+
gboolean
mono_gc_user_markers_supported (void)
{
@@ -4547,7 +4578,6 @@ mono_gc_base_init (void)
char *minor_collector_opt = NULL;
size_t max_heap = 0;
size_t soft_limit = 0;
- int num_workers;
int result;
int dummy;
gboolean debug_print_allowance = FALSE;
@@ -4617,6 +4647,8 @@ mono_gc_base_init (void)
sgen_init_fin_weak_hash ();
sgen_init_stw ();
sgen_init_hash_table ();
+ sgen_init_descriptors ();
+ sgen_init_gray_queues ();
sgen_register_fixed_internal_mem_type (INTERNAL_MEM_SECTION, SGEN_SIZEOF_GC_MEM_SECTION);
sgen_register_fixed_internal_mem_type (INTERNAL_MEM_FINALIZE_READY_ENTRY, sizeof (FinalizeReadyEntry));
@@ -4667,12 +4699,6 @@ mono_gc_base_init (void)
if (!major_collector_opt || !strcmp (major_collector_opt, "marksweep")) {
use_marksweep_major:
sgen_marksweep_init (&major_collector);
- } else if (!major_collector_opt || !strcmp (major_collector_opt, "marksweep-fixed")) {
- sgen_marksweep_fixed_init (&major_collector);
- } else if (!major_collector_opt || !strcmp (major_collector_opt, "marksweep-par")) {
- sgen_marksweep_par_init (&major_collector);
- } else if (!major_collector_opt || !strcmp (major_collector_opt, "marksweep-fixed-par")) {
- sgen_marksweep_fixed_par_init (&major_collector);
} else if (!major_collector_opt || !strcmp (major_collector_opt, "marksweep-conc")) {
sgen_marksweep_conc_init (&major_collector);
} else {
@@ -4680,16 +4706,6 @@ mono_gc_base_init (void)
goto use_marksweep_major;
}
- if (have_split_nursery && major_collector.is_parallel) {
- sgen_env_var_error (MONO_GC_PARAMS_NAME, "Disabling split minor collector.", "`minor=split` is not supported with the parallel collector yet.");
- have_split_nursery = FALSE;
- }
-
- num_workers = mono_cpu_count ();
- g_assert (num_workers > 0);
- if (num_workers > 16)
- num_workers = 16;
-
///* Keep this the default for now */
/* Precise marking is broken on all supported targets. Disable until fixed. */
conservative_stack_mark = TRUE;
@@ -4731,26 +4747,6 @@ mono_gc_base_init (void)
}
continue;
}
- if (g_str_has_prefix (opt, "workers=")) {
- long val;
- char *endptr;
- if (!major_collector.is_parallel) {
- sgen_env_var_error (MONO_GC_PARAMS_NAME, "Ignoring.", "The `workers` option can only be used for parallel collectors.");
- continue;
- }
- opt = strchr (opt, '=') + 1;
- val = strtol (opt, &endptr, 10);
- if (!*opt || *endptr) {
- sgen_env_var_error (MONO_GC_PARAMS_NAME, "Ignoring.", "Cannot parse the `workers` option value.");
- continue;
- }
- if (val <= 0 || val > 16) {
- sgen_env_var_error (MONO_GC_PARAMS_NAME, "Using default value.", "The number of `workers` must be in the range 1 to 16.");
- continue;
- }
- num_workers = (int)val;
- continue;
- }
if (g_str_has_prefix (opt, "stack-mark=")) {
opt = strchr (opt, '=') + 1;
if (!strcmp (opt, "precise")) {
@@ -4841,10 +4837,6 @@ mono_gc_base_init (void)
}
if (!strcmp (opt, "cementing")) {
- if (major_collector.is_parallel) {
- sgen_env_var_error (MONO_GC_PARAMS_NAME, "Ignoring.", "`cementing` is not supported for the parallel major collector.");
- continue;
- }
cement_enabled = TRUE;
continue;
}
@@ -4868,7 +4860,7 @@ mono_gc_base_init (void)
fprintf (stderr, " max-heap-size=N (where N is an integer, possibly with a k, m or a g suffix)\n");
fprintf (stderr, " soft-heap-limit=n (where N is an integer, possibly with a k, m or a g suffix)\n");
fprintf (stderr, " nursery-size=N (where N is an integer, possibly with a k, m or a g suffix)\n");
- fprintf (stderr, " major=COLLECTOR (where COLLECTOR is `marksweep', `marksweep-conc', `marksweep-par', 'marksweep-fixed' or 'marksweep-fixed-par')\n");
+ fprintf (stderr, " major=COLLECTOR (where COLLECTOR is `marksweep', `marksweep-conc', `marksweep-par')\n");
fprintf (stderr, " minor=COLLECTOR (where COLLECTOR is `simple' or `split')\n");
fprintf (stderr, " wbarrier=WBARRIER (where WBARRIER is `remset' or `cardtable')\n");
fprintf (stderr, " stack-mark=MARK-METHOD (where MARK-METHOD is 'precise' or 'conservative')\n");
@@ -4889,12 +4881,8 @@ mono_gc_base_init (void)
g_strfreev (opts);
}
- if (major_collector.is_parallel) {
- cement_enabled = FALSE;
- sgen_workers_init (num_workers);
- } else if (major_collector.is_concurrent) {
+ if (major_collector.is_concurrent)
sgen_workers_init (1);
- }
if (major_collector_opt)
g_free (major_collector_opt);
@@ -4920,11 +4908,7 @@ mono_gc_base_init (void)
if (opt [0] == ':')
opt++;
if (opt [0]) {
-#ifdef HOST_WIN32
- char *rf = g_strdup_printf ("%s.%d", opt, GetCurrentProcessId ());
-#else
- char *rf = g_strdup_printf ("%s.%d", opt, getpid ());
-#endif
+ char *rf = g_strdup_printf ("%s.%d", opt, mono_process_current_pid ());
gc_debug_file = fopen (rf, "wb");
if (!gc_debug_file)
gc_debug_file = stderr;
@@ -5011,6 +4995,10 @@ mono_gc_base_init (void)
*colon = '\0';
}
binary_protocol_init (filename, (long long)limit);
+ } else if (!strcmp (opt, "nursery-canaries")) {
+ do_verify_nursery = TRUE;
+ sgen_set_use_managed_allocator (FALSE);
+ enable_nursery_canaries = TRUE;
} else if (!sgen_bridge_handle_gc_debug (opt)) {
sgen_env_var_error (MONO_GC_DEBUG_NAME, "Ignoring.", "Unknown option `%s`.", opt);
@@ -5040,6 +5028,7 @@ mono_gc_base_init (void)
fprintf (stderr, " print-pinning\n");
fprintf (stderr, " heap-dump=\n");
fprintf (stderr, " binary-protocol=[:]\n");
+ fprintf (stderr, " nursery-canaries\n");
sgen_bridge_print_gc_debug_usage ();
fprintf (stderr, "\n");
@@ -5049,18 +5038,6 @@ mono_gc_base_init (void)
g_strfreev (opts);
}
- if (major_collector.is_parallel) {
- if (heap_dump_file) {
- sgen_env_var_error (MONO_GC_DEBUG_NAME, "Disabling.", "Cannot do `heap-dump` with the parallel collector.");
- fclose (heap_dump_file);
- heap_dump_file = NULL;
- }
- if (do_pin_stats) {
- sgen_env_var_error (MONO_GC_DEBUG_NAME, "Disabling.", "`print-pinning` is not supported with the parallel collector.");
- do_pin_stats = FALSE;
- }
- }
-
if (major_collector.post_param_init)
major_collector.post_param_init (&major_collector);
@@ -5432,4 +5409,8 @@ mono_gc_register_finalizer_callbacks (MonoGCFinalizerCallbacks *callbacks)
fin_callbacks = *callbacks;
}
+
+
+
+
#endif /* HAVE_SGEN_GC */
diff --git a/mono/metadata/sgen-gc.h b/mono/metadata/sgen-gc.h
index 41a7151ba29..0fa76130411 100644
--- a/mono/metadata/sgen-gc.h
+++ b/mono/metadata/sgen-gc.h
@@ -144,8 +144,8 @@ struct _GCMemSection {
*/
char **scan_starts;
/* in major collections indexes in the pin_queue for objects that pin this section */
- void **pin_queue_start;
- size_t pin_queue_num_entries;
+ size_t pin_queue_first_entry;
+ size_t pin_queue_last_entry;
size_t num_scan_start;
};
@@ -190,14 +190,10 @@ extern LOCK_DECLARE (sgen_interruption_mutex);
#endif
#ifdef HEAVY_STATISTICS
-#define HEAVY_STAT(x) x
-
extern long long stat_objects_alloced_degraded;
extern long long stat_bytes_alloced_degraded;
extern long long stat_copy_object_called_major;
extern long long stat_objects_copied_major;
-#else
-#define HEAVY_STAT(x)
#endif
#define SGEN_ASSERT(level, a, ...) do { \
@@ -323,77 +319,42 @@ typedef struct {
* The values are already shifted.
* The forwarding address is stored in the sync block.
*/
-#define SGEN_FORWARDED_BIT 1
-#define SGEN_PINNED_BIT 2
+
#define SGEN_VTABLE_BITS_MASK 0x3
+#include "sgen-tagged-pointer.h"
+
+#define SGEN_POINTER_IS_TAGGED_FORWARDED(p) SGEN_POINTER_IS_TAGGED_1((p))
+#define SGEN_POINTER_TAG_FORWARDED(p) SGEN_POINTER_TAG_1((p))
+
+#define SGEN_POINTER_IS_TAGGED_PINNED(p) SGEN_POINTER_IS_TAGGED_2((p))
+#define SGEN_POINTER_TAG_PINNED(p) SGEN_POINTER_TAG_2((p))
+
+#define SGEN_POINTER_UNTAG_VTABLE(p) SGEN_POINTER_UNTAG_12((p))
+
/* returns NULL if not forwarded, or the forwarded address */
-#define SGEN_OBJECT_IS_FORWARDED(obj) (((mword*)(obj))[0] & SGEN_FORWARDED_BIT ? (void*)(((mword*)(obj))[0] & ~SGEN_VTABLE_BITS_MASK) : NULL)
-#define SGEN_OBJECT_IS_PINNED(obj) (((mword*)(obj))[0] & SGEN_PINNED_BIT)
+#define SGEN_VTABLE_IS_FORWARDED(vtable) (SGEN_POINTER_IS_TAGGED_FORWARDED ((vtable)) ? SGEN_POINTER_UNTAG_VTABLE ((vtable)) : NULL)
+#define SGEN_OBJECT_IS_FORWARDED(obj) (SGEN_VTABLE_IS_FORWARDED (((mword*)(obj))[0]))
+
+#define SGEN_VTABLE_IS_PINNED(vtable) SGEN_POINTER_IS_TAGGED_PINNED ((vtable))
+#define SGEN_OBJECT_IS_PINNED(obj) (SGEN_VTABLE_IS_PINNED (((mword*)(obj))[0]))
/* set the forwarded address fw_addr for object obj */
#define SGEN_FORWARD_OBJECT(obj,fw_addr) do { \
- ((mword*)(obj))[0] = (mword)(fw_addr) | SGEN_FORWARDED_BIT; \
+ *(void**)(obj) = SGEN_POINTER_TAG_FORWARDED ((fw_addr)); \
} while (0)
#define SGEN_PIN_OBJECT(obj) do { \
- ((mword*)(obj))[0] |= SGEN_PINNED_BIT; \
+ *(void**)(obj) = SGEN_POINTER_TAG_PINNED (*(void**)(obj)); \
} while (0)
#define SGEN_UNPIN_OBJECT(obj) do { \
- ((mword*)(obj))[0] &= ~SGEN_PINNED_BIT; \
+ *(void**)(obj) = SGEN_POINTER_UNTAG_2 (*(void**)(obj)); \
} while (0)
/*
* Since we set bits in the vtable, use the macro to load it from the pointer to
* an object that is potentially pinned.
*/
-#define SGEN_LOAD_VTABLE(addr) ((*(mword*)(addr)) & ~SGEN_VTABLE_BITS_MASK)
-
-static inline MONO_ALWAYS_INLINE void
-GRAY_OBJECT_ENQUEUE (SgenGrayQueue *queue, char* obj)
-{
-#if defined(SGEN_GRAY_OBJECT_ENQUEUE) || SGEN_MAX_DEBUG_LEVEL >= 9
- sgen_gray_object_enqueue (queue, obj);
-#else
- if (G_UNLIKELY (!queue->first || queue->cursor == GRAY_LAST_CURSOR_POSITION (queue->first))) {
- sgen_gray_object_enqueue (queue, obj);
- } else {
- HEAVY_STAT (gc_stats.gray_queue_enqueue_fast_path ++);
-
- *++queue->cursor = obj;
-#ifdef SGEN_HEAVY_BINARY_PROTOCOL
- binary_protocol_gray_enqueue (queue, queue->cursor, obj);
-#endif
- }
-
- PREFETCH (obj);
-#endif
-}
-
-static inline MONO_ALWAYS_INLINE void
-GRAY_OBJECT_DEQUEUE (SgenGrayQueue *queue, char** obj)
-{
-#if defined(SGEN_GRAY_OBJECT_ENQUEUE) || SGEN_MAX_DEBUG_LEVEL >= 9
- *obj = sgen_gray_object_enqueue (queue);
-#else
- if (!queue->first) {
- HEAVY_STAT (gc_stats.gray_queue_dequeue_fast_path ++);
-
- *obj = NULL;
-#ifdef SGEN_HEAVY_BINARY_PROTOCOL
- binary_protocol_gray_dequeue (queue, queue->cursor, *obj);
-#endif
- } else if (G_UNLIKELY (queue->cursor == GRAY_FIRST_CURSOR_POSITION (queue->first))) {
- *obj = sgen_gray_object_dequeue (queue);
- } else {
- HEAVY_STAT (gc_stats.gray_queue_dequeue_fast_path ++);
-
- *obj = *queue->cursor--;
-#ifdef SGEN_HEAVY_BINARY_PROTOCOL
- binary_protocol_gray_dequeue (queue, queue->cursor + 1, *obj);
-#endif
- }
-#endif
-}
+#define SGEN_LOAD_VTABLE(addr) SGEN_POINTER_UNTAG_12 (*(void**)(addr))
/*
List of what each bit on of the vtable gc bits means.
@@ -500,7 +461,7 @@ struct _ObjectList {
};
typedef void (*CopyOrMarkObjectFunc) (void**, SgenGrayQueue*);
-typedef void (*ScanObjectFunc) (char*, SgenGrayQueue*);
+typedef void (*ScanObjectFunc) (char *obj, mword desc, SgenGrayQueue*);
typedef void (*ScanVTypeFunc) (char*, mword desc, SgenGrayQueue* BINARY_PROTOCOL_ARG (size_t size));
typedef struct
@@ -525,10 +486,6 @@ void sgen_free_internal (void *addr, int type) MONO_INTERNAL;
void* sgen_alloc_internal_dynamic (size_t size, int type, gboolean assert_on_failure) MONO_INTERNAL;
void sgen_free_internal_dynamic (void *addr, size_t size, int type) MONO_INTERNAL;
-void** sgen_find_optimized_pin_queue_area (void *start, void *end, size_t *num) MONO_INTERNAL;
-void sgen_find_section_pin_queue_start_end (GCMemSection *section) MONO_INTERNAL;
-void sgen_pin_objects_in_section (GCMemSection *section, ScanCopyContext ctx) MONO_INTERNAL;
-
void sgen_pin_stats_register_object (char *obj, size_t size);
void sgen_pin_stats_register_global_remset (char *obj);
void sgen_pin_stats_print_class_stats (void);
@@ -537,7 +494,6 @@ void sgen_sort_addresses (void **array, size_t size) MONO_INTERNAL;
void sgen_add_to_global_remset (gpointer ptr, gpointer obj) MONO_INTERNAL;
int sgen_get_current_collection_generation (void) MONO_INTERNAL;
-gboolean sgen_collection_is_parallel (void) MONO_INTERNAL;
gboolean sgen_collection_is_concurrent (void) MONO_INTERNAL;
gboolean sgen_concurrent_collection_in_progress (void) MONO_INTERNAL;
@@ -600,7 +556,7 @@ static inline gboolean
sgen_nursery_is_to_space (char *object)
{
size_t idx = (object - sgen_nursery_start) >> SGEN_TO_SPACE_GRANULE_BITS;
- size_t byte = idx / 8;
+ size_t byte = idx >> 3;
size_t bit = idx & 0x7;
SGEN_ASSERT (4, sgen_ptr_in_nursery (object), "object %p is not in nursery [%p - %p]", object, sgen_get_nursery_start (), sgen_get_nursery_end ());
@@ -634,10 +590,8 @@ typedef struct {
gboolean is_split;
char* (*alloc_for_promotion) (MonoVTable *vtable, char *obj, size_t objsize, gboolean has_references);
- char* (*par_alloc_for_promotion) (MonoVTable *vtable, char *obj, size_t objsize, gboolean has_references);
SgenObjectOperations serial_ops;
- SgenObjectOperations parallel_ops;
void (*prepare_to_space) (char *to_space_bitmap, size_t space_bitmap_size);
void (*clear_fragments) (void);
@@ -671,7 +625,6 @@ typedef enum {
typedef struct _SgenMajorCollector SgenMajorCollector;
struct _SgenMajorCollector {
size_t section_size;
- gboolean is_parallel;
gboolean is_concurrent;
gboolean supports_cardtable;
gboolean sweeps_lazily;
@@ -697,7 +650,6 @@ struct _SgenMajorCollector {
SgenObjectOperations major_concurrent_ops;
void* (*alloc_object) (MonoVTable *vtable, size_t size, gboolean has_references);
- void* (*par_alloc_object) (MonoVTable *vtable, size_t size, gboolean has_references);
void (*free_pinned_object) (char *obj, size_t size);
void (*iterate_objects) (IterateObjectsFlags flags, IterateObjectCallbackFunc callback, void *data);
void (*free_non_pinned_object) (char *obj, size_t size);
@@ -775,7 +727,7 @@ slow_object_get_size (MonoVTable *vtable, MonoObject* o)
* mono_array_length_fast not using the object's vtable.
*/
if (klass == mono_defaults.string_class) {
- return sizeof (MonoString) + 2 * mono_string_length_fast ((MonoString*) o) + 2;
+ return offsetof (MonoString, chars) + 2 * mono_string_length_fast ((MonoString*) o) + 2;
} else if (klass->rank) {
MonoArray *array = (MonoArray*)o;
size_t size = sizeof (MonoArray) + klass->sizes.element_size * mono_array_length_fast (array);
@@ -791,6 +743,27 @@ slow_object_get_size (MonoVTable *vtable, MonoObject* o)
}
}
+static inline mword
+sgen_vtable_get_descriptor (MonoVTable *vtable)
+{
+ return (mword)vtable->gc_descr;
+}
+
+static inline mword
+sgen_obj_get_descriptor (char *obj)
+{
+ MonoVTable *vtable = ((MonoObject*)obj)->vtable;
+ SGEN_ASSERT (0, !SGEN_POINTER_IS_TAGGED_1_OR_2 (vtable), "Object can't be tagged");
+ return sgen_vtable_get_descriptor (vtable);
+}
+
+static inline mword
+sgen_obj_get_descriptor_safe (char *obj)
+{
+ MonoVTable *vtable = (MonoVTable*)SGEN_LOAD_VTABLE (obj);
+ return sgen_vtable_get_descriptor (vtable);
+}
+
/*
* This function can be called on an object whose first word, the
* vtable field, is not intact. This is necessary for the parallel
@@ -805,7 +778,7 @@ sgen_par_object_get_size (MonoVTable *vtable, MonoObject* o)
if (type == DESC_TYPE_RUN_LENGTH || type == DESC_TYPE_SMALL_BITMAP) {
mword size = descr & 0xfff8;
if (size == 0) /* This is used to encode a string */
- return sizeof (MonoString) + 2 * mono_string_length_fast ((MonoString*) o) + 2;
+ return offsetof (MonoString, chars) + 2 * mono_string_length_fast ((MonoString*) o) + 2;
return size;
} else if (type == DESC_TYPE_VECTOR) {
int element_size = ((descr) >> VECTOR_ELSIZE_SHIFT) & MAX_ELEMENT_SIZE;
@@ -834,6 +807,22 @@ sgen_safe_object_get_size (MonoObject *obj)
return sgen_par_object_get_size ((MonoVTable*)SGEN_LOAD_VTABLE (obj), obj);
}
+/*
+ * This variant guarantees to return the exact size of the object
+ * before alignment. Needed for canary support.
+ */
+static inline guint
+sgen_safe_object_get_size_unaligned (MonoObject *obj)
+{
+ char *forwarded;
+
+ if ((forwarded = SGEN_OBJECT_IS_FORWARDED (obj))) {
+ obj = (MonoObject*)forwarded;
+ }
+
+ return slow_object_get_size ((MonoVTable*)SGEN_LOAD_VTABLE (obj), obj);
+}
+
const char* sgen_safe_name (void* obj) MONO_INTERNAL;
gboolean sgen_object_is_live (void *obj) MONO_INTERNAL;
@@ -985,7 +974,7 @@ gboolean sgen_los_object_is_pinned (char *obj) MONO_INTERNAL;
void sgen_clear_nursery_fragments (void) MONO_INTERNAL;
void sgen_nursery_allocator_prepare_for_pinning (void) MONO_INTERNAL;
void sgen_nursery_allocator_set_nursery_bounds (char *nursery_start, char *nursery_end) MONO_INTERNAL;
-mword sgen_build_nursery_fragments (GCMemSection *nursery_section, void **start, size_t num_entries, SgenGrayQueue *unpin_queue) MONO_INTERNAL;
+mword sgen_build_nursery_fragments (GCMemSection *nursery_section, SgenGrayQueue *unpin_queue) MONO_INTERNAL;
void sgen_init_nursery_allocator (void) MONO_INTERNAL;
void sgen_nursery_allocator_init_heavy_stats (void) MONO_INTERNAL;
void sgen_alloc_init_heavy_stats (void) MONO_INTERNAL;
@@ -1000,7 +989,6 @@ void sgen_nursery_alloc_prepare_for_minor (void) MONO_INTERNAL;
void sgen_nursery_alloc_prepare_for_major (void) MONO_INTERNAL;
char* sgen_alloc_for_promotion (char *obj, size_t objsize, gboolean has_references) MONO_INTERNAL;
-char* sgen_par_alloc_for_promotion (char *obj, size_t objsize, gboolean has_references) MONO_INTERNAL;
/* TLS Data */
@@ -1168,6 +1156,37 @@ void sgen_env_var_error (const char *env_var, const char *fallback, const char *
void sgen_qsort (void *base, size_t nel, size_t width, int (*compar) (const void*, const void*)) MONO_INTERNAL;
gint64 sgen_timestamp (void) MONO_INTERNAL;
+/*
+ * Canary (guard word) support
+ * Notes:
+ * - CANARY_SIZE must be multiple of word size in bytes
+ * - Canary space is not included on checks against SGEN_MAX_SMALL_OBJ_SIZE
+ */
+
+gboolean nursery_canaries_enabled (void) MONO_INTERNAL;
+
+#define CANARY_SIZE 8
+#define CANARY_STRING "koupepia"
+
+#define CANARIFY_SIZE(size) if (nursery_canaries_enabled ()) { \
+ size = size + CANARY_SIZE; \
+ }
+
+#define CANARIFY_ALLOC(addr,size) if (nursery_canaries_enabled ()) { \
+ memcpy ((char*) (addr) + (size), CANARY_STRING, CANARY_SIZE); \
+ }
+
+#define CANARY_VALID(addr) (strncmp ((char*) (addr), CANARY_STRING, CANARY_SIZE) == 0)
+
+#define CHECK_CANARY_FOR_OBJECT(addr) if (nursery_canaries_enabled ()) { \
+ char* canary_ptr = (char*) (addr) + sgen_safe_object_get_size_unaligned ((MonoObject *) (addr)); \
+ if (!CANARY_VALID(canary_ptr)) { \
+ char canary_copy[CANARY_SIZE +1]; \
+ strncpy (canary_copy, canary_ptr, 8); \
+ canary_copy[CANARY_SIZE] = 0; \
+ g_error ("CORRUPT CANARY:\naddr->%p\ntype->%s\nexcepted->'%s'\nfound->'%s'\n", (char*) addr, ((MonoObject*)addr)->vtable->klass->name, CANARY_STRING, canary_copy); \
+ } }
+
#endif /* HAVE_SGEN_GC */
#endif /* __MONO_SGENGC_H__ */
diff --git a/mono/metadata/sgen-gray.c b/mono/metadata/sgen-gray.c
index 2393cbabb14..247608751fe 100644
--- a/mono/metadata/sgen-gray.c
+++ b/mono/metadata/sgen-gray.c
@@ -25,6 +25,15 @@
#include "utils/mono-counters.h"
#include "sgen-protocol.h"
+#ifdef HEAVY_STATISTICS
+unsigned long long stat_gray_queue_section_alloc;
+unsigned long long stat_gray_queue_section_free;
+unsigned long long stat_gray_queue_enqueue_fast_path;
+unsigned long long stat_gray_queue_dequeue_fast_path;
+unsigned long long stat_gray_queue_enqueue_slow_path;
+unsigned long long stat_gray_queue_dequeue_slow_path;
+#endif
+
#define GRAY_QUEUE_LENGTH_LIMIT 64
#ifdef SGEN_CHECK_GRAY_OBJECT_SECTIONS
@@ -46,7 +55,7 @@ sgen_gray_object_alloc_queue_section (SgenGrayQueue *queue)
{
GrayQueueSection *section;
- HEAVY_STAT (gc_stats.gray_queue_section_alloc ++);
+ HEAVY_STAT (stat_gray_queue_section_alloc ++);
if (queue->alloc_prepare_func)
queue->alloc_prepare_func (queue);
@@ -69,13 +78,13 @@ sgen_gray_object_alloc_queue_section (SgenGrayQueue *queue)
/* Link it with the others */
section->next = queue->first;
queue->first = section;
- queue->cursor = (char**)section->objects - 1;
+ queue->cursor = section->entries - 1;
}
void
sgen_gray_object_free_queue_section (GrayQueueSection *section)
{
- HEAVY_STAT (gc_stats.gray_queue_section_free ++);
+ HEAVY_STAT (stat_gray_queue_section_free ++);
STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_FLOATING, GRAY_QUEUE_SECTION_STATE_FREED);
sgen_free_internal (section, INTERNAL_MEM_GRAY_QUEUE);
@@ -88,9 +97,11 @@ sgen_gray_object_free_queue_section (GrayQueueSection *section)
*/
void
-sgen_gray_object_enqueue (SgenGrayQueue *queue, char *obj)
+sgen_gray_object_enqueue (SgenGrayQueue *queue, char *obj, mword desc)
{
- HEAVY_STAT (gc_stats.gray_queue_enqueue_slow_path ++);
+ GrayQueueEntry entry = { obj, desc };
+
+ HEAVY_STAT (stat_gray_queue_enqueue_slow_path ++);
SGEN_ASSERT (9, obj, "enqueueing a null object");
//sgen_check_objref (obj);
@@ -110,33 +121,35 @@ sgen_gray_object_enqueue (SgenGrayQueue *queue, char *obj)
}
STATE_ASSERT (queue->first, GRAY_QUEUE_SECTION_STATE_ENQUEUED);
SGEN_ASSERT (9, queue->cursor <= GRAY_LAST_CURSOR_POSITION (queue->first), "gray queue %p overflow, first %p, cursor %p", queue, queue->first, queue->cursor);
- *++queue->cursor = obj;
+ *++queue->cursor = entry;
#ifdef SGEN_HEAVY_BINARY_PROTOCOL
binary_protocol_gray_enqueue (queue, queue->cursor, obj);
#endif
}
-char*
+GrayQueueEntry
sgen_gray_object_dequeue (SgenGrayQueue *queue)
{
- char *obj;
+ GrayQueueEntry entry;
- HEAVY_STAT (gc_stats.gray_queue_dequeue_slow_path ++);
+ HEAVY_STAT (stat_gray_queue_dequeue_slow_path ++);
- if (sgen_gray_object_queue_is_empty (queue))
- return NULL;
+ if (sgen_gray_object_queue_is_empty (queue)) {
+ entry.obj = NULL;
+ return entry;
+ }
STATE_ASSERT (queue->first, GRAY_QUEUE_SECTION_STATE_ENQUEUED);
- SGEN_ASSERT (9, queue->cursor >= (char**)queue->first->objects, "gray queue %p underflow, first %p, cursor %d", queue, queue->first, queue->cursor);
+ SGEN_ASSERT (9, queue->cursor >= GRAY_FIRST_CURSOR_POSITION (queue->first), "gray queue %p underflow, first %p, cursor %d", queue, queue->first, queue->cursor);
- obj = *queue->cursor--;
+ entry = *queue->cursor--;
#ifdef SGEN_HEAVY_BINARY_PROTOCOL
binary_protocol_gray_dequeue (queue, queue->cursor + 1, obj);
#endif
- if (G_UNLIKELY (queue->cursor == (char**)queue->first->objects - 1)) {
+ if (G_UNLIKELY (queue->cursor < GRAY_FIRST_CURSOR_POSITION (queue->first))) {
GrayQueueSection *section = queue->first;
queue->first = section->next;
section->next = queue->free_list;
@@ -144,10 +157,10 @@ sgen_gray_object_dequeue (SgenGrayQueue *queue)
STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_ENQUEUED, GRAY_QUEUE_SECTION_STATE_FREE_LIST);
queue->free_list = section;
- queue->cursor = queue->first ? (char**)queue->first->objects + queue->first->size - 1 : NULL;
+ queue->cursor = queue->first ? queue->first->entries + queue->first->size - 1 : NULL;
}
- return obj;
+ return entry;
}
GrayQueueSection*
@@ -162,9 +175,9 @@ sgen_gray_object_dequeue_section (SgenGrayQueue *queue)
queue->first = section->next;
section->next = NULL;
- section->size = queue->cursor - (char**)section->objects + 1;
+ section->size = queue->cursor - section->entries + 1;
- queue->cursor = queue->first ? (char**)queue->first->objects + queue->first->size - 1 : NULL;
+ queue->cursor = queue->first ? queue->first->entries + queue->first->size - 1 : NULL;
STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_ENQUEUED, GRAY_QUEUE_SECTION_STATE_FLOATING);
@@ -177,36 +190,25 @@ sgen_gray_object_enqueue_section (SgenGrayQueue *queue, GrayQueueSection *sectio
STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_FLOATING, GRAY_QUEUE_SECTION_STATE_ENQUEUED);
if (queue->first)
- queue->first->size = queue->cursor - (char**)queue->first->objects + 1;
+ queue->first->size = queue->cursor - queue->first->entries + 1;
section->next = queue->first;
queue->first = section;
- queue->cursor = (char**)queue->first->objects + queue->first->size - 1;
+ queue->cursor = queue->first->entries + queue->first->size - 1;
#ifdef SGEN_CHECK_GRAY_OBJECT_ENQUEUE
if (queue->enqueue_check_func) {
int i;
for (i = 0; i < section->size; ++i)
- queue->enqueue_check_func (section->objects [i]);
+ queue->enqueue_check_func (section->entries [i].obj);
}
#endif
}
void
-sgen_gray_object_queue_init (SgenGrayQueue *queue, GrayQueueEnqueueCheckFunc enqueue_check_func)
+sgen_gray_object_queue_trim_free_list (SgenGrayQueue *queue)
{
GrayQueueSection *section, *next;
- int i;
-
- g_assert (sgen_gray_object_queue_is_empty (queue));
-
- queue->alloc_prepare_func = NULL;
- queue->alloc_prepare_data = NULL;
-#ifdef SGEN_CHECK_GRAY_OBJECT_ENQUEUE
- queue->enqueue_check_func = enqueue_check_func;
-#endif
-
- /* Free the extra sections allocated during the last collection */
- i = 0;
+ int i = 0;
for (section = queue->free_list; section && i < GRAY_QUEUE_LENGTH_LIMIT - 1; section = section->next) {
STATE_ASSERT (section, GRAY_QUEUE_SECTION_STATE_FREE_LIST);
i ++;
@@ -221,6 +223,21 @@ sgen_gray_object_queue_init (SgenGrayQueue *queue, GrayQueueEnqueueCheckFunc enq
}
}
+void
+sgen_gray_object_queue_init (SgenGrayQueue *queue, GrayQueueEnqueueCheckFunc enqueue_check_func)
+{
+ g_assert (sgen_gray_object_queue_is_empty (queue));
+
+ queue->alloc_prepare_func = NULL;
+ queue->alloc_prepare_data = NULL;
+#ifdef SGEN_CHECK_GRAY_OBJECT_ENQUEUE
+ queue->enqueue_check_func = enqueue_check_func;
+#endif
+
+ /* Free the extra sections allocated during the last collection */
+ sgen_gray_object_queue_trim_free_list (queue);
+}
+
static void
invalid_prepare_func (SgenGrayQueue *queue)
{
@@ -338,11 +355,23 @@ sgen_section_gray_queue_enqueue (SgenSectionGrayQueue *queue, GrayQueueSection *
if (queue->enqueue_check_func) {
int i;
for (i = 0; i < section->size; ++i)
- queue->enqueue_check_func (section->objects [i]);
+ queue->enqueue_check_func (section->entries [i].obj);
}
#endif
unlock_section_queue (queue);
}
+void
+sgen_init_gray_queues (void)
+{
+#ifdef HEAVY_STATISTICS
+ mono_counters_register ("Gray Queue alloc section", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_gray_queue_section_alloc);
+ mono_counters_register ("Gray Queue free section", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_gray_queue_section_free);
+ mono_counters_register ("Gray Queue enqueue fast path", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_gray_queue_enqueue_fast_path);
+ mono_counters_register ("Gray Queue dequeue fast path", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_gray_queue_dequeue_fast_path);
+ mono_counters_register ("Gray Queue enqueue slow path", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_gray_queue_enqueue_slow_path);
+ mono_counters_register ("Gray Queue dequeue slow path", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_gray_queue_dequeue_slow_path);
+#endif
+}
#endif
diff --git a/mono/metadata/sgen-gray.h b/mono/metadata/sgen-gray.h
index 2dfea35a146..c0ccd616bd7 100644
--- a/mono/metadata/sgen-gray.h
+++ b/mono/metadata/sgen-gray.h
@@ -48,7 +48,14 @@
* array and another 1 for the actual value in the array.
*/
-#define SGEN_GRAY_QUEUE_SECTION_SIZE (128 - 3)
+/* SGEN_GRAY_QUEUE_HEADER_SIZE is number of machine words */
+#ifdef SGEN_CHECK_GRAY_OBJECT_SECTIONS
+#define SGEN_GRAY_QUEUE_HEADER_SIZE 4
+#else
+#define SGEN_GRAY_QUEUE_HEADER_SIZE 2
+#endif
+
+#define SGEN_GRAY_QUEUE_SECTION_SIZE (128 - SGEN_GRAY_QUEUE_HEADER_SIZE)
#ifdef SGEN_CHECK_GRAY_OBJECT_SECTIONS
typedef enum {
@@ -59,6 +66,12 @@ typedef enum {
} GrayQueueSectionState;
#endif
+typedef struct _GrayQueueEntry GrayQueueEntry;
+struct _GrayQueueEntry {
+ char *obj;
+ mword desc;
+};
+
/*
* This is a stack now instead of a queue, so the most recently added items are removed
* first, improving cache locality, and keeping the stack size manageable.
@@ -75,7 +88,7 @@ struct _GrayQueueSection {
#endif
int size;
GrayQueueSection *next;
- char *objects [SGEN_GRAY_QUEUE_SECTION_SIZE];
+ GrayQueueEntry entries [SGEN_GRAY_QUEUE_SECTION_SIZE];
};
typedef struct _SgenGrayQueue SgenGrayQueue;
@@ -84,7 +97,7 @@ typedef void (*GrayQueueAllocPrepareFunc) (SgenGrayQueue*);
typedef void (*GrayQueueEnqueueCheckFunc) (char*);
struct _SgenGrayQueue {
- char **cursor;
+ GrayQueueEntry *cursor;
GrayQueueSection *first;
GrayQueueSection *free_list;
GrayQueueAllocPrepareFunc alloc_prepare_func;
@@ -105,13 +118,25 @@ struct _SgenSectionGrayQueue {
#endif
};
-#define GRAY_LAST_CURSOR_POSITION(s) ((char**)(s)->objects + SGEN_GRAY_QUEUE_SECTION_SIZE - 1)
-#define GRAY_FIRST_CURSOR_POSITION(s) ((char**)(s)->objects)
+#define GRAY_LAST_CURSOR_POSITION(s) ((s)->entries + SGEN_GRAY_QUEUE_SECTION_SIZE - 1)
+#define GRAY_FIRST_CURSOR_POSITION(s) ((s)->entries)
+
+#ifdef HEAVY_STATISTICS
+extern unsigned long long stat_gray_queue_section_alloc;
+extern unsigned long long stat_gray_queue_section_free;
+extern unsigned long long stat_gray_queue_enqueue_fast_path;
+extern unsigned long long stat_gray_queue_dequeue_fast_path;
+extern unsigned long long stat_gray_queue_enqueue_slow_path;
+extern unsigned long long stat_gray_queue_dequeue_slow_path;
+#endif
+
+void sgen_init_gray_queues (void) MONO_INTERNAL;
-void sgen_gray_object_enqueue (SgenGrayQueue *queue, char *obj) MONO_INTERNAL;
-char* sgen_gray_object_dequeue (SgenGrayQueue *queue) MONO_INTERNAL;
+void sgen_gray_object_enqueue (SgenGrayQueue *queue, char *obj, mword desc) MONO_INTERNAL;
+GrayQueueEntry sgen_gray_object_dequeue (SgenGrayQueue *queue) MONO_INTERNAL;
GrayQueueSection* sgen_gray_object_dequeue_section (SgenGrayQueue *queue) MONO_INTERNAL;
void sgen_gray_object_enqueue_section (SgenGrayQueue *queue, GrayQueueSection *section) MONO_INTERNAL;
+void sgen_gray_object_queue_trim_free_list (SgenGrayQueue *queue) MONO_INTERNAL;
void sgen_gray_object_queue_init (SgenGrayQueue *queue, GrayQueueEnqueueCheckFunc enqueue_check_func) MONO_INTERNAL;
void sgen_gray_object_queue_init_invalid (SgenGrayQueue *queue) MONO_INTERNAL;
void sgen_gray_object_queue_init_with_alloc_prepare (SgenGrayQueue *queue, GrayQueueEnqueueCheckFunc enqueue_check_func,
@@ -133,4 +158,58 @@ sgen_gray_object_queue_is_empty (SgenGrayQueue *queue)
return queue->first == NULL;
}
+static inline MONO_ALWAYS_INLINE void
+GRAY_OBJECT_ENQUEUE (SgenGrayQueue *queue, char* obj, mword desc)
+{
+#if SGEN_MAX_DEBUG_LEVEL >= 9
+ sgen_gray_object_enqueue (queue, obj, desc);
+#else
+ if (G_UNLIKELY (!queue->first || queue->cursor == GRAY_LAST_CURSOR_POSITION (queue->first))) {
+ sgen_gray_object_enqueue (queue, obj, desc);
+ } else {
+ GrayQueueEntry entry = { obj, desc };
+
+ HEAVY_STAT (stat_gray_queue_enqueue_fast_path ++);
+
+ *++queue->cursor = entry;
+#ifdef SGEN_HEAVY_BINARY_PROTOCOL
+ binary_protocol_gray_enqueue (queue, queue->cursor, obj);
+#endif
+ }
+#endif
+}
+
+static inline MONO_ALWAYS_INLINE void
+GRAY_OBJECT_DEQUEUE (SgenGrayQueue *queue, char** obj, mword *desc)
+{
+ GrayQueueEntry entry;
+#if SGEN_MAX_DEBUG_LEVEL >= 9
+ entry = sgen_gray_object_enqueue (queue);
+ *obj = entry.obj;
+ *desc = entry.desc;
+#else
+ if (!queue->first) {
+ HEAVY_STAT (stat_gray_queue_dequeue_fast_path ++);
+
+ *obj = NULL;
+#ifdef SGEN_HEAVY_BINARY_PROTOCOL
+ binary_protocol_gray_dequeue (queue, queue->cursor, *obj);
+#endif
+ } else if (G_UNLIKELY (queue->cursor == GRAY_FIRST_CURSOR_POSITION (queue->first))) {
+ entry = sgen_gray_object_dequeue (queue);
+ *obj = entry.obj;
+ *desc = entry.desc;
+ } else {
+ HEAVY_STAT (stat_gray_queue_dequeue_fast_path ++);
+
+ entry = *queue->cursor--;
+ *obj = entry.obj;
+ *desc = entry.desc;
+#ifdef SGEN_HEAVY_BINARY_PROTOCOL
+ binary_protocol_gray_dequeue (queue, queue->cursor + 1, *obj);
+#endif
+ }
+#endif
+}
+
#endif
diff --git a/mono/metadata/sgen-internal.c b/mono/metadata/sgen-internal.c
index 37ac5c6f329..333f8c3ee41 100644
--- a/mono/metadata/sgen-internal.c
+++ b/mono/metadata/sgen-internal.c
@@ -23,21 +23,53 @@
#include "utils/mono-counters.h"
#include "metadata/sgen-gc.h"
+#include "utils/mono-mmap.h"
#include "utils/lock-free-alloc.h"
#include "metadata/sgen-memory-governor.h"
/* keep each size a multiple of ALLOC_ALIGN */
+#if SIZEOF_VOID_P == 4
static const int allocator_sizes [] = {
8, 16, 24, 32, 40, 48, 64, 80,
- 96, 128, 160, 192, 224, 248, 320, 384,
- 448, 528, 584, 680, 816, 1088, 1360, 2040,
- 2336, 2728, 3272, 4088, 5456, 8184 };
+ 96, 128, 160, 192, 224, 248, 296, 320,
+ 384, 448, 504, 528, 584, 680, 816, 1088,
+ 1360, 2044, 2336, 2728, 3272, 4092, 5456, 8188 };
+#else
+static const int allocator_sizes [] = {
+ 8, 16, 24, 32, 40, 48, 64, 80,
+ 96, 128, 160, 192, 224, 248, 320, 328,
+ 384, 448, 528, 584, 680, 816, 1016, 1088,
+ 1360, 2040, 2336, 2728, 3272, 4088, 5456, 8184 };
+#endif
#define NUM_ALLOCATORS (sizeof (allocator_sizes) / sizeof (int))
+static int allocator_block_sizes [NUM_ALLOCATORS];
+
static MonoLockFreeAllocSizeClass size_classes [NUM_ALLOCATORS];
static MonoLockFreeAllocator allocators [NUM_ALLOCATORS];
+#ifdef HEAVY_STATISTICS
+static int allocator_sizes_stats [NUM_ALLOCATORS];
+#endif
+
+static size_t
+block_size (size_t slot_size)
+{
+ static int pagesize = -1;
+
+ int size;
+
+ if (pagesize == -1)
+ pagesize = mono_pagesize ();
+
+ for (size = pagesize; size < LOCK_FREE_ALLOC_SB_MAX_SIZE; size <<= 1) {
+ if (slot_size * 2 <= LOCK_FREE_ALLOC_SB_USABLE_SIZE (size))
+ return size;
+ }
+ return LOCK_FREE_ALLOC_SB_MAX_SIZE;
+}
+
/*
* Find the allocator index for memory chunks that can contain @size
* objects.
@@ -67,6 +99,7 @@ sgen_register_fixed_internal_mem_type (int type, size_t size)
int slot;
g_assert (type >= 0 && type < INTERNAL_MEM_MAX);
+ g_assert (size <= allocator_sizes [NUM_ALLOCATORS - 1]);
slot = index_for_size (size);
g_assert (slot >= 0);
@@ -135,6 +168,10 @@ sgen_alloc_internal_dynamic (size_t size, int type, gboolean assert_on_failure)
} else {
index = index_for_size (size);
+#ifdef HEAVY_STATISTICS
+ ++ allocator_sizes_stats [index];
+#endif
+
p = mono_lock_free_alloc (&allocators [index]);
if (!p)
sgen_assert_memory_alloc (NULL, size, description_for_type (type));
@@ -154,7 +191,7 @@ sgen_free_internal_dynamic (void *addr, size_t size, int type)
if (size > allocator_sizes [NUM_ALLOCATORS - 1])
sgen_free_os_memory (addr, size, SGEN_ALLOC_INTERNAL);
else
- mono_lock_free_free (addr);
+ mono_lock_free_free (addr, block_size (size));
MONO_GC_INTERNAL_DEALLOC ((mword)addr, size, type);
}
@@ -162,10 +199,18 @@ sgen_free_internal_dynamic (void *addr, size_t size, int type)
void*
sgen_alloc_internal (int type)
{
- int index = fixed_type_allocator_indexes [type];
- int size = allocator_sizes [index];
+ int index, size;
void *p;
+
+ index = fixed_type_allocator_indexes [type];
g_assert (index >= 0 && index < NUM_ALLOCATORS);
+
+#ifdef HEAVY_STATISTICS
+ ++ allocator_sizes_stats [index];
+#endif
+
+ size = allocator_sizes [index];
+
p = mono_lock_free_alloc (&allocators [index]);
memset (p, 0, size);
@@ -185,7 +230,7 @@ sgen_free_internal (void *addr, int type)
index = fixed_type_allocator_indexes [type];
g_assert (index >= 0 && index < NUM_ALLOCATORS);
- mono_lock_free_free (addr);
+ mono_lock_free_free (addr, allocator_block_sizes [index]);
if (MONO_GC_INTERNAL_DEALLOC_ENABLED ()) {
int size G_GNUC_UNUSED = allocator_sizes [index];
@@ -211,22 +256,37 @@ sgen_dump_internal_mem_usage (FILE *heap_dump_file)
void
sgen_report_internal_mem_usage (void)
{
- /* FIXME: implement */
- printf ("not implemented yet\n");
+ int i G_GNUC_UNUSED;
+#ifdef HEAVY_STATISTICS
+ printf ("size -> # allocations\n");
+ for (i = 0; i < NUM_ALLOCATORS; ++i)
+ printf ("%d -> %d\n", allocator_sizes [i], allocator_sizes_stats [i]);
+#endif
}
void
sgen_init_internal_allocator (void)
{
- int i;
+ int i, size;
for (i = 0; i < INTERNAL_MEM_MAX; ++i)
fixed_type_allocator_indexes [i] = -1;
for (i = 0; i < NUM_ALLOCATORS; ++i) {
- mono_lock_free_allocator_init_size_class (&size_classes [i], allocator_sizes [i]);
+ allocator_block_sizes [i] = block_size (allocator_sizes [i]);
+ mono_lock_free_allocator_init_size_class (&size_classes [i], allocator_sizes [i], allocator_block_sizes [i]);
mono_lock_free_allocator_init_allocator (&allocators [i], &size_classes [i]);
}
+
+ for (size = mono_pagesize (); size <= LOCK_FREE_ALLOC_SB_MAX_SIZE; size <<= 1) {
+ int max_size = LOCK_FREE_ALLOC_SB_USABLE_SIZE (size) / 2;
+ /*
+ * we assert that allocator_sizes contains the biggest possible object size
+ * per block (4K => 4080 / 2 = 2040, 8k => 8176 / 2 = 4088, 16k => 16368 / 2 = 8184 on 64bits),
+ * so that we do not get different block sizes for sizes that should go to the same one
+ */
+ g_assert (allocator_sizes [index_for_size (max_size)] == max_size);
+ }
}
#endif
diff --git a/mono/metadata/sgen-los.c b/mono/metadata/sgen-los.c
index 1e38006cac7..8e823b05537 100644
--- a/mono/metadata/sgen-los.c
+++ b/mono/metadata/sgen-los.c
@@ -336,13 +336,13 @@ sgen_los_alloc_large_inner (MonoVTable *vtable, size_t size)
g_assert ((size & 1) == 0);
/*
- * size + sizeof (LOSObject) <= SIZE_MAX - (mono_pagesize () - 1)
+ * size + sizeof (LOSObject) <= SSIZE_MAX - (mono_pagesize () - 1)
*
* therefore:
*
- * size <= SIZE_MAX - (mono_pagesize () - 1) - sizeof (LOSObject)
+ * size <= SSIZE_MAX - (mono_pagesize () - 1) - sizeof (LOSObject)
*/
- if (size > SIZE_MAX - (mono_pagesize () - 1) - sizeof (LOSObject))
+ if (size > SSIZE_MAX - (mono_pagesize () - 1) - sizeof (LOSObject))
return NULL;
#ifdef LOS_DUMMY
diff --git a/mono/metadata/sgen-major-scan-object.h b/mono/metadata/sgen-major-scan-object.h
index a4674a2139d..14b11317096 100644
--- a/mono/metadata/sgen-major-scan-object.h
+++ b/mono/metadata/sgen-major-scan-object.h
@@ -37,12 +37,23 @@ extern long long stat_scan_object_called_major;
#define CONCURRENT_NAME(x) x
#endif
+/*
+ * FIXME: We use the same scanning function in the concurrent collector whether we scan
+ * during the starting/finishing collection pause (with the world stopped) or from the
+ * concurrent worker thread.
+ *
+ * As long as the world is stopped, we should just follow pointers into the nursery and
+ * evict if possible. In that case we also don't need the ALWAYS_ADD_TO_GLOBAL_REMSET case,
+ * which only seems to make sense for when the world is stopped, in which case we only need
+ * it because we don't follow into the nursery.
+ */
+
#undef HANDLE_PTR
#define HANDLE_PTR(ptr,obj) do { \
void *__old = *(ptr); \
- void *__copy; \
SGEN_OBJECT_LAYOUT_STATISTICS_MARK_BITMAP ((obj), (ptr)); \
if (__old && FOLLOW_OBJECT (__old)) { \
+ void *__copy; \
PREFETCH_DYNAMIC_HEAP (__old); \
CONCURRENT_NAME (major_copy_or_mark_object) ((ptr), __old, queue); \
__copy = *(ptr); \
@@ -56,10 +67,14 @@ extern long long stat_scan_object_called_major;
} while (0)
static void
-CONCURRENT_NAME (major_scan_object) (char *start, SgenGrayQueue *queue)
+CONCURRENT_NAME (major_scan_object) (char *start, mword desc, SgenGrayQueue *queue)
{
SGEN_OBJECT_LAYOUT_STATISTICS_DECLARE_BITMAP;
+#ifdef HEAVY_STATISTICS
+ sgen_descriptor_count_scanned_object (desc);
+#endif
+
#define SCAN_OBJECT_PROTOCOL
#include "sgen-scan-object.h"
diff --git a/mono/metadata/sgen-marksweep-fixed-par.c b/mono/metadata/sgen-marksweep-fixed-par.c
deleted file mode 100644
index 7c03e5b1728..00000000000
--- a/mono/metadata/sgen-marksweep-fixed-par.c
+++ /dev/null
@@ -1,25 +0,0 @@
-#include "config.h"
-
-#ifdef HAVE_SGEN_GC
-
-#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_FIXED_PAR
-
-#define SGEN_PARALLEL_MARK
-#define FIXED_HEAP
-
-#include "sgen-marksweep.c"
-
-#else
-
-#include "metadata/sgen-gc.h"
-
-void
-sgen_marksweep_fixed_par_init (SgenMajorCollector *collector)
-{
- fprintf (stderr, "Error: Mono was configured using --enable-minimal=sgen_marksweep_fixed_par.\n");
- exit (1);
-}
-
-#endif
-
-#endif
diff --git a/mono/metadata/sgen-marksweep-fixed.c b/mono/metadata/sgen-marksweep-fixed.c
deleted file mode 100644
index 3d08895bce7..00000000000
--- a/mono/metadata/sgen-marksweep-fixed.c
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "config.h"
-
-#ifdef HAVE_SGEN_GC
-
-#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_FIXED
-
-#define FIXED_HEAP
-
-#include "sgen-marksweep.c"
-
-#else
-
-#include "metadata/sgen-gc.h"
-
-void
-sgen_marksweep_fixed_init (SgenMajorCollector *collector)
-{
- fprintf (stderr, "Error: Mono was configured using --enable-minimal=sgen_marksweep_fixed.\n");
- exit (1);
-}
-
-#endif
-
-#endif
diff --git a/mono/metadata/sgen-marksweep-par.c b/mono/metadata/sgen-marksweep-par.c
deleted file mode 100644
index 5bc7805c870..00000000000
--- a/mono/metadata/sgen-marksweep-par.c
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "config.h"
-
-#ifdef HAVE_SGEN_GC
-
-#ifndef DISABLE_SGEN_MAJOR_MARKSWEEP_PAR
-
-#define SGEN_PARALLEL_MARK
-
-#include "sgen-marksweep.c"
-
-#else
-
-#include "metadata/sgen-gc.h"
-
-void
-sgen_marksweep_par_init (SgenMajorCollector *collector)
-{
- fprintf (stderr, "Error: Mono was configured using --enable-minimal=sgen_marksweep_par.\n");
- exit (1);
-}
-
-#endif /* DISABLE_SGEN_MAJOR_MARKSWEEP_PAR */
-
-#endif
diff --git a/mono/metadata/sgen-marksweep.c b/mono/metadata/sgen-marksweep.c
index d3093385805..dfe7504242f 100644
--- a/mono/metadata/sgen-marksweep.c
+++ b/mono/metadata/sgen-marksweep.c
@@ -40,20 +40,16 @@
#include "metadata/sgen-memory-governor.h"
#include "metadata/sgen-layout-stats.h"
#include "metadata/gc-internal.h"
+#include "metadata/sgen-pointer-queue.h"
+#include "metadata/sgen-pinning.h"
-#if !defined(SGEN_PARALLEL_MARK) && !defined(FIXED_HEAP)
#define SGEN_HAVE_CONCURRENT_MARK
-#endif
#define MS_BLOCK_SIZE (16*1024)
#define MS_BLOCK_SIZE_SHIFT 14
#define MAJOR_SECTION_SIZE MS_BLOCK_SIZE
#define CARDS_PER_BLOCK (MS_BLOCK_SIZE / CARD_SIZE_IN_BYTES)
-#ifdef FIXED_HEAP
-#define MS_DEFAULT_HEAP_NUM_BLOCKS (32 * 1024) /* 512 MB */
-#endif
-
/*
* Don't allocate single blocks, but alloc a contingent of this many
* blocks in one swoop. This must be a power of two.
@@ -65,11 +61,7 @@
* of a block is the MSBlockHeader, then opional padding, then come
* the objects, so this must be >= sizeof (MSBlockHeader).
*/
-#ifdef FIXED_HEAP
-#define MS_BLOCK_SKIP 0
-#else
#define MS_BLOCK_SKIP 16
-#endif
#define MS_BLOCK_FREE (MS_BLOCK_SIZE - MS_BLOCK_SKIP)
@@ -83,55 +75,36 @@ typedef struct _MSBlockInfo MSBlockInfo;
struct _MSBlockInfo {
int obj_size;
int obj_size_index;
- size_t pin_queue_num_entries;
unsigned int pinned : 1;
unsigned int has_references : 1;
unsigned int has_pinned : 1; /* means cannot evacuate */
unsigned int is_to_space : 1;
unsigned int swept : 1;
-#ifdef FIXED_HEAP
- unsigned int used : 1;
- unsigned int zeroed : 1;
-#endif
- MSBlockInfo *next;
char *block;
void **free_list;
MSBlockInfo *next_free;
- void **pin_queue_start;
+ size_t pin_queue_first_entry;
+ size_t pin_queue_last_entry;
#ifdef SGEN_HAVE_CONCURRENT_MARK
guint8 *cardtable_mod_union;
#endif
mword mark_words [MS_NUM_MARK_WORDS];
};
-#ifdef FIXED_HEAP
-static mword ms_heap_num_blocks = MS_DEFAULT_HEAP_NUM_BLOCKS;
-
-static char *ms_heap_start;
-static char *ms_heap_end;
-
-#define MS_PTR_IN_SMALL_MAJOR_HEAP(p) ((char*)(p) >= ms_heap_start && (char*)(p) < ms_heap_end)
-
-/* array of all all block infos in the system */
-static MSBlockInfo *block_infos;
-#endif
+#define MS_BLOCK_FOR_BLOCK_INFO(b) ((b)->block)
-#define MS_BLOCK_OBJ(b,i) ((b)->block + MS_BLOCK_SKIP + (b)->obj_size * (i))
-#define MS_BLOCK_OBJ_FOR_SIZE(b,i,obj_size) ((b)->block + MS_BLOCK_SKIP + (obj_size) * (i))
+#define MS_BLOCK_OBJ(b,i) (MS_BLOCK_FOR_BLOCK_INFO(b) + MS_BLOCK_SKIP + (b)->obj_size * (i))
+#define MS_BLOCK_OBJ_FOR_SIZE(b,i,obj_size) (MS_BLOCK_FOR_BLOCK_INFO(b) + MS_BLOCK_SKIP + (obj_size) * (i))
#define MS_BLOCK_DATA_FOR_OBJ(o) ((char*)((mword)(o) & ~(mword)(MS_BLOCK_SIZE - 1)))
-#ifdef FIXED_HEAP
-#define MS_BLOCK_FOR_OBJ(o) (&block_infos [(mword)((char*)(o) - ms_heap_start) >> MS_BLOCK_SIZE_SHIFT])
-#else
typedef struct {
MSBlockInfo *info;
} MSBlockHeader;
#define MS_BLOCK_FOR_OBJ(o) (((MSBlockHeader*)MS_BLOCK_DATA_FOR_OBJ ((o)))->info)
-#endif
/* object index will always be small */
-#define MS_BLOCK_OBJ_INDEX(o,b) ((int)(((char*)(o) - ((b)->block + MS_BLOCK_SKIP)) / (b)->obj_size))
+#define MS_BLOCK_OBJ_INDEX(o,b) ((int)(((char*)(o) - (MS_BLOCK_FOR_BLOCK_INFO(b) + MS_BLOCK_SKIP)) / (b)->obj_size))
//casting to int is fine since blocks are 32k
#define MS_CALC_MARK_BIT(w,b,o) do { \
@@ -163,7 +136,7 @@ typedef struct {
} \
} while (1)
-#define MS_OBJ_ALLOCED(o,b) (*(void**)(o) && (*(char**)(o) < (b)->block || *(char**)(o) >= (b)->block + MS_BLOCK_SIZE))
+#define MS_OBJ_ALLOCED(o,b) (*(void**)(o) && (*(char**)(o) < MS_BLOCK_FOR_BLOCK_INFO (b) || *(char**)(o) >= MS_BLOCK_FOR_BLOCK_INFO (b) + MS_BLOCK_SIZE))
#define MS_BLOCK_OBJ_SIZE_FACTOR (sqrt (2.0))
@@ -182,12 +155,6 @@ static int fast_block_obj_size_indexes [MS_NUM_FAST_BLOCK_OBJ_SIZE_INDEXES];
#define MS_BLOCK_TYPE_MAX 4
-#ifdef SGEN_PARALLEL_MARK
-static LOCK_DECLARE (ms_block_list_mutex);
-#define LOCK_MS_BLOCK_LIST mono_mutex_lock (&ms_block_list_mutex)
-#define UNLOCK_MS_BLOCK_LIST mono_mutex_unlock (&ms_block_list_mutex)
-#endif
-
static gboolean *evacuate_block_obj_sizes;
static float evacuation_threshold = 0.666f;
#ifdef SGEN_HAVE_CONCURRENT_MARK
@@ -202,33 +169,28 @@ static gboolean have_swept;
static gboolean concurrent_mark;
#endif
+#define BLOCK_IS_TAGGED_HAS_REFERENCES(bl) SGEN_POINTER_IS_TAGGED_1 ((bl))
+#define BLOCK_TAG_HAS_REFERENCES(bl) SGEN_POINTER_TAG_1 ((bl))
+#define BLOCK_UNTAG_HAS_REFERENCES(bl) SGEN_POINTER_UNTAG_1 ((bl))
+
+#define BLOCK_TAG(bl) ((bl)->has_references ? BLOCK_TAG_HAS_REFERENCES ((bl)) : (bl))
+
/* all allocated blocks in the system */
-static MSBlockInfo *all_blocks;
+static SgenPointerQueue allocated_blocks;
-#ifdef FIXED_HEAP
-/* non-allocated block free-list */
-static MSBlockInfo *empty_blocks = NULL;
-#else
/* non-allocated block free-list */
static void *empty_blocks = NULL;
static size_t num_empty_blocks = 0;
-#endif
-#define FOREACH_BLOCK(bl) for ((bl) = all_blocks; (bl); (bl) = (bl)->next) {
-#define END_FOREACH_BLOCK }
+#define FOREACH_BLOCK(bl) { size_t __index; for (__index = 0; __index < allocated_blocks.next_slot; ++__index) { (bl) = BLOCK_UNTAG_HAS_REFERENCES (allocated_blocks.data [__index]);
+#define FOREACH_BLOCK_HAS_REFERENCES(bl,hr) { size_t __index; for (__index = 0; __index < allocated_blocks.next_slot; ++__index) { (bl) = allocated_blocks.data [__index]; (hr) = BLOCK_IS_TAGGED_HAS_REFERENCES ((bl)); (bl) = BLOCK_UNTAG_HAS_REFERENCES ((bl));
+#define END_FOREACH_BLOCK } }
+#define DELETE_BLOCK_IN_FOREACH() (allocated_blocks.data [__index] = NULL)
static size_t num_major_sections = 0;
/* one free block list for each block object size */
static MSBlockInfo **free_block_lists [MS_BLOCK_TYPE_MAX];
-#ifdef SGEN_PARALLEL_MARK
-#ifdef HAVE_KW_THREAD
-static __thread MSBlockInfo ***workers_free_block_lists;
-#else
-static MonoNativeTlsKey workers_free_block_lists_key;
-#endif
-#endif
-
static long long stat_major_blocks_alloced = 0;
static long long stat_major_blocks_freed = 0;
static long long stat_major_blocks_lazy_swept = 0;
@@ -264,55 +226,12 @@ ms_find_block_obj_size_index (size_t size)
#define FREE_BLOCKS_FROM(lists,p,r) (lists [((p) ? MS_BLOCK_FLAG_PINNED : 0) | ((r) ? MS_BLOCK_FLAG_REFS : 0)])
#define FREE_BLOCKS(p,r) (FREE_BLOCKS_FROM (free_block_lists, (p), (r)))
-#ifdef SGEN_PARALLEL_MARK
-#ifdef HAVE_KW_THREAD
-#define FREE_BLOCKS_LOCAL(p,r) (FREE_BLOCKS_FROM (workers_free_block_lists, (p), (r)))
-#else
-#define FREE_BLOCKS_LOCAL(p,r) (FREE_BLOCKS_FROM (((MSBlockInfo***)(mono_native_tls_get_value (workers_free_block_lists_key))), (p), (r)))
-#endif
-#else
-//#define FREE_BLOCKS_LOCAL(p,r) (FREE_BLOCKS_FROM (free_block_lists, (p), (r)))
-#endif
#define MS_BLOCK_OBJ_SIZE_INDEX(s) \
(((s)+7)>>3 < MS_NUM_FAST_BLOCK_OBJ_SIZE_INDEXES ? \
fast_block_obj_size_indexes [((s)+7)>>3] : \
ms_find_block_obj_size_index ((s)))
-#ifdef FIXED_HEAP
-static void*
-major_alloc_heap (mword nursery_size, mword nursery_align, int the_nursery_bits)
-{
- char *nursery_start;
- mword major_heap_size = ms_heap_num_blocks * MS_BLOCK_SIZE;
- mword alloc_size = nursery_size + major_heap_size;
- mword i;
-
- g_assert (ms_heap_num_blocks > 0);
- g_assert (nursery_size % MS_BLOCK_SIZE == 0);
- if (nursery_align)
- g_assert (nursery_align % MS_BLOCK_SIZE == 0);
-
- nursery_start = sgen_alloc_os_memory_aligned (alloc_size, nursery_align ? nursery_align : MS_BLOCK_SIZE, SGEN_ALLOC_HEAP | SGEN_ALLOC_ACTIVATE, "heap");
- ms_heap_start = nursery_start + nursery_size;
- ms_heap_end = ms_heap_start + major_heap_size;
-
- block_infos = sgen_alloc_internal_dynamic (sizeof (MSBlockInfo) * ms_heap_num_blocks, INTERNAL_MEM_MS_BLOCK_INFO, TRUE);
-
- for (i = 0; i < ms_heap_num_blocks; ++i) {
- block_infos [i].block = ms_heap_start + i * MS_BLOCK_SIZE;
- if (i < ms_heap_num_blocks - 1)
- block_infos [i].next_free = &block_infos [i + 1];
- else
- block_infos [i].next_free = NULL;
- block_infos [i].zeroed = TRUE;
- }
-
- empty_blocks = &block_infos [0];
-
- return nursery_start;
-}
-#else
static void*
major_alloc_heap (mword nursery_size, mword nursery_align, int the_nursery_bits)
{
@@ -324,44 +243,13 @@ major_alloc_heap (mword nursery_size, mword nursery_align, int the_nursery_bits)
return start;
}
-#endif
static void
update_heap_boundaries_for_block (MSBlockInfo *block)
{
- sgen_update_heap_boundaries ((mword)block->block, (mword)block->block + MS_BLOCK_SIZE);
+ sgen_update_heap_boundaries ((mword)MS_BLOCK_FOR_BLOCK_INFO (block), (mword)MS_BLOCK_FOR_BLOCK_INFO (block) + MS_BLOCK_SIZE);
}
-#ifdef FIXED_HEAP
-static MSBlockInfo*
-ms_get_empty_block (void)
-{
- MSBlockInfo *block;
-
- g_assert (empty_blocks);
-
- do {
- block = empty_blocks;
- } while (SGEN_CAS_PTR ((gpointer*)&empty_blocks, block->next_free, block) != block);
-
- block->used = TRUE;
-
- if (!block->zeroed)
- memset (block->block, 0, MS_BLOCK_SIZE);
-
- return block;
-}
-
-static void
-ms_free_block (MSBlockInfo *block)
-{
- block->next_free = empty_blocks;
- empty_blocks = block;
- block->used = FALSE;
- block->zeroed = FALSE;
- sgen_memgov_release_space (MS_BLOCK_SIZE, SPACE_MAJOR);
-}
-#else
static void*
ms_get_empty_block (void)
{
@@ -440,7 +328,6 @@ ms_free_block (void *block)
SGEN_ATOMIC_ADD_P (num_empty_blocks, 1);
}
-#endif
//#define MARKSWEEP_CONSISTENCY_CHECK
@@ -459,30 +346,19 @@ check_block_free_list (MSBlockInfo *block, int size, gboolean pinned)
if (block->swept)
g_assert (block->free_list);
-#ifdef FIXED_HEAP
- /* the block must not be in the empty_blocks list */
- for (b = empty_blocks; b; b = b->next_free)
- g_assert (b != block);
-#endif
- /* the block must be in the all_blocks list */
- for (b = all_blocks; b; b = b->next) {
- if (b == block)
- break;
- }
- g_assert (b == block);
+ /* the block must be in the allocated_blocks array */
+ g_assert (sgen_pointer_queue_find (&allocated_blocks, BLOCK_TAG (block)) != (size_t)-1);
}
}
static void
check_empty_blocks (void)
{
-#ifndef FIXED_HEAP
void *p;
size_t i = 0;
for (p = empty_blocks; p; p = *(void**)p)
++i;
g_assert (i == num_empty_blocks);
-#endif
}
static void
@@ -497,10 +373,8 @@ consistency_check (void)
int num_free = 0;
void **free;
-#ifndef FIXED_HEAP
/* check block header */
g_assert (((MSBlockHeader*)block->block)->info == block);
-#endif
/* count number of free slots */
for (i = 0; i < count; ++i) {
@@ -540,12 +414,7 @@ ms_alloc_block (int size_index, gboolean pinned, gboolean has_references)
int size = block_obj_sizes [size_index];
int count = MS_BLOCK_FREE / size;
MSBlockInfo *info;
-#ifdef SGEN_PARALLEL_MARK
- MSBlockInfo *next;
-#endif
-#ifndef FIXED_HEAP
MSBlockHeader *header;
-#endif
MSBlockInfo **free_blocks = FREE_BLOCKS (pinned, has_references);
char *obj_start;
int i;
@@ -553,11 +422,7 @@ ms_alloc_block (int size_index, gboolean pinned, gboolean has_references)
if (!sgen_memgov_try_alloc_space (MS_BLOCK_SIZE, SPACE_MAJOR))
return FALSE;
-#ifdef FIXED_HEAP
- info = ms_get_empty_block ();
-#else
info = sgen_alloc_internal (INTERNAL_MEM_MS_BLOCK_INFO);
-#endif
SGEN_ASSERT (9, count >= 2, "block with %d objects, it must hold at least 2", count);
@@ -574,12 +439,10 @@ ms_alloc_block (int size_index, gboolean pinned, gboolean has_references)
*/
info->is_to_space = (sgen_get_current_collection_generation () == GENERATION_OLD);
info->swept = 1;
-#ifndef FIXED_HEAP
info->block = ms_get_empty_block ();
header = (MSBlockHeader*) info->block;
header->info = info;
-#endif
#ifdef SGEN_HAVE_CONCURRENT_MARK
info->cardtable_mod_union = NULL;
#endif
@@ -587,7 +450,7 @@ ms_alloc_block (int size_index, gboolean pinned, gboolean has_references)
update_heap_boundaries_for_block (info);
/* build free list */
- obj_start = info->block + MS_BLOCK_SKIP;
+ obj_start = MS_BLOCK_FOR_BLOCK_INFO (info) + MS_BLOCK_SKIP;
info->free_list = (void**)obj_start;
/* we're skipping the last one - it must be nulled */
for (i = 0; i < count - 1; ++i) {
@@ -598,21 +461,10 @@ ms_alloc_block (int size_index, gboolean pinned, gboolean has_references)
/* the last one */
*(void**)obj_start = NULL;
-#ifdef SGEN_PARALLEL_MARK
- do {
- next = info->next_free = free_blocks [size_index];
- } while (SGEN_CAS_PTR ((void**)&free_blocks [size_index], info, next) != next);
-
- do {
- next = info->next = all_blocks;
- } while (SGEN_CAS_PTR ((void**)&all_blocks, info, next) != next);
-#else
info->next_free = free_blocks [size_index];
free_blocks [size_index] = info;
- info->next = all_blocks;
- all_blocks = info;
-#endif
+ sgen_pointer_queue_add (&allocated_blocks, BLOCK_TAG (info));
++num_major_sections;
return TRUE;
@@ -624,7 +476,7 @@ obj_is_from_pinned_alloc (char *ptr)
MSBlockInfo *block;
FOREACH_BLOCK (block) {
- if (ptr >= block->block && ptr <= block->block + MS_BLOCK_SIZE)
+ if (ptr >= MS_BLOCK_FOR_BLOCK_INFO (block) && ptr <= MS_BLOCK_FOR_BLOCK_INFO (block) + MS_BLOCK_SIZE)
return block->pinned;
} END_FOREACH_BLOCK;
return FALSE;
@@ -656,86 +508,6 @@ unlink_slot_from_free_list_uncontested (MSBlockInfo **free_blocks, int size_inde
return obj;
}
-#ifdef SGEN_PARALLEL_MARK
-static gboolean
-try_remove_block_from_free_list (MSBlockInfo *block, MSBlockInfo **free_blocks, int size_index)
-{
- /*
- * No more free slots in the block, so try to free the block.
- * Don't try again if we don't succeed - another thread will
- * already have done it.
- */
- MSBlockInfo *next_block = block->next_free;
- if (SGEN_CAS_PTR ((void**)&free_blocks [size_index], next_block, block) == block) {
- /*
- void *old = SGEN_CAS_PTR ((void**)&block->next_free, NULL, next_block);
- g_assert (old == next_block);
- */
- block->next_free = NULL;
- return TRUE;
- }
- return FALSE;
-}
-
-static void*
-alloc_obj_par (MonoVTable *vtable, int size, gboolean pinned, gboolean has_references)
-{
- int size_index = MS_BLOCK_OBJ_SIZE_INDEX (size);
- MSBlockInfo **free_blocks_local = FREE_BLOCKS_LOCAL (pinned, has_references);
- MSBlockInfo *block;
- void *obj;
-
-#ifdef SGEN_HAVE_CONCURRENT_MARK
- if (concurrent_mark)
- g_assert_not_reached ();
-#endif
-
- SGEN_ASSERT (9, current_collection_generation == GENERATION_OLD, "old gen parallel allocator called from a %d collection", current_collection_generation);
-
- if (free_blocks_local [size_index]) {
- get_slot:
- obj = unlink_slot_from_free_list_uncontested (free_blocks_local, size_index);
- } else {
- MSBlockInfo **free_blocks = FREE_BLOCKS (pinned, has_references);
-
- get_block:
- block = free_blocks [size_index];
- if (block) {
- if (!try_remove_block_from_free_list (block, free_blocks, size_index))
- goto get_block;
-
- g_assert (block->next_free == NULL);
- g_assert (block->free_list);
- block->next_free = free_blocks_local [size_index];
- free_blocks_local [size_index] = block;
-
- goto get_slot;
- } else {
- gboolean success;
-
- LOCK_MS_BLOCK_LIST;
- success = ms_alloc_block (size_index, pinned, has_references);
- UNLOCK_MS_BLOCK_LIST;
-
- if (G_UNLIKELY (!success))
- return NULL;
-
- goto get_block;
- }
- }
-
- *(MonoVTable**)obj = vtable;
-
- return obj;
-}
-
-static void*
-major_par_alloc_object (MonoVTable *vtable, size_t size, gboolean has_references)
-{
- return alloc_obj_par (vtable, size, FALSE, has_references);
-}
-#endif
-
static void*
alloc_obj (MonoVTable *vtable, size_t size, gboolean pinned, gboolean has_references)
{
@@ -743,11 +515,6 @@ alloc_obj (MonoVTable *vtable, size_t size, gboolean pinned, gboolean has_refere
MSBlockInfo **free_blocks = FREE_BLOCKS (pinned, has_references);
void *obj;
-#ifdef SGEN_PARALLEL_MARK
- SGEN_ASSERT (9, current_collection_generation == GENERATION_OLD, "old gen parallel allocator called from a %d collection", current_collection_generation);
-
-#endif
-
if (!free_blocks [size_index]) {
if (G_UNLIKELY (!ms_alloc_block (size_index, pinned, has_references)))
return NULL;
@@ -859,24 +626,16 @@ major_is_object_live (char *obj)
{
MSBlockInfo *block;
int word, bit;
-#ifndef FIXED_HEAP
mword objsize;
-#endif
if (sgen_ptr_in_nursery (obj))
return FALSE;
-#ifdef FIXED_HEAP
- /* LOS */
- if (!MS_PTR_IN_SMALL_MAJOR_HEAP (obj))
- return FALSE;
-#else
objsize = SGEN_ALIGN_UP (sgen_safe_object_get_size ((MonoObject*)obj));
/* LOS */
if (objsize > SGEN_MAX_SMALL_OBJ_SIZE)
return FALSE;
-#endif
/* now we know it's in a major block */
block = MS_BLOCK_FOR_OBJ (obj);
@@ -891,7 +650,7 @@ major_ptr_is_in_non_pinned_space (char *ptr, char **start)
MSBlockInfo *block;
FOREACH_BLOCK (block) {
- if (ptr >= block->block && ptr <= block->block + MS_BLOCK_SIZE) {
+ if (ptr >= MS_BLOCK_FOR_BLOCK_INFO (block) && ptr <= MS_BLOCK_FOR_BLOCK_INFO (block) + MS_BLOCK_SIZE) {
int count = MS_BLOCK_FREE / block->obj_size;
int i;
@@ -952,7 +711,7 @@ major_is_valid_object (char *object)
int idx;
char *obj;
- if ((block->block > object) || ((block->block + MS_BLOCK_SIZE) <= object))
+ if ((MS_BLOCK_FOR_BLOCK_INFO (block) > object) || ((MS_BLOCK_FOR_BLOCK_INFO (block) + MS_BLOCK_SIZE) <= object))
continue;
idx = MS_BLOCK_OBJ_INDEX (object, block);
@@ -979,11 +738,11 @@ major_describe_pointer (char *ptr)
int w, b;
gboolean marked;
- if ((block->block > ptr) || ((block->block + MS_BLOCK_SIZE) <= ptr))
+ if ((MS_BLOCK_FOR_BLOCK_INFO (block) > ptr) || ((MS_BLOCK_FOR_BLOCK_INFO (block) + MS_BLOCK_SIZE) <= ptr))
continue;
SGEN_LOG (0, "major-ptr (block %p sz %d pin %d ref %d)\n",
- block->block, block->obj_size, block->pinned, block->has_references);
+ MS_BLOCK_FOR_BLOCK_INFO (block), block->obj_size, block->pinned, block->has_references);
idx = MS_BLOCK_OBJ_INDEX (ptr, block);
obj = (char*)MS_BLOCK_OBJ (block, idx);
@@ -1061,7 +820,7 @@ major_dump_heap (FILE *heap_dump_file)
start = i;
} else {
if (start >= 0) {
- sgen_dump_occupied (MS_BLOCK_OBJ (block, start), MS_BLOCK_OBJ (block, i), block->block);
+ sgen_dump_occupied (MS_BLOCK_OBJ (block, start), MS_BLOCK_OBJ (block, i), MS_BLOCK_FOR_BLOCK_INFO (block));
start = -1;
}
}
@@ -1073,30 +832,30 @@ major_dump_heap (FILE *heap_dump_file)
#define LOAD_VTABLE SGEN_LOAD_VTABLE
-#define MS_MARK_OBJECT_AND_ENQUEUE_CHECKED(obj,block,queue) do { \
+#define MS_MARK_OBJECT_AND_ENQUEUE_CHECKED(obj,desc,block,queue) do { \
int __word, __bit; \
MS_CALC_MARK_BIT (__word, __bit, (obj)); \
if (!MS_MARK_BIT ((block), __word, __bit) && MS_OBJ_ALLOCED ((obj), (block))) { \
MS_SET_MARK_BIT ((block), __word, __bit); \
if ((block)->has_references) \
- GRAY_OBJECT_ENQUEUE ((queue), (obj)); \
+ GRAY_OBJECT_ENQUEUE ((queue), (obj), (desc)); \
binary_protocol_mark ((obj), (gpointer)LOAD_VTABLE ((obj)), sgen_safe_object_get_size ((MonoObject*)(obj))); \
INC_NUM_MAJOR_OBJECTS_MARKED (); \
} \
} while (0)
-#define MS_MARK_OBJECT_AND_ENQUEUE(obj,block,queue) do { \
+#define MS_MARK_OBJECT_AND_ENQUEUE(obj,desc,block,queue) do { \
int __word, __bit; \
MS_CALC_MARK_BIT (__word, __bit, (obj)); \
SGEN_ASSERT (9, MS_OBJ_ALLOCED ((obj), (block)), "object %p not allocated", obj); \
if (!MS_MARK_BIT ((block), __word, __bit)) { \
MS_SET_MARK_BIT ((block), __word, __bit); \
if ((block)->has_references) \
- GRAY_OBJECT_ENQUEUE ((queue), (obj)); \
+ GRAY_OBJECT_ENQUEUE ((queue), (obj), (desc)); \
binary_protocol_mark ((obj), (gpointer)LOAD_VTABLE ((obj)), sgen_safe_object_get_size ((MonoObject*)(obj))); \
INC_NUM_MAJOR_OBJECTS_MARKED (); \
} \
} while (0)
-#define MS_PAR_MARK_OBJECT_AND_ENQUEUE(obj,block,queue) do { \
+#define MS_PAR_MARK_OBJECT_AND_ENQUEUE(obj,desc,block,queue) do { \
int __word, __bit; \
gboolean __was_marked; \
SGEN_ASSERT (9, MS_OBJ_ALLOCED ((obj), (block)), "object %p not allocated", obj); \
@@ -1104,7 +863,7 @@ major_dump_heap (FILE *heap_dump_file)
MS_PAR_SET_MARK_BIT (__was_marked, (block), __word, __bit); \
if (!__was_marked) { \
if ((block)->has_references) \
- GRAY_OBJECT_ENQUEUE ((queue), (obj)); \
+ GRAY_OBJECT_ENQUEUE ((queue), (obj), (desc)); \
binary_protocol_mark ((obj), (gpointer)LOAD_VTABLE ((obj)), sgen_safe_object_get_size ((MonoObject*)(obj))); \
INC_NUM_MAJOR_OBJECTS_MARKED (); \
} \
@@ -1122,170 +881,11 @@ pin_major_object (char *obj, SgenGrayQueue *queue)
block = MS_BLOCK_FOR_OBJ (obj);
block->has_pinned = TRUE;
- MS_MARK_OBJECT_AND_ENQUEUE (obj, block, queue);
+ MS_MARK_OBJECT_AND_ENQUEUE (obj, sgen_obj_get_descriptor (obj), block, queue);
}
#include "sgen-major-copy-object.h"
-#ifdef SGEN_PARALLEL_MARK
-static void
-major_copy_or_mark_object (void **ptr, void *obj, SgenGrayQueue *queue)
-{
- mword objsize;
- MSBlockInfo *block;
- MonoVTable *vt;
-
- HEAVY_STAT (++stat_copy_object_called_major);
-
- SGEN_ASSERT (9, obj, "null object from pointer %p", ptr);
- SGEN_ASSERT (9, current_collection_generation == GENERATION_OLD, "old gen parallel allocator called from a %d collection", current_collection_generation);
-
- if (sgen_ptr_in_nursery (obj)) {
- int word, bit;
- gboolean has_references;
- void *destination;
- mword vtable_word = *(mword*)obj;
- vt = (MonoVTable*)(vtable_word & ~SGEN_VTABLE_BITS_MASK);
-
- if (vtable_word & SGEN_FORWARDED_BIT) {
- *ptr = (void*)vt;
- return;
- }
-
- if (vtable_word & SGEN_PINNED_BIT)
- return;
-
- /* An object in the nursery To Space has already been copied and grayed. Nothing to do. */
- if (sgen_nursery_is_to_space (obj))
- return;
-
- HEAVY_STAT (++stat_objects_copied_major);
-
- do_copy_object:
- objsize = SGEN_ALIGN_UP (sgen_par_object_get_size (vt, (MonoObject*)obj));
- has_references = SGEN_VTABLE_HAS_REFERENCES (vt);
-
- destination = sgen_minor_collector.par_alloc_for_promotion (vt, obj, objsize, has_references);
- if (G_UNLIKELY (!destination)) {
- if (!sgen_ptr_in_nursery (obj)) {
- int size_index;
- block = MS_BLOCK_FOR_OBJ (obj);
- size_index = block->obj_size_index;
- evacuate_block_obj_sizes [size_index] = FALSE;
- }
-
- sgen_parallel_pin_or_update (ptr, obj, vt, queue);
- sgen_set_pinned_from_failed_allocation (objsize);
- return;
- }
-
- if (SGEN_CAS_PTR (obj, (void*)((mword)destination | SGEN_FORWARDED_BIT), vt) == vt) {
- gboolean was_marked;
-
- par_copy_object_no_checks (destination, vt, obj, objsize, has_references ? queue : NULL);
- obj = destination;
- *ptr = obj;
-
- /*
- * FIXME: If we make major_alloc_object() give
- * us the block info, too, we won't have to
- * re-fetch it here.
- *
- * FIXME (2): We should rework this to avoid all those nursery checks.
- */
- /*
- * For the split nursery allocator the object
- * might still be in the nursery despite
- * having being promoted, in which case we
- * can't mark it.
- */
- if (!sgen_ptr_in_nursery (obj)) {
- block = MS_BLOCK_FOR_OBJ (obj);
- MS_CALC_MARK_BIT (word, bit, obj);
- SGEN_ASSERT (9, !MS_MARK_BIT (block, word, bit), "object %p already marked", obj);
- MS_PAR_SET_MARK_BIT (was_marked, block, word, bit);
- binary_protocol_mark (obj, vt, sgen_safe_object_get_size ((MonoObject*)obj));
- }
- } else {
- /*
- * FIXME: We have allocated destination, but
- * we cannot use it. Give it back to the
- * allocator.
- */
- *(void**)destination = NULL;
-
- vtable_word = *(mword*)obj;
- g_assert (vtable_word & SGEN_FORWARDED_BIT);
-
- obj = (void*)(vtable_word & ~SGEN_VTABLE_BITS_MASK);
-
- *ptr = obj;
-
- HEAVY_STAT (++stat_slots_allocated_in_vain);
- }
- } else {
-#ifdef FIXED_HEAP
- if (MS_PTR_IN_SMALL_MAJOR_HEAP (obj))
-#else
- mword vtable_word = *(mword*)obj;
- vt = (MonoVTable*)(vtable_word & ~SGEN_VTABLE_BITS_MASK);
-
- /* see comment in the non-parallel version below */
- if (vtable_word & SGEN_FORWARDED_BIT) {
- *ptr = (void*)vt;
- return;
- }
- objsize = SGEN_ALIGN_UP (sgen_par_object_get_size (vt, (MonoObject*)obj));
-
- if (objsize <= SGEN_MAX_SMALL_OBJ_SIZE)
-#endif
- {
- int size_index;
-
- block = MS_BLOCK_FOR_OBJ (obj);
- size_index = block->obj_size_index;
-
- if (!block->has_pinned && evacuate_block_obj_sizes [size_index]) {
- if (block->is_to_space)
- return;
-
-#ifdef FIXED_HEAP
- {
- mword vtable_word = *(mword*)obj;
- vt = (MonoVTable*)(vtable_word & ~SGEN_VTABLE_BITS_MASK);
-
- if (vtable_word & SGEN_FORWARDED_BIT) {
- *ptr = (void*)vt;
- return;
- }
- }
-#endif
-
- HEAVY_STAT (++stat_major_objects_evacuated);
- goto do_copy_object;
- }
-
- MS_PAR_MARK_OBJECT_AND_ENQUEUE (obj, block, queue);
- } else {
- LOSObject *bigobj = sgen_los_header_for_object (obj);
- mword size_word = bigobj->size;
-#ifdef FIXED_HEAP
- mword vtable_word = *(mword*)obj;
- vt = (MonoVTable*)(vtable_word & ~SGEN_VTABLE_BITS_MASK);
-#endif
- if (size_word & 1)
- return;
- binary_protocol_pin (obj, vt, sgen_safe_object_get_size ((MonoObject*)obj));
- if (SGEN_CAS_PTR ((void*)&bigobj->size, (void*)(size_word | 1), (void*)size_word) == (void*)size_word) {
- if (SGEN_VTABLE_HAS_REFERENCES (vt))
- GRAY_OBJECT_ENQUEUE (queue, obj);
- } else {
- g_assert (sgen_los_object_is_pinned (obj));
- }
- }
- }
-}
-#else
#ifdef SGEN_HAVE_CONCURRENT_MARK
static void
major_copy_or_mark_object_concurrent (void **ptr, void *obj, SgenGrayQueue *queue)
@@ -1293,18 +893,13 @@ major_copy_or_mark_object_concurrent (void **ptr, void *obj, SgenGrayQueue *queu
g_assert (!SGEN_OBJECT_IS_FORWARDED (obj));
if (!sgen_ptr_in_nursery (obj)) {
-#ifdef FIXED_HEAP
- if (MS_PTR_IN_SMALL_MAJOR_HEAP (obj))
-#else
mword objsize;
objsize = SGEN_ALIGN_UP (sgen_safe_object_get_size ((MonoObject*)obj));
- if (objsize <= SGEN_MAX_SMALL_OBJ_SIZE)
-#endif
- {
+ if (objsize <= SGEN_MAX_SMALL_OBJ_SIZE) {
MSBlockInfo *block = MS_BLOCK_FOR_OBJ (obj);
- MS_MARK_OBJECT_AND_ENQUEUE (obj, block, queue);
+ MS_MARK_OBJECT_AND_ENQUEUE (obj, sgen_obj_get_descriptor (obj), block, queue);
} else {
if (sgen_los_object_is_pinned (obj))
return;
@@ -1318,7 +913,7 @@ major_copy_or_mark_object_concurrent (void **ptr, void *obj, SgenGrayQueue *queu
sgen_los_pin_object (obj);
if (SGEN_OBJECT_HAS_REFERENCES (obj))
- GRAY_OBJECT_ENQUEUE (queue, obj);
+ GRAY_OBJECT_ENQUEUE (queue, obj, sgen_obj_get_descriptor (obj));
INC_NUM_MAJOR_OBJECTS_MARKED ();
}
}
@@ -1362,7 +957,7 @@ major_copy_or_mark_object (void **ptr, void *obj, SgenGrayQueue *queue)
block = MS_BLOCK_FOR_OBJ (obj);
size_index = block->obj_size_index;
evacuate_block_obj_sizes [size_index] = FALSE;
- MS_MARK_OBJECT_AND_ENQUEUE (obj, block, queue);
+ MS_MARK_OBJECT_AND_ENQUEUE (obj, sgen_obj_get_descriptor (obj), block, queue);
}
return;
}
@@ -1390,9 +985,6 @@ major_copy_or_mark_object (void **ptr, void *obj, SgenGrayQueue *queue)
}
} else {
char *forwarded;
-#ifdef FIXED_HEAP
- if (MS_PTR_IN_SMALL_MAJOR_HEAP (obj))
-#else
mword objsize;
/*
@@ -1410,9 +1002,7 @@ major_copy_or_mark_object (void **ptr, void *obj, SgenGrayQueue *queue)
objsize = SGEN_ALIGN_UP (sgen_safe_object_get_size ((MonoObject*)obj));
- if (objsize <= SGEN_MAX_SMALL_OBJ_SIZE)
-#endif
- {
+ if (objsize <= SGEN_MAX_SMALL_OBJ_SIZE) {
int size_index;
gboolean evacuate;
@@ -1420,20 +1010,6 @@ major_copy_or_mark_object (void **ptr, void *obj, SgenGrayQueue *queue)
size_index = block->obj_size_index;
evacuate = evacuate_block_obj_sizes [size_index];
-#ifdef FIXED_HEAP
- /*
- * We could also check for !block->has_pinned
- * here, but it would only make an uncommon case
- * faster, namely objects that are in blocks
- * whose slot sizes are evacuated but which have
- * pinned objects.
- */
- if (evacuate && (forwarded = SGEN_OBJECT_IS_FORWARDED (obj))) {
- *ptr = forwarded;
- return;
- }
-#endif
-
if (evacuate && !block->has_pinned) {
g_assert (!SGEN_OBJECT_IS_PINNED (obj));
if (block->is_to_space)
@@ -1441,7 +1017,7 @@ major_copy_or_mark_object (void **ptr, void *obj, SgenGrayQueue *queue)
HEAVY_STAT (++stat_major_objects_evacuated);
goto do_copy_object;
} else {
- MS_MARK_OBJECT_AND_ENQUEUE (obj, block, queue);
+ MS_MARK_OBJECT_AND_ENQUEUE (obj, sgen_obj_get_descriptor (obj), block, queue);
}
} else {
if (sgen_los_object_is_pinned (obj))
@@ -1457,11 +1033,10 @@ major_copy_or_mark_object (void **ptr, void *obj, SgenGrayQueue *queue)
sgen_los_pin_object (obj);
if (SGEN_OBJECT_HAS_REFERENCES (obj))
- GRAY_OBJECT_ENQUEUE (queue, obj);
+ GRAY_OBJECT_ENQUEUE (queue, obj, sgen_obj_get_descriptor (obj));
}
}
}
-#endif
static void
major_copy_or_mark_object_canonical (void **ptr, SgenGrayQueue *queue)
@@ -1475,6 +1050,7 @@ major_copy_or_mark_object_concurrent_canonical (void **ptr, SgenGrayQueue *queue
{
major_copy_or_mark_object_concurrent (ptr, *ptr, queue);
}
+#endif
static long long
major_get_and_reset_num_major_objects_marked (void)
@@ -1487,7 +1063,6 @@ major_get_and_reset_num_major_objects_marked (void)
return 0;
#endif
}
-#endif
#include "sgen-major-scan-object.h"
@@ -1500,20 +1075,25 @@ major_get_and_reset_num_major_objects_marked (void)
static void
mark_pinned_objects_in_block (MSBlockInfo *block, SgenGrayQueue *queue)
{
- int i;
+ void **entry, **end;
int last_index = -1;
- if (!block->pin_queue_num_entries)
+ if (block->pin_queue_first_entry == block->pin_queue_last_entry)
return;
block->has_pinned = TRUE;
- for (i = 0; i < block->pin_queue_num_entries; ++i) {
- int index = MS_BLOCK_OBJ_INDEX (block->pin_queue_start [i], block);
- SGEN_ASSERT (9, index >= 0 && index < MS_BLOCK_FREE / block->obj_size, "invalid object %p index %d max-index %d", block->pin_queue_start [i], index, MS_BLOCK_FREE / block->obj_size);
+ entry = sgen_pinning_get_entry (block->pin_queue_first_entry);
+ end = sgen_pinning_get_entry (block->pin_queue_last_entry);
+
+ for (; entry < end; ++entry) {
+ int index = MS_BLOCK_OBJ_INDEX (*entry, block);
+ char *obj;
+ SGEN_ASSERT (9, index >= 0 && index < MS_BLOCK_FREE / block->obj_size, "invalid object %p index %d max-index %d", *entry, index, MS_BLOCK_FREE / block->obj_size);
if (index == last_index)
continue;
- MS_MARK_OBJECT_AND_ENQUEUE_CHECKED (MS_BLOCK_OBJ (block, index), block, queue);
+ obj = MS_BLOCK_OBJ (block, index);
+ MS_MARK_OBJECT_AND_ENQUEUE_CHECKED (obj, sgen_obj_get_descriptor (obj), block, queue);
last_index = index;
}
}
@@ -1620,7 +1200,7 @@ static void
ms_sweep (void)
{
int i;
- MSBlockInfo **iter;
+ MSBlockInfo *block;
/* statistics for evacuation */
int *slots_available = alloca (sizeof (int) * num_block_obj_sizes);
@@ -1644,9 +1224,7 @@ ms_sweep (void)
}
/* traverse all blocks, free and zero unmarked objects */
- iter = &all_blocks;
- while (*iter) {
- MSBlockInfo *block = *iter;
+ FOREACH_BLOCK (block) {
int count;
gboolean have_live = FALSE;
gboolean has_pinned;
@@ -1691,8 +1269,6 @@ ms_sweep (void)
slots_available [obj_size_index] += count;
}
- iter = &block->next;
-
/*
* If there are free slots in the block, add
* the block to the corresponding free list.
@@ -1710,20 +1286,16 @@ ms_sweep (void)
* Blocks without live objects are removed from the
* block list and freed.
*/
- *iter = block->next;
+ DELETE_BLOCK_IN_FOREACH ();
binary_protocol_empty (MS_BLOCK_OBJ (block, 0), (char*)MS_BLOCK_OBJ (block, count) - (char*)MS_BLOCK_OBJ (block, 0));
-#ifdef FIXED_HEAP
- ms_free_block (block);
-#else
ms_free_block (block->block);
-
sgen_free_internal (block, INTERNAL_MEM_MS_BLOCK_INFO);
-#endif
--num_major_sections;
}
- }
+ } END_FOREACH_BLOCK;
+ sgen_pointer_queue_remove_nulls (&allocated_blocks);
for (i = 0; i < num_block_obj_sizes; ++i) {
float usage = (float)slots_used [i] / (float)slots_available [i];
@@ -1869,18 +1441,13 @@ major_start_major_collection (void)
// Sweep all unswept blocks
if (lazy_sweep) {
- MSBlockInfo **iter;
+ MSBlockInfo *block;
MONO_GC_SWEEP_BEGIN (GENERATION_OLD, TRUE);
- iter = &all_blocks;
- while (*iter) {
- MSBlockInfo *block = *iter;
-
+ FOREACH_BLOCK (block) {
sweep_block (block, TRUE);
-
- iter = &block->next;
- }
+ } END_FOREACH_BLOCK;
MONO_GC_SWEEP_END (GENERATION_OLD, TRUE);
}
@@ -1891,7 +1458,7 @@ major_finish_major_collection (void)
{
}
-#if !defined(FIXED_HEAP) && SIZEOF_VOID_P != 8
+#if SIZEOF_VOID_P != 8
static int
compare_pointers (const void *va, const void *vb) {
char *a = *(char**)va, *b = *(char**)vb;
@@ -1906,7 +1473,6 @@ compare_pointers (const void *va, const void *vb) {
static void
major_have_computer_minor_collection_allowance (void)
{
-#ifndef FIXED_HEAP
size_t section_reserve = sgen_get_minor_collection_allowance () / MS_BLOCK_SIZE;
g_assert (have_swept);
@@ -2056,7 +1622,6 @@ major_have_computer_minor_collection_allowance (void)
++stat_major_blocks_freed_individual;
#endif
}
-#endif
}
static void
@@ -2065,8 +1630,8 @@ major_find_pin_queue_start_ends (SgenGrayQueue *queue)
MSBlockInfo *block;
FOREACH_BLOCK (block) {
- block->pin_queue_start = sgen_find_optimized_pin_queue_area (block->block + MS_BLOCK_SKIP, block->block + MS_BLOCK_SIZE,
- &block->pin_queue_num_entries);
+ sgen_find_optimized_pin_queue_area (MS_BLOCK_FOR_BLOCK_INFO (block) + MS_BLOCK_SKIP, MS_BLOCK_FOR_BLOCK_INFO (block) + MS_BLOCK_SIZE,
+ &block->pin_queue_first_entry, &block->pin_queue_last_entry);
} END_FOREACH_BLOCK;
}
@@ -2117,17 +1682,6 @@ get_num_major_sections (void)
static gboolean
major_handle_gc_param (const char *opt)
{
-#ifdef FIXED_HEAP
- if (g_str_has_prefix (opt, "major-heap-size=")) {
- const char *arg = strchr (opt, '=') + 1;
- size_t size;
- if (!mono_gc_parse_environment_string_extract_number (arg, &size))
- return FALSE;
- ms_heap_num_blocks = (size + MS_BLOCK_SIZE - 1) / MS_BLOCK_SIZE;
- g_assert (ms_heap_num_blocks > 0);
- return TRUE;
- } else
-#endif
if (g_str_has_prefix (opt, "evacuation-threshold=")) {
const char *arg = strchr (opt, '=') + 1;
int percentage = atoi (arg);
@@ -2153,9 +1707,6 @@ major_print_gc_param_usage (void)
{
fprintf (stderr,
""
-#ifdef FIXED_HEAP
- " major-heap-size=N (where N is an integer, possibly with a k, m or a g suffix)\n"
-#endif
" evacuation-threshold=P (where P is a percentage, an integer in 0-100)\n"
" (no-)lazy-sweep\n"
);
@@ -2165,10 +1716,11 @@ static void
major_iterate_live_block_ranges (sgen_cardtable_block_callback callback)
{
MSBlockInfo *block;
+ gboolean has_references;
- FOREACH_BLOCK (block) {
- if (block->has_references)
- callback ((mword)block->block, MS_BLOCK_SIZE);
+ FOREACH_BLOCK_HAS_REFERENCES (block, has_references) {
+ if (has_references)
+ callback ((mword)MS_BLOCK_FOR_BLOCK_INFO (block), MS_BLOCK_SIZE);
} END_FOREACH_BLOCK;
}
@@ -2232,6 +1784,7 @@ static void
major_scan_card_table (gboolean mod_union, SgenGrayQueue *queue)
{
MSBlockInfo *block;
+ gboolean has_references;
ScanObjectFunc scan_func = sgen_get_current_object_ops ()->scan_object;
#ifdef SGEN_HAVE_CONCURRENT_MARK
@@ -2241,15 +1794,15 @@ major_scan_card_table (gboolean mod_union, SgenGrayQueue *queue)
g_assert (!mod_union);
#endif
- FOREACH_BLOCK (block) {
+ FOREACH_BLOCK_HAS_REFERENCES (block, has_references) {
int block_obj_size;
char *block_start;
- if (!block->has_references)
+ if (!has_references)
continue;
block_obj_size = block->obj_size;
- block_start = block->block;
+ block_start = MS_BLOCK_FOR_BLOCK_INFO (block);
if (block_obj_size >= CARD_SIZE_IN_BYTES) {
guint8 *cards;
@@ -2377,7 +1930,7 @@ major_scan_card_table (gboolean mod_union, SgenGrayQueue *queue)
}
HEAVY_STAT (++scanned_objects);
- scan_func (obj, queue);
+ scan_func (obj, sgen_obj_get_descriptor (obj), queue);
next_small:
obj += block_obj_size;
}
@@ -2392,14 +1945,15 @@ static void
major_count_cards (long long *num_total_cards, long long *num_marked_cards)
{
MSBlockInfo *block;
+ gboolean has_references;
long long total_cards = 0;
long long marked_cards = 0;
- FOREACH_BLOCK (block) {
- guint8 *cards = sgen_card_table_get_card_scan_address ((mword) block->block);
+ FOREACH_BLOCK_HAS_REFERENCES (block, has_references) {
+ guint8 *cards = sgen_card_table_get_card_scan_address ((mword) MS_BLOCK_FOR_BLOCK_INFO (block));
int i;
- if (!block->has_references)
+ if (!has_references)
continue;
total_cards += CARDS_PER_BLOCK;
@@ -2423,7 +1977,7 @@ update_cardtable_mod_union (void)
size_t num_cards;
block->cardtable_mod_union = sgen_card_table_update_mod_union (block->cardtable_mod_union,
- block->block, MS_BLOCK_SIZE, &num_cards);
+ MS_BLOCK_FOR_BLOCK_INFO (block), MS_BLOCK_SIZE, &num_cards);
SGEN_ASSERT (0, num_cards == CARDS_PER_BLOCK, "Number of cards calculation is wrong");
} END_FOREACH_BLOCK;
@@ -2433,7 +1987,7 @@ static guint8*
major_get_cardtable_mod_union_for_object (char *obj)
{
MSBlockInfo *block = MS_BLOCK_FOR_OBJ (obj);
- return &block->cardtable_mod_union [(obj - (char*)sgen_card_table_align_pointer (block->block)) >> CARD_BITS];
+ return &block->cardtable_mod_union [(obj - (char*)sgen_card_table_align_pointer (MS_BLOCK_FOR_BLOCK_INFO (block))) >> CARD_BITS];
}
#endif
@@ -2445,49 +1999,6 @@ alloc_free_block_lists (MSBlockInfo ***lists)
lists [i] = sgen_alloc_internal_dynamic (sizeof (MSBlockInfo*) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES, TRUE);
}
-#ifdef SGEN_PARALLEL_MARK
-static void*
-major_alloc_worker_data (void)
-{
- /* FIXME: free this when the workers come down */
- MSBlockInfo ***lists = malloc (sizeof (MSBlockInfo**) * MS_BLOCK_TYPE_MAX);
- alloc_free_block_lists (lists);
- return lists;
-}
-
-static void
-major_init_worker_thread (void *data)
-{
- MSBlockInfo ***lists = data;
- int i;
-
- g_assert (lists && lists != free_block_lists);
- for (i = 0; i < MS_BLOCK_TYPE_MAX; ++i) {
- int j;
- for (j = 0; j < num_block_obj_sizes; ++j)
- g_assert (!lists [i][j]);
- }
-
-#ifdef HAVE_KW_THREAD
- workers_free_block_lists = data;
-#else
- mono_native_tls_set_value (workers_free_block_lists_key, data);
-#endif
-}
-
-static void
-major_reset_worker_data (void *data)
-{
- MSBlockInfo ***lists = data;
- int i;
- for (i = 0; i < MS_BLOCK_TYPE_MAX; ++i) {
- int j;
- for (j = 0; j < num_block_obj_sizes; ++j)
- lists [i][j] = NULL;
- }
-}
-#endif
-
#undef pthread_create
static void
@@ -2500,29 +2011,12 @@ post_param_init (SgenMajorCollector *collector)
static void
sgen_marksweep_init_internal (SgenMajorCollector *collector, gboolean is_concurrent)
#else // SGEN_HAVE_CONCURRENT_MARK
-#ifdef SGEN_PARALLEL_MARK
-#ifdef FIXED_HEAP
-void
-sgen_marksweep_fixed_par_init (SgenMajorCollector *collector)
-#else // FIXED_HEAP
-void
-sgen_marksweep_par_init (SgenMajorCollector *collector)
-#endif // FIXED_HEAP
-#else // SGEN_PARALLEL_MARK
-#ifdef FIXED_HEAP
-void
-sgen_marksweep_fixed_init (SgenMajorCollector *collector)
-#else // FIXED_HEAP
#error unknown configuration
-#endif // FIXED_HEAP
-#endif // SGEN_PARALLEL_MARK
#endif // SGEN_HAVE_CONCURRENT_MARK
{
int i;
-#ifndef FIXED_HEAP
sgen_register_fixed_internal_mem_type (INTERNAL_MEM_MS_BLOCK_INFO, sizeof (MSBlockInfo));
-#endif
num_block_obj_sizes = ms_calculate_block_obj_sizes (MS_BLOCK_OBJ_SIZE_FACTOR, NULL);
block_obj_sizes = sgen_alloc_internal_dynamic (sizeof (int) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES, TRUE);
@@ -2548,10 +2042,6 @@ sgen_marksweep_fixed_init (SgenMajorCollector *collector)
for (i = 0; i < MS_NUM_FAST_BLOCK_OBJ_SIZE_INDEXES * 8; ++i)
g_assert (MS_BLOCK_OBJ_SIZE_INDEX (i) == ms_find_block_obj_size_index (i));
-#ifdef SGEN_PARALLEL_MARK
- LOCK_INIT (ms_block_list_mutex);
-#endif
-
mono_counters_register ("# major blocks allocated", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_blocks_alloced);
mono_counters_register ("# major blocks freed", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_blocks_freed);
mono_counters_register ("# major blocks lazy swept", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_blocks_lazy_swept);
@@ -2563,33 +2053,20 @@ sgen_marksweep_fixed_init (SgenMajorCollector *collector)
mono_counters_register ("# major blocks allocated less ideally", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_major_blocks_alloced_less_ideal);
#endif
-#ifdef SGEN_PARALLEL_MARK
-#ifndef HAVE_KW_THREAD
- mono_native_tls_alloc (&workers_free_block_lists_key, NULL);
-#endif
-#endif
-
collector->section_size = MAJOR_SECTION_SIZE;
-#ifdef SGEN_PARALLEL_MARK
- collector->is_parallel = TRUE;
- collector->alloc_worker_data = major_alloc_worker_data;
- collector->init_worker_thread = major_init_worker_thread;
- collector->reset_worker_data = major_reset_worker_data;
-#else
- collector->is_parallel = FALSE;
-#endif
+
#ifdef SGEN_HAVE_CONCURRENT_MARK
concurrent_mark = is_concurrent;
if (is_concurrent) {
collector->is_concurrent = TRUE;
collector->want_synchronous_collection = &want_evacuation;
- collector->get_and_reset_num_major_objects_marked = major_get_and_reset_num_major_objects_marked;
} else
#endif
{
collector->is_concurrent = FALSE;
collector->want_synchronous_collection = NULL;
}
+ collector->get_and_reset_num_major_objects_marked = major_get_and_reset_num_major_objects_marked;
collector->supports_cardtable = TRUE;
collector->have_swept = &have_swept;
@@ -2600,9 +2077,6 @@ sgen_marksweep_fixed_init (SgenMajorCollector *collector)
collector->alloc_degraded = major_alloc_degraded;
collector->alloc_object = major_alloc_object;
-#ifdef SGEN_PARALLEL_MARK
- collector->par_alloc_object = major_par_alloc_object;
-#endif
collector->free_pinned_object = free_pinned_object;
collector->iterate_objects = major_iterate_objects;
collector->free_non_pinned_object = major_free_non_pinned_object;
diff --git a/mono/metadata/sgen-memory-governor.c b/mono/metadata/sgen-memory-governor.c
index 448ebef3f05..5d17a0d721c 100644
--- a/mono/metadata/sgen-memory-governor.c
+++ b/mono/metadata/sgen-memory-governor.c
@@ -48,6 +48,7 @@ static double save_target_ratio = SGEN_DEFAULT_SAVE_TARGET_RATIO;
/**/
static mword allocated_heap;
static mword total_alloc = 0;
+static mword total_alloc_max = 0;
/* GC triggers. */
@@ -72,21 +73,13 @@ static mword last_collection_los_memory_alloced;
static mword sgen_memgov_available_free_space (void);
-static mword
-double_to_mword_with_saturation (double value)
-{
- if (value >= (double)MWORD_MAX_VALUE)
- return MWORD_MAX_VALUE;
- return (mword)value;
-}
-
/* GC trigger heuristics. */
static void
sgen_memgov_try_calculate_minor_collection_allowance (gboolean overwrite)
{
- size_t num_major_sections, num_major_sections_saved;
- mword los_memory_saved, new_major, new_heap_size, save_target, allowance_target;
+ size_t num_major_sections;
+ mword new_major, new_heap_size, allowance_target;
if (overwrite)
g_assert (need_calculate_minor_collection_allowance);
@@ -102,32 +95,16 @@ sgen_memgov_try_calculate_minor_collection_allowance (gboolean overwrite)
num_major_sections = major_collector.get_num_major_sections ();
- num_major_sections_saved = MAX (last_collection_old_num_major_sections - num_major_sections, 0);
- los_memory_saved = MAX (last_collection_old_los_memory_usage - last_collection_los_memory_usage, 1);
-
new_major = num_major_sections * major_collector.section_size;
new_heap_size = new_major + last_collection_los_memory_usage;
- save_target = (mword)((new_major + last_collection_los_memory_usage) * SGEN_DEFAULT_SAVE_TARGET_RATIO);
-
/*
- * We aim to allow the allocation of as many sections as is
- * necessary to reclaim save_target sections in the next
- * collection. We assume the collection pattern won't change.
- * In the last cycle, we had num_major_sections_saved for
- * minor_collection_sections_alloced. Assuming things won't
- * change, this must be the same ratio as save_target for
- * allowance_target, i.e.
- *
- * num_major_sections_saved save_target
- * --------------------------------- == ----------------
- * minor_collection_sections_alloced allowance_target
- *
- * hence:
+ * We allow the heap to grow by one third its current size before we start the next
+ * major collection.
*/
- allowance_target = double_to_mword_with_saturation ((double)save_target * (double)(minor_collection_sections_alloced * major_collector.section_size + last_collection_los_memory_alloced) / (double)(num_major_sections_saved * major_collector.section_size + los_memory_saved));
+ allowance_target = new_heap_size / 3;
- minor_collection_allowance = MAX (MIN (allowance_target, num_major_sections * major_collector.section_size + los_memory_usage), MIN_MINOR_COLLECTION_ALLOWANCE);
+ minor_collection_allowance = MAX (allowance_target, MIN_MINOR_COLLECTION_ALLOWANCE);
if (new_heap_size + minor_collection_allowance > soft_heap_limit) {
if (new_heap_size > soft_heap_limit)
@@ -311,6 +288,7 @@ sgen_alloc_os_memory (size_t size, SgenAllocFlags flags, const char *assert_desc
SGEN_ATOMIC_ADD_P (total_alloc, size);
if (flags & SGEN_ALLOC_HEAP)
MONO_GC_HEAP_ALLOC ((mword)ptr, size);
+ total_alloc_max = MAX (total_alloc_max, total_alloc);
}
return ptr;
}
@@ -329,6 +307,7 @@ sgen_alloc_os_memory_aligned (size_t size, mword alignment, SgenAllocFlags flags
SGEN_ATOMIC_ADD_P (total_alloc, size);
if (flags & SGEN_ALLOC_HEAP)
MONO_GC_HEAP_ALLOC ((mword)ptr, size);
+ total_alloc_max = MAX (total_alloc_max, total_alloc);
}
return ptr;
}
@@ -345,6 +324,7 @@ sgen_free_os_memory (void *addr, size_t size, SgenAllocFlags flags)
SGEN_ATOMIC_ADD_P (total_alloc, -(gssize)size);
if (flags & SGEN_ALLOC_HEAP)
MONO_GC_HEAP_FREE ((mword)addr, size);
+ total_alloc_max = MAX (total_alloc_max, total_alloc);
}
int64_t
@@ -392,6 +372,9 @@ sgen_memgov_init (size_t max_heap, size_t soft_limit, gboolean debug_allowance,
debug_print_allowance = debug_allowance;
minor_collection_allowance = MIN_MINOR_COLLECTION_ALLOWANCE;
+ mono_counters_register ("Memgov alloc", MONO_COUNTER_GC | MONO_COUNTER_WORD | MONO_COUNTER_BYTES | MONO_COUNTER_VARIABLE, &total_alloc);
+ mono_counters_register ("Memgov max alloc", MONO_COUNTER_GC | MONO_COUNTER_WORD | MONO_COUNTER_BYTES | MONO_COUNTER_MONOTONIC, &total_alloc_max);
+
if (max_heap == 0)
return;
diff --git a/mono/metadata/sgen-minor-copy-object.h b/mono/metadata/sgen-minor-copy-object.h
index 782bbdf8de2..c18e49f16dd 100644
--- a/mono/metadata/sgen-minor-copy-object.h
+++ b/mono/metadata/sgen-minor-copy-object.h
@@ -21,10 +21,11 @@
#define collector_pin_object(obj, queue) sgen_pin_object (obj, queue);
#define COLLECTOR_SERIAL_ALLOC_FOR_PROMOTION alloc_for_promotion
-#define COLLECTOR_PARALLEL_ALLOC_FOR_PROMOTION par_alloc_for_promotion
extern long long stat_nursery_copy_object_failed_to_space; /* from sgen-gc.c */
+#include "mono/utils/mono-compiler.h"
+
#include "sgen-copy-object.h"
/*
@@ -47,11 +48,7 @@ extern long long stat_nursery_copy_object_failed_to_space; /* from sgen-gc.c */
* copy_object could be made into a macro once debugged (use inline for now).
*/
-#ifdef _MSC_VER
-static __forceinline void
-#else
-static inline void __attribute__((always_inline))
-#endif
+static MONO_ALWAYS_INLINE void
SERIAL_COPY_OBJECT (void **obj_slot, SgenGrayQueue *queue)
{
char *forwarded;
@@ -107,11 +104,7 @@ SERIAL_COPY_OBJECT (void **obj_slot, SgenGrayQueue *queue)
*
* Similar to SERIAL_COPY_OBJECT, but assumes that OBJ_SLOT is part of an object, so it handles global remsets as well.
*/
-#ifdef _MSC_VER
-static __forceinline void
-#else
-static inline void __attribute__((always_inline))
-#endif
+static MONO_ALWAYS_INLINE void
SERIAL_COPY_OBJECT_FROM_OBJ (void **obj_slot, SgenGrayQueue *queue)
{
char *forwarded;
@@ -217,88 +210,6 @@ SERIAL_COPY_OBJECT_FROM_OBJ (void **obj_slot, SgenGrayQueue *queue)
#endif
}
-static void
-PARALLEL_COPY_OBJECT (void **obj_slot, SgenGrayQueue *queue)
-{
- char *obj = *obj_slot;
- mword vtable_word, objsize;
- MonoVTable *vt;
- void *destination;
- gboolean has_references;
-
- SGEN_ASSERT (9, current_collection_generation == GENERATION_NURSERY, "calling minor-par-copy from a %d generation collection", current_collection_generation);
-
- HEAVY_STAT (++stat_copy_object_called_nursery);
-
- if (!sgen_ptr_in_nursery (obj)) {
- HEAVY_STAT (++stat_nursery_copy_object_failed_from_space);
- return;
- }
-
- vtable_word = *(mword*)obj;
- vt = (MonoVTable*)(vtable_word & ~SGEN_VTABLE_BITS_MASK);
-
- /*
- * Before we can copy the object we must make sure that we are
- * allowed to, i.e. that the object not pinned, not already
- * forwarded and not in the nursery To Space.
- */
-
- if (vtable_word & SGEN_FORWARDED_BIT) {
- HEAVY_STAT (++stat_nursery_copy_object_failed_forwarded);
- *obj_slot = vt;
- return;
- }
- if (vtable_word & SGEN_PINNED_BIT) {
- HEAVY_STAT (++stat_nursery_copy_object_failed_pinned);
- return;
- }
-
- if (sgen_nursery_is_to_space (obj)) {
- HEAVY_STAT (++stat_nursery_copy_object_failed_to_space);
- return;
- }
-
- HEAVY_STAT (++stat_objects_copied_nursery);
-
- objsize = SGEN_ALIGN_UP (sgen_par_object_get_size (vt, (MonoObject*)obj));
- has_references = SGEN_VTABLE_HAS_REFERENCES (vt);
-
- destination = COLLECTOR_PARALLEL_ALLOC_FOR_PROMOTION (vt, obj, objsize, has_references);
-
- if (G_UNLIKELY (!destination)) {
- sgen_parallel_pin_or_update (obj_slot, obj, vt, queue);
- return;
- }
-
- *(MonoVTable**)destination = vt;
-
- if (SGEN_CAS_PTR ((void*)obj, (void*)((mword)destination | SGEN_FORWARDED_BIT), vt) == vt) {
- par_copy_object_no_checks (destination, vt, obj, objsize, has_references ? queue : NULL);
- obj = destination;
- *obj_slot = obj;
- } else {
- /* FIXME: unify with code in major_copy_or_mark_object() */
-
- /* FIXME: Give destination back to the allocator. */
- /*The major collector only needs the first word zeroed and nursery requires all bits to be. */
- if (!sgen_ptr_in_nursery (destination))
- *(void**)destination = NULL;
- else
- memset (destination, 0, objsize);
-
- vtable_word = *(mword*)obj;
- g_assert (vtable_word & SGEN_FORWARDED_BIT);
-
- obj = (void*)(vtable_word & ~SGEN_VTABLE_BITS_MASK);
-
- *obj_slot = obj;
-
- HEAVY_STAT (++stat_slots_allocated_in_vain);
- }
-}
-
#define FILL_MINOR_COLLECTOR_COPY_OBJECT(collector) do { \
(collector)->serial_ops.copy_or_mark_object = SERIAL_COPY_OBJECT; \
- (collector)->parallel_ops.copy_or_mark_object = PARALLEL_COPY_OBJECT; \
} while (0)
diff --git a/mono/metadata/sgen-minor-scan-object.h b/mono/metadata/sgen-minor-scan-object.h
index 7a34dfd4ac3..3cff269a7da 100644
--- a/mono/metadata/sgen-minor-scan-object.h
+++ b/mono/metadata/sgen-minor-scan-object.h
@@ -24,70 +24,15 @@ extern long long stat_scan_object_called_nursery;
#if defined(SGEN_SIMPLE_NURSERY)
#define SERIAL_SCAN_OBJECT simple_nursery_serial_scan_object
#define SERIAL_SCAN_VTYPE simple_nursery_serial_scan_vtype
-#define PARALLEL_SCAN_OBJECT simple_nursery_parallel_scan_object
-#define PARALLEL_SCAN_VTYPE simple_nursery_parallel_scan_vtype
#elif defined (SGEN_SPLIT_NURSERY)
#define SERIAL_SCAN_OBJECT split_nursery_serial_scan_object
#define SERIAL_SCAN_VTYPE split_nursery_serial_scan_vtype
-#define PARALLEL_SCAN_OBJECT split_nursery_parallel_scan_object
-#define PARALLEL_SCAN_VTYPE split_nursery_parallel_scan_vtype
#else
#error "Please define GC_CONF_NAME"
#endif
-#undef HANDLE_PTR
-#define HANDLE_PTR(ptr,obj) do { \
- void *__old = *(ptr); \
- void *__copy; \
- SGEN_OBJECT_LAYOUT_STATISTICS_MARK_BITMAP ((obj), (ptr)); \
- if (__old) { \
- PARALLEL_COPY_OBJECT ((ptr), queue); \
- __copy = *(ptr); \
- SGEN_COND_LOG (9, __old != __copy, "Overwrote field at %p with %p (was: %p)", (ptr), *(ptr), __old); \
- if (G_UNLIKELY (sgen_ptr_in_nursery (__copy) && !sgen_ptr_in_nursery ((ptr)))) \
- sgen_add_to_global_remset ((ptr), __copy); \
- } \
- } while (0)
-
-/*
- * Scan the object pointed to by @start for references to
- * other objects between @from_start and @from_end and copy
- * them to the gray_objects area.
- */
-static void
-PARALLEL_SCAN_OBJECT (char *start, SgenGrayQueue *queue)
-{
- SGEN_OBJECT_LAYOUT_STATISTICS_DECLARE_BITMAP;
-
-#define SCAN_OBJECT_PROTOCOL
-#include "sgen-scan-object.h"
-
- SGEN_OBJECT_LAYOUT_STATISTICS_COMMIT_BITMAP;
- HEAVY_STAT (++stat_scan_object_called_nursery);
-}
-
-/*
- * scan_vtype:
- *
- * Scan the valuetype pointed to by START, described by DESC for references to
- * other objects between @from_start and @from_end and copy them to the gray_objects area.
- * Returns a pointer to the end of the object.
- */
-static void
-PARALLEL_SCAN_VTYPE (char *start, mword desc, SgenGrayQueue *queue BINARY_PROTOCOL_ARG (size_t size))
-{
- SGEN_OBJECT_LAYOUT_STATISTICS_DECLARE_BITMAP;
-
- /* The descriptors include info about the MonoObject header as well */
- start -= sizeof (MonoObject);
-
-#define SCAN_OBJECT_NOVTABLE
-#define SCAN_OBJECT_PROTOCOL
-#include "sgen-scan-object.h"
-}
-
#undef HANDLE_PTR
/* Global remsets are handled in SERIAL_COPY_OBJECT_FROM_OBJ */
#define HANDLE_PTR(ptr,obj) do { \
@@ -100,10 +45,14 @@ PARALLEL_SCAN_VTYPE (char *start, mword desc, SgenGrayQueue *queue BINARY_PROTOC
} while (0)
static void
-SERIAL_SCAN_OBJECT (char *start, SgenGrayQueue *queue)
+SERIAL_SCAN_OBJECT (char *start, mword desc, SgenGrayQueue *queue)
{
SGEN_OBJECT_LAYOUT_STATISTICS_DECLARE_BITMAP;
+#ifdef HEAVY_STATISTICS
+ sgen_descriptor_count_scanned_object (desc);
+#endif
+
#define SCAN_OBJECT_PROTOCOL
#include "sgen-scan-object.h"
@@ -125,8 +74,6 @@ SERIAL_SCAN_VTYPE (char *start, mword desc, SgenGrayQueue *queue BINARY_PROTOCOL
}
#define FILL_MINOR_COLLECTOR_SCAN_OBJECT(collector) do { \
- (collector)->parallel_ops.scan_object = PARALLEL_SCAN_OBJECT; \
- (collector)->parallel_ops.scan_vtype = PARALLEL_SCAN_VTYPE; \
(collector)->serial_ops.scan_object = SERIAL_SCAN_OBJECT; \
(collector)->serial_ops.scan_vtype = SERIAL_SCAN_VTYPE; \
} while (0)
diff --git a/mono/metadata/sgen-new-bridge.c b/mono/metadata/sgen-new-bridge.c
index d07203db4d1..51b00e96695 100644
--- a/mono/metadata/sgen-new-bridge.c
+++ b/mono/metadata/sgen-new-bridge.c
@@ -652,6 +652,7 @@ dfs1 (HashEntry *obj_entry)
if (obj_entry) {
/* obj_entry needs to be expanded */
src = dyn_array_ptr_pop (&dfs_stack);
+
if (src)
g_assert (!src->v.dfs1.forwarded_to);
@@ -664,6 +665,7 @@ dfs1 (HashEntry *obj_entry)
if (!obj_entry->v.dfs1.is_visited) {
int num_links = 0;
+ mword desc = sgen_obj_get_descriptor (start);
obj_entry->v.dfs1.is_visited = 1;
diff --git a/mono/metadata/sgen-nursery-allocator.c b/mono/metadata/sgen-nursery-allocator.c
index 3d422e6b7b8..75297a7e1b1 100644
--- a/mono/metadata/sgen-nursery-allocator.c
+++ b/mono/metadata/sgen-nursery-allocator.c
@@ -71,6 +71,7 @@
#include "metadata/sgen-archdep.h"
#include "metadata/sgen-bridge.h"
#include "metadata/sgen-memory-governor.h"
+#include "metadata/sgen-pinning.h"
#include "metadata/mono-gc.h"
#include "metadata/method-builder.h"
#include "metadata/profiler-private.h"
@@ -747,12 +748,12 @@ fragment_list_reverse (SgenFragmentAllocator *allocator)
}
mword
-sgen_build_nursery_fragments (GCMemSection *nursery_section, void **start, size_t num_entries, SgenGrayQueue *unpin_queue)
+sgen_build_nursery_fragments (GCMemSection *nursery_section, SgenGrayQueue *unpin_queue)
{
char *frag_start, *frag_end;
size_t frag_size;
- size_t i = 0;
SgenFragment *frags_ranges;
+ void **pin_start, **pin_entry, **pin_end;
#ifdef NALLOC_DEBUG
reset_alloc_records ();
@@ -769,26 +770,30 @@ sgen_build_nursery_fragments (GCMemSection *nursery_section, void **start, size_
/* clear scan starts */
memset (nursery_section->scan_starts, 0, nursery_section->num_scan_start * sizeof (gpointer));
- while (i < num_entries || frags_ranges) {
+ pin_start = pin_entry = sgen_pinning_get_entry (nursery_section->pin_queue_first_entry);
+ pin_end = sgen_pinning_get_entry (nursery_section->pin_queue_last_entry);
+
+ while (pin_entry < pin_end || frags_ranges) {
char *addr0, *addr1;
size_t size;
SgenFragment *last_frag = NULL;
addr0 = addr1 = sgen_nursery_end;
- if (i < num_entries)
- addr0 = start [i];
+ if (pin_entry < pin_end)
+ addr0 = *pin_entry;
if (frags_ranges)
addr1 = frags_ranges->fragment_start;
if (addr0 < addr1) {
if (unpin_queue)
- GRAY_OBJECT_ENQUEUE (unpin_queue, addr0);
+ GRAY_OBJECT_ENQUEUE (unpin_queue, addr0, sgen_obj_get_descriptor_safe (addr0));
else
SGEN_UNPIN_OBJECT (addr0);
+ size = SGEN_ALIGN_UP (sgen_safe_object_get_size ((MonoObject*)addr0));
+ CANARIFY_SIZE (size);
sgen_set_nursery_scan_start (addr0);
frag_end = addr0;
- size = SGEN_ALIGN_UP (sgen_safe_object_get_size ((MonoObject*)addr0));
- ++i;
+ ++pin_entry;
} else {
frag_end = addr1;
size = frags_ranges->fragment_next - addr1;
@@ -808,7 +813,7 @@ sgen_build_nursery_fragments (GCMemSection *nursery_section, void **start, size_
frag_size = size;
#ifdef NALLOC_DEBUG
- add_alloc_record (start [i], frag_size, PINNING);
+ add_alloc_record (*pin_entry, frag_size, PINNING);
#endif
frag_start = frag_end + frag_size;
}
@@ -829,9 +834,10 @@ sgen_build_nursery_fragments (GCMemSection *nursery_section, void **start, size_
sgen_minor_collector.build_fragments_finish (&mutator_allocator);
if (!unmask (mutator_allocator.alloc_head)) {
- SGEN_LOG (1, "Nursery fully pinned (%zd)", num_entries);
- for (i = 0; i < num_entries; ++i) {
- SGEN_LOG (3, "Bastard pinning obj %p (%s), size: %zd", start [i], sgen_safe_name (start [i]), sgen_safe_object_get_size (start [i]));
+ SGEN_LOG (1, "Nursery fully pinned");
+ for (pin_entry = pin_start; pin_entry < pin_end; ++pin_entry) {
+ void *p = *pin_entry;
+ SGEN_LOG (3, "Bastard pinning obj %p (%s), size: %zd", p, sgen_safe_name (p), sgen_safe_object_get_size (p));
}
}
return fragment_total;
@@ -871,7 +877,7 @@ sgen_can_alloc_size (size_t size)
void*
sgen_nursery_alloc (size_t size)
{
- SGEN_ASSERT (1, size >= sizeof (MonoObject) && size <= SGEN_MAX_SMALL_OBJ_SIZE, "Invalid nursery object size");
+ SGEN_ASSERT (1, size >= sizeof (MonoObject) && size <= (SGEN_MAX_SMALL_OBJ_SIZE + CANARY_SIZE), "Invalid nursery object size");
SGEN_LOG (4, "Searching nursery for size: %zd", size);
size = SGEN_ALIGN_UP (size);
diff --git a/mono/metadata/sgen-old-bridge.c b/mono/metadata/sgen-old-bridge.c
index 42a588164df..4e2ba7b84d7 100644
--- a/mono/metadata/sgen-old-bridge.c
+++ b/mono/metadata/sgen-old-bridge.c
@@ -521,10 +521,12 @@ dfs1 (HashEntry *obj_entry)
obj_entry = dyn_array_ptr_pop (&dfs_stack);
if (obj_entry) {
+ mword desc;
src = dyn_array_ptr_pop (&dfs_stack);
obj = obj_entry->obj;
start = (char*)obj;
+ desc = sgen_obj_get_descriptor (start);
if (src) {
//g_print ("link %s -> %s\n", sgen_safe_name (src->obj), sgen_safe_name (obj));
diff --git a/mono/metadata/sgen-os-posix.c b/mono/metadata/sgen-os-posix.c
index 909b8382c81..55acf5137c3 100644
--- a/mono/metadata/sgen-os-posix.c
+++ b/mono/metadata/sgen-os-posix.c
@@ -56,17 +56,30 @@ suspend_thread (SgenThreadInfo *info, void *context)
#ifndef USE_MONO_CTX
gpointer regs [ARCH_NUM_REGS];
#endif
+ MonoContext ctx;
gpointer stack_start;
info->stopped_domain = mono_domain_get ();
- info->stopped_ip = context ? (gpointer) ARCH_SIGCTX_IP (context) : NULL;
info->signal = 0;
stop_count = sgen_global_stop_count;
/* duplicate signal */
if (0 && info->stop_count == stop_count)
return;
+#ifdef USE_MONO_CTX
+ if (context) {
+ mono_sigctx_to_monoctx (context, &ctx);
+ info->stopped_ip = MONO_CONTEXT_GET_IP (&ctx);
+ stack_start = MONO_CONTEXT_GET_SP (&ctx) - REDZONE_SIZE;
+ } else {
+ info->stopped_ip = NULL;
+ stack_start = NULL;
+ }
+#else
+ info->stopped_ip = context ? (gpointer) ARCH_SIGCTX_IP (context) : NULL;
stack_start = context ? (char*) ARCH_SIGCTX_SP (context) - REDZONE_SIZE : NULL;
+#endif
+
/* If stack_start is not within the limits, then don't set it
in info and we will be restarted. */
if (stack_start >= info->stack_start_limit && info->stack_start <= info->stack_end) {
@@ -74,7 +87,7 @@ suspend_thread (SgenThreadInfo *info, void *context)
#ifdef USE_MONO_CTX
if (context) {
- mono_sigctx_to_monoctx (context, &info->ctx);
+ memcpy (&info->ctx, &ctx, sizeof (MonoContext));
} else {
memset (&info->ctx, 0, sizeof (MonoContext));
}
@@ -122,7 +135,7 @@ suspend_thread (SgenThreadInfo *info, void *context)
}
/* LOCKING: assumes the GC lock is held (by the stopping thread) */
-MONO_SIGNAL_HANDLER_FUNC (static, suspend_handler, (int sig, siginfo_t *siginfo, void *context))
+MONO_SIG_HANDLER_FUNC (static, suspend_handler)
{
/*
* The suspend signal handler potentially uses syscalls that
@@ -131,19 +144,19 @@ MONO_SIGNAL_HANDLER_FUNC (static, suspend_handler, (int sig, siginfo_t *siginfo,
* must restore those to the values they had when we
* interrupted.
*/
-
SgenThreadInfo *info;
int old_errno = errno;
int hp_save_index = mono_hazard_pointer_save_for_signal_handler ();
+ MONO_SIG_HANDLER_GET_CONTEXT;
info = mono_thread_info_current ();
- suspend_thread (info, context);
+ suspend_thread (info, ctx);
mono_hazard_pointer_restore_for_signal_handler (hp_save_index);
errno = old_errno;
}
-MONO_SIGNAL_HANDLER_FUNC (static, restart_handler, (int sig))
+MONO_SIG_HANDLER_FUNC (static, restart_handler)
{
SgenThreadInfo *info;
int old_errno = errno;
diff --git a/mono/metadata/sgen-pinning.c b/mono/metadata/sgen-pinning.c
index 523c7737b14..c895d7471ea 100644
--- a/mono/metadata/sgen-pinning.c
+++ b/mono/metadata/sgen-pinning.c
@@ -25,10 +25,9 @@
#include "metadata/sgen-gc.h"
#include "metadata/sgen-pinning.h"
#include "metadata/sgen-protocol.h"
+#include "metadata/sgen-pointer-queue.h"
-static void** pin_queue;
-static size_t pin_queue_size = 0;
-static size_t next_pin_slot = 0;
+static SgenPointerQueue pin_queue;
static size_t last_num_pinned = 0;
#define PIN_HASH_SIZE 1024
@@ -43,20 +42,8 @@ sgen_init_pinning (void)
void
sgen_finish_pinning (void)
{
- last_num_pinned = next_pin_slot;
- next_pin_slot = 0;
-}
-
-static void
-realloc_pin_queue (void)
-{
- size_t new_size = pin_queue_size? pin_queue_size + pin_queue_size/2: 1024;
- void **new_pin = sgen_alloc_internal_dynamic (sizeof (void*) * new_size, INTERNAL_MEM_PIN_QUEUE, TRUE);
- memcpy (new_pin, pin_queue, sizeof (void*) * next_pin_slot);
- sgen_free_internal_dynamic (pin_queue, sizeof (void*) * pin_queue_size, INTERNAL_MEM_PIN_QUEUE);
- pin_queue = new_pin;
- pin_queue_size = new_size;
- SGEN_LOG (4, "Reallocated pin queue to size: %zd", new_size);
+ last_num_pinned = pin_queue.next_slot;
+ sgen_pointer_queue_clear (&pin_queue);
}
void
@@ -69,71 +56,92 @@ sgen_pin_stage_ptr (void *ptr)
pin_hash_filter [hash_idx] = ptr;
- if (next_pin_slot >= pin_queue_size)
- realloc_pin_queue ();
-
- pin_queue [next_pin_slot++] = ptr;
+ sgen_pointer_queue_add (&pin_queue, ptr);
}
-static size_t
-optimized_pin_queue_search (void *addr)
+gboolean
+sgen_find_optimized_pin_queue_area (void *start, void *end, size_t *first_out, size_t *last_out)
{
- size_t first = 0, last = next_pin_slot;
- while (first < last) {
- size_t middle = first + ((last - first) >> 1);
- if (addr <= pin_queue [middle])
- last = middle;
- else
- first = middle + 1;
- }
- g_assert (first == last);
- return first;
+ size_t first = sgen_pointer_queue_search (&pin_queue, start);
+ size_t last = sgen_pointer_queue_search (&pin_queue, end);
+ SGEN_ASSERT (0, last == pin_queue.next_slot || pin_queue.data [last] >= end, "Pin queue search gone awry");
+ *first_out = first;
+ *last_out = last;
+ return first != last;
}
void**
-sgen_find_optimized_pin_queue_area (void *start, void *end, size_t *num)
+sgen_pinning_get_entry (size_t index)
{
- size_t first, last;
- first = optimized_pin_queue_search (start);
- last = optimized_pin_queue_search (end);
- *num = last - first;
- if (first == last)
- return NULL;
- return pin_queue + first;
+ SGEN_ASSERT (0, index <= pin_queue.next_slot, "Pin queue entry out of range");
+ return &pin_queue.data [index];
}
void
sgen_find_section_pin_queue_start_end (GCMemSection *section)
{
SGEN_LOG (6, "Pinning from section %p (%p-%p)", section, section->data, section->end_data);
- section->pin_queue_start = sgen_find_optimized_pin_queue_area (section->data, section->end_data, §ion->pin_queue_num_entries);
- SGEN_LOG (6, "Found %zd pinning addresses in section %p", section->pin_queue_num_entries, section);
+
+ sgen_find_optimized_pin_queue_area (section->data, section->end_data,
+ §ion->pin_queue_first_entry, §ion->pin_queue_last_entry);
+
+ SGEN_LOG (6, "Found %zd pinning addresses in section %p",
+ section->pin_queue_last_entry - section->pin_queue_first_entry, section);
}
/*This will setup the given section for the while pin queue. */
void
sgen_pinning_setup_section (GCMemSection *section)
{
- section->pin_queue_start = pin_queue;
- section->pin_queue_num_entries = next_pin_slot;
+ section->pin_queue_first_entry = 0;
+ section->pin_queue_last_entry = pin_queue.next_slot;
}
void
sgen_pinning_trim_queue_to_section (GCMemSection *section)
{
- next_pin_slot = section->pin_queue_num_entries;
+ SGEN_ASSERT (0, section->pin_queue_first_entry == 0, "Pin queue trimming assumes the whole pin queue is used by the nursery");
+ pin_queue.next_slot = section->pin_queue_last_entry;
}
+/*
+ * This is called when we've run out of memory during a major collection.
+ *
+ * After collecting potential pin entries and sorting the array, this is what it looks like:
+ *
+ * +--------------------+---------------------------------------------+--------------------+
+ * | major heap entries | nursery entries | major heap entries |
+ * +--------------------+---------------------------------------------+--------------------+
+ *
+ * Of course there might not be major heap entries before and/or after the nursery entries,
+ * depending on where the major heap sections are in the address space, and whether there
+ * were any potential pointers there.
+ *
+ * When we pin nursery objects, we compact the nursery part of the pin array, which leaves
+ * discarded entries after the ones that actually pointed to nursery objects:
+ *
+ * +--------------------+-----------------+---------------------------+--------------------+
+ * | major heap entries | nursery entries | discarded nursery entries | major heap entries |
+ * +--------------------+-----------------+---------------------------+--------------------+
+ *
+ * When, due to being out of memory, we late pin more objects, the pin array looks like
+ * this:
+ *
+ * +--------------------+-----------------+---------------------------+--------------------+--------------+
+ * | major heap entries | nursery entries | discarded nursery entries | major heap entries | late entries |
+ * +--------------------+-----------------+---------------------------+--------------------+--------------+
+ *
+ * This function gets rid of the discarded nursery entries by nulling them out. Note that
+ * we can late pin objects not only in the nursery but also in the major heap, which happens
+ * when evacuation fails.
+ */
void
sgen_pin_queue_clear_discarded_entries (GCMemSection *section, size_t max_pin_slot)
{
- void **start = section->pin_queue_start + section->pin_queue_num_entries;
- void **end = pin_queue + max_pin_slot;
+ void **start = sgen_pinning_get_entry (section->pin_queue_last_entry);
+ void **end = sgen_pinning_get_entry (max_pin_slot);
void *addr;
- if (!start)
- return;
-
for (; start < end; ++start) {
addr = *start;
if ((char*)addr < section->data || (char*)addr > section->end_data)
@@ -144,30 +152,15 @@ sgen_pin_queue_clear_discarded_entries (GCMemSection *section, size_t max_pin_sl
/* reduce the info in the pin queue, removing duplicate pointers and sorting them */
void
-sgen_optimize_pin_queue (size_t start_slot)
+sgen_optimize_pin_queue (void)
{
- void **start, **cur, **end;
- /* sort and uniq pin_queue: we just sort and we let the rest discard multiple values */
- /* it may be better to keep ranges of pinned memory instead of individually pinning objects */
- SGEN_LOG (5, "Sorting pin queue, size: %zd", next_pin_slot);
- if ((next_pin_slot - start_slot) > 1)
- sgen_sort_addresses (pin_queue + start_slot, next_pin_slot - start_slot);
- start = cur = pin_queue + start_slot;
- end = pin_queue + next_pin_slot;
- while (cur < end) {
- *start = *cur++;
- while (*start == *cur && cur < end)
- cur++;
- start++;
- };
- next_pin_slot = start - pin_queue;
- SGEN_LOG (5, "Pin queue reduced to size: %zd", next_pin_slot);
+ sgen_pointer_queue_sort_uniq (&pin_queue);
}
size_t
sgen_get_pinned_count (void)
{
- return next_pin_slot;
+ return pin_queue.next_slot;
}
void
@@ -176,8 +169,9 @@ sgen_dump_pin_queue (void)
int i;
for (i = 0; i < last_num_pinned; ++i) {
- SGEN_LOG (3, "Bastard pinning obj %p (%s), size: %zd", pin_queue [i], sgen_safe_name (pin_queue [i]), sgen_safe_object_get_size (pin_queue [i]));
- }
+ void *ptr = pin_queue.data [i];
+ SGEN_LOG (3, "Bastard pinning obj %p (%s), size: %zd", ptr, sgen_safe_name (ptr), sgen_safe_object_get_size (ptr));
+ }
}
typedef struct _CementHashEntry CementHashEntry;
@@ -311,7 +305,7 @@ sgen_cement_lookup_or_register (char *obj)
}
void
-sgen_cement_iterate (IterateObjectCallbackFunc callback, void *callback_data)
+sgen_pin_cemented_objects (void)
{
int i;
for (i = 0; i < SGEN_CEMENT_HASH_SIZE; ++i) {
@@ -320,7 +314,8 @@ sgen_cement_iterate (IterateObjectCallbackFunc callback, void *callback_data)
SGEN_ASSERT (5, cement_hash [i].count >= SGEN_CEMENT_THRESHOLD, "Cementing hash inconsistent");
- callback (cement_hash [i].obj, 0, callback_data);
+ sgen_pin_stage_ptr (cement_hash [i].obj);
+ /* FIXME: do pin stats if enabled */
}
}
diff --git a/mono/metadata/sgen-pinning.h b/mono/metadata/sgen-pinning.h
index ef41df24d2f..9a2dcbb2c57 100644
--- a/mono/metadata/sgen-pinning.h
+++ b/mono/metadata/sgen-pinning.h
@@ -28,7 +28,7 @@ enum {
};
void sgen_pin_stage_ptr (void *ptr) MONO_INTERNAL;
-void sgen_optimize_pin_queue (size_t start_slot) MONO_INTERNAL;
+void sgen_optimize_pin_queue (void) MONO_INTERNAL;
void sgen_init_pinning (void) MONO_INTERNAL;
void sgen_finish_pinning (void) MONO_INTERNAL;
void sgen_pin_queue_clear_discarded_entries (GCMemSection *section, size_t max_pin_slot) MONO_INTERNAL;
@@ -38,6 +38,11 @@ void sgen_pinning_trim_queue_to_section (GCMemSection *section) MONO_INTERNAL;
void sgen_dump_pin_queue (void) MONO_INTERNAL;
+gboolean sgen_find_optimized_pin_queue_area (void *start, void *end, size_t *first_out, size_t *last_out) MONO_INTERNAL;
+void sgen_find_section_pin_queue_start_end (GCMemSection *section) MONO_INTERNAL;
+void** sgen_pinning_get_entry (size_t index) MONO_INTERNAL;
+void sgen_pin_objects_in_section (GCMemSection *section, ScanCopyContext ctx) MONO_INTERNAL;
+
/* Pinning stats */
void sgen_pin_stats_register_address (char *addr, int pin_type) MONO_INTERNAL;
@@ -53,7 +58,7 @@ void sgen_cement_concurrent_start (void) MONO_INTERNAL;
void sgen_cement_concurrent_finish (void) MONO_INTERNAL;
gboolean sgen_cement_lookup (char *obj) MONO_INTERNAL;
gboolean sgen_cement_lookup_or_register (char *obj) MONO_INTERNAL;
-void sgen_cement_iterate (IterateObjectCallbackFunc callback, void *callback_data) MONO_INTERNAL;
+void sgen_pin_cemented_objects (void) MONO_INTERNAL;
void sgen_cement_clear_below_threshold (void) MONO_INTERNAL;
#endif
diff --git a/mono/metadata/sgen-pointer-queue.c b/mono/metadata/sgen-pointer-queue.c
index fe491605d52..3c1d8fb6c61 100644
--- a/mono/metadata/sgen-pointer-queue.c
+++ b/mono/metadata/sgen-pointer-queue.c
@@ -64,6 +64,27 @@ sgen_pointer_queue_search (SgenPointerQueue *queue, void *addr)
return first;
}
+/*
+ * Removes all NULL pointers from the queue.
+ */
+void
+sgen_pointer_queue_remove_nulls (SgenPointerQueue *queue)
+{
+ void **start, **cur, **end;
+ start = cur = queue->data;
+ end = queue->data + queue->next_slot;
+ while (cur < end) {
+ if (*cur)
+ *start++ = *cur++;
+ else
+ ++cur;
+ }
+ queue->next_slot = start - queue->data;
+}
+
+/*
+ * Sorts the pointers in the queue, then removes duplicates.
+ */
void
sgen_pointer_queue_sort_uniq (SgenPointerQueue *queue)
{
@@ -77,7 +98,7 @@ sgen_pointer_queue_sort_uniq (SgenPointerQueue *queue)
end = queue->data + queue->next_slot;
while (cur < end) {
*start = *cur++;
- while (*start == *cur && cur < end)
+ while (cur < end && *start == *cur)
cur++;
start++;
};
@@ -85,4 +106,18 @@ sgen_pointer_queue_sort_uniq (SgenPointerQueue *queue)
SGEN_LOG (5, "Pointer queue reduced to size: %lu", queue->next_slot);
}
+/*
+ * Does a linear search through the pointer queue to find `ptr`. Returns the index if
+ * found, otherwise (size_t)-1.
+ */
+size_t
+sgen_pointer_queue_find (SgenPointerQueue *queue, void *ptr)
+{
+ size_t i;
+ for (i = 0; i < queue->next_slot; ++i)
+ if (queue->data [i] == ptr)
+ return i;
+ return (size_t)-1;
+}
+
#endif
diff --git a/mono/metadata/sgen-pointer-queue.h b/mono/metadata/sgen-pointer-queue.h
index 031870f1285..d972f3cc92e 100644
--- a/mono/metadata/sgen-pointer-queue.h
+++ b/mono/metadata/sgen-pointer-queue.h
@@ -28,7 +28,9 @@ typedef struct {
void sgen_pointer_queue_add (SgenPointerQueue *queue, void *ptr) MONO_INTERNAL;
void sgen_pointer_queue_clear (SgenPointerQueue *queue) MONO_INTERNAL;
+void sgen_pointer_queue_remove_nulls (SgenPointerQueue *queue) MONO_INTERNAL;
void sgen_pointer_queue_sort_uniq (SgenPointerQueue *queue) MONO_INTERNAL;
size_t sgen_pointer_queue_search (SgenPointerQueue *queue, void *addr) MONO_INTERNAL;
+size_t sgen_pointer_queue_find (SgenPointerQueue *queue, void *ptr) MONO_INTERNAL;
#endif
diff --git a/mono/metadata/sgen-scan-object.h b/mono/metadata/sgen-scan-object.h
index 7cbe57a6c83..ad569dda359 100644
--- a/mono/metadata/sgen-scan-object.h
+++ b/mono/metadata/sgen-scan-object.h
@@ -23,7 +23,12 @@
* object must be given in the variable "char* start". Afterwards,
* "start" will point to the start of the next object, if the scanned
* object contained references. If not, the value of "start" should
- * be considered undefined after executing this code.
+ * be considered undefined after executing this code. The object's
+ * GC descriptor must be in the variable "mword desc".
+ *
+ * The macro `HANDLE_PTR` will be invoked for every reference encountered while scanning the
+ * object. It is called with two parameters: The pointer to the reference (not the
+ * reference itself!) as well as the pointer to the scanned object.
*
* Modifiers (automatically undefined):
*
@@ -40,17 +45,8 @@
{
#ifndef SCAN_OBJECT_NOVTABLE
- GCVTable *vt;
- mword desc;
-
- vt = (GCVTable*)SGEN_LOAD_VTABLE (start);
- //type = vt->desc & 0x7;
-
- /* gcc should be smart enough to remove the bounds check, but it isn't:( */
- desc = vt->desc;
-
#if defined(SGEN_HEAVY_BINARY_PROTOCOL) && defined(SCAN_OBJECT_PROTOCOL)
- binary_protocol_scan_begin (start, vt, sgen_safe_object_get_size ((MonoObject*)start));
+ binary_protocol_scan_begin (start, SGEN_LOAD_VTABLE (start), sgen_safe_object_get_size ((MonoObject*)start));
#endif
#else
#if defined(SGEN_HEAVY_BINARY_PROTOCOL) && defined(SCAN_OBJECT_PROTOCOL)
@@ -97,7 +93,7 @@
#ifndef SCAN_OBJECT_NOVTABLE
case DESC_TYPE_COMPLEX_ARR:
/* this is an array of complex structs */
-#define SCAN OBJ_COMPLEX_ARR_FOREACH_PTR (vt, start)
+#define SCAN OBJ_COMPLEX_ARR_FOREACH_PTR (desc, start)
#ifndef SCAN_OBJECT_NOSCAN
SCAN;
#endif
diff --git a/mono/metadata/sgen-simple-nursery.c b/mono/metadata/sgen-simple-nursery.c
index f2f7066c301..2cfb9d3211c 100644
--- a/mono/metadata/sgen-simple-nursery.c
+++ b/mono/metadata/sgen-simple-nursery.c
@@ -35,12 +35,6 @@ alloc_for_promotion (MonoVTable *vtable, char *obj, size_t objsize, gboolean has
return major_collector.alloc_object (vtable, objsize, has_references);
}
-static inline char*
-par_alloc_for_promotion (MonoVTable *vtable, char *obj, size_t objsize, gboolean has_references)
-{
- return major_collector.par_alloc_object (vtable, objsize, has_references);
-}
-
static SgenFragment*
build_fragments_get_exclude_head (void)
{
@@ -79,7 +73,6 @@ init_nursery (SgenFragmentAllocator *allocator, char *start, char *end)
#define SGEN_SIMPLE_NURSERY
#define SERIAL_COPY_OBJECT simple_nursery_serial_copy_object
-#define PARALLEL_COPY_OBJECT simple_nursery_parallel_copy_object
#define SERIAL_COPY_OBJECT_FROM_OBJ simple_nursery_serial_copy_object_from_obj
#include "sgen-minor-copy-object.h"
@@ -91,7 +84,6 @@ sgen_simple_nursery_init (SgenMinorCollector *collector)
collector->is_split = FALSE;
collector->alloc_for_promotion = alloc_for_promotion;
- collector->par_alloc_for_promotion = par_alloc_for_promotion;
collector->prepare_to_space = prepare_to_space;
collector->clear_fragments = clear_fragments;
diff --git a/mono/metadata/sgen-split-nursery.c b/mono/metadata/sgen-split-nursery.c
index 1f62d14b703..87cc412c672 100644
--- a/mono/metadata/sgen-split-nursery.c
+++ b/mono/metadata/sgen-split-nursery.c
@@ -145,8 +145,6 @@ static AgeAllocationBuffer age_alloc_buffers [MAX_AGE];
/* The collector allocs from here. */
static SgenFragmentAllocator collector_allocator;
-static LOCK_DECLARE (par_alloc_buffer_refill_mutex);
-
static inline int
get_object_age (char *object)
{
@@ -292,82 +290,6 @@ alloc_for_promotion (MonoVTable *vtable, char *obj, size_t objsize, gboolean has
return p;
}
-static char*
-par_alloc_for_promotion_slow_path (int age, size_t objsize)
-{
- char *p;
- size_t allocated_size;
- size_t aligned_objsize = (size_t)align_up (objsize, SGEN_TO_SPACE_GRANULE_BITS);
-
- mono_mutex_lock (&par_alloc_buffer_refill_mutex);
-
-restart:
- p = age_alloc_buffers [age].next;
- if (G_LIKELY (p + objsize <= age_alloc_buffers [age].end)) {
- if (SGEN_CAS_PTR ((void*)&age_alloc_buffers [age].next, p + objsize, p) != p)
- goto restart;
- } else {
- /* Reclaim remaining space - if we OOMd the nursery nothing to see here. */
- char *end = age_alloc_buffers [age].end;
- if (end) {
- do {
- p = age_alloc_buffers [age].next;
- } while (SGEN_CAS_PTR ((void*)&age_alloc_buffers [age].next, end, p) != p);
- sgen_clear_range (p, end);
- }
-
- /* By setting end to NULL we make sure no other thread can advance while we're updating.*/
- age_alloc_buffers [age].end = NULL;
- STORE_STORE_FENCE;
-
- p = sgen_fragment_allocator_par_range_alloc (
- &collector_allocator,
- MAX (aligned_objsize, AGE_ALLOC_BUFFER_DESIRED_SIZE),
- MAX (aligned_objsize, AGE_ALLOC_BUFFER_MIN_SIZE),
- &allocated_size);
- if (p) {
- set_age_in_range (p, p + allocated_size, age);
- age_alloc_buffers [age].next = p + objsize;
- STORE_STORE_FENCE; /* Next must arrive before the new value for next. */
- age_alloc_buffers [age].end = p + allocated_size;
- }
- }
-
- mono_mutex_unlock (&par_alloc_buffer_refill_mutex);
- return p;
-}
-
-static inline char*
-par_alloc_for_promotion (MonoVTable *vtable, char *obj, size_t objsize, gboolean has_references)
-{
- char *p;
- int age;
-
- age = get_object_age (obj);
- if (age >= promote_age)
- return major_collector.par_alloc_object (vtable, objsize, has_references);
-
-restart:
- p = age_alloc_buffers [age].next;
-
- LOAD_LOAD_FENCE; /* The read of ->next must happen before ->end */
-
- if (G_LIKELY (p + objsize <= age_alloc_buffers [age].end)) {
- if (SGEN_CAS_PTR ((void*)&age_alloc_buffers [age].next, p + objsize, p) != p)
- goto restart;
- } else {
- p = par_alloc_for_promotion_slow_path (age, objsize);
-
- /* Have we failed to promote to the nursery, lets just evacuate it to old gen. */
- if (!p)
- return major_collector.par_alloc_object (vtable, objsize, has_references);
- }
-
- *(MonoVTable**)p = vtable;
-
- return p;
-}
-
static char*
minor_alloc_for_promotion (MonoVTable *vtable, char *obj, size_t objsize, gboolean has_references)
{
@@ -380,18 +302,6 @@ minor_alloc_for_promotion (MonoVTable *vtable, char *obj, size_t objsize, gboole
return alloc_for_promotion (vtable, obj, objsize, has_references);
}
-static char*
-minor_par_alloc_for_promotion (MonoVTable *vtable, char *obj, size_t objsize, gboolean has_references)
-{
- /*
- We only need to check for a non-nursery object if we're doing a major collection.
- */
- if (!sgen_ptr_in_nursery (obj))
- return major_collector.par_alloc_object (vtable, objsize, has_references);
-
- return par_alloc_for_promotion (vtable, obj, objsize, has_references);
-}
-
static SgenFragment*
build_fragments_get_exclude_head (void)
{
@@ -522,7 +432,6 @@ print_gc_param_usage (void)
#define SGEN_SPLIT_NURSERY
#define SERIAL_COPY_OBJECT split_nursery_serial_copy_object
-#define PARALLEL_COPY_OBJECT split_nursery_parallel_copy_object
#define SERIAL_COPY_OBJECT_FROM_OBJ split_nursery_serial_copy_object_from_obj
#include "sgen-minor-copy-object.h"
@@ -534,7 +443,6 @@ sgen_split_nursery_init (SgenMinorCollector *collector)
collector->is_split = TRUE;
collector->alloc_for_promotion = minor_alloc_for_promotion;
- collector->par_alloc_for_promotion = minor_par_alloc_for_promotion;
collector->prepare_to_space = prepare_to_space;
collector->clear_fragments = clear_fragments;
@@ -547,7 +455,6 @@ sgen_split_nursery_init (SgenMinorCollector *collector)
FILL_MINOR_COLLECTOR_COPY_OBJECT (collector);
FILL_MINOR_COLLECTOR_SCAN_OBJECT (collector);
- LOCK_INIT (par_alloc_buffer_refill_mutex);
}
diff --git a/mono/metadata/sgen-stw.c b/mono/metadata/sgen-stw.c
index 5a2ab0e9687..2a9bf34788c 100644
--- a/mono/metadata/sgen-stw.c
+++ b/mono/metadata/sgen-stw.c
@@ -52,7 +52,7 @@ align_pointer (void *ptr)
#ifdef USE_MONO_CTX
static MonoContext cur_thread_ctx;
#else
-static mword cur_thread_regs [ARCH_NUM_REGS] = {0};
+static mword cur_thread_regs [ARCH_NUM_REGS];
#endif
static void
diff --git a/mono/metadata/sgen-tagged-pointer.h b/mono/metadata/sgen-tagged-pointer.h
new file mode 100644
index 00000000000..fc065f7f96b
--- /dev/null
+++ b/mono/metadata/sgen-tagged-pointer.h
@@ -0,0 +1,34 @@
+/*
+ * sgen-tagged-pointer.h: Macros for tagging and untagging pointers.
+ *
+ * Copyright (C) 2014 Xamarin Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License 2.0 as published by the Free Software Foundation;
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License 2.0 along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MONO_SGEN_TAGGED_POINTER_H__
+#define __MONO_SGEN_TAGGED_POINTER_H__
+
+#define SGEN_POINTER_IS_TAGGED_1(p) ((mword)(p) & 1)
+#define SGEN_POINTER_TAG_1(p) ((void*)((mword)(p) | 1))
+#define SGEN_POINTER_UNTAG_1(p) ((void*)((mword)(p) & ~1))
+
+#define SGEN_POINTER_IS_TAGGED_2(p) ((mword)(p) & 2)
+#define SGEN_POINTER_TAG_2(p) ((void*)((mword)(p) | 2))
+#define SGEN_POINTER_UNTAG_2(p) ((void*)((mword)(p) & ~2))
+
+#define SGEN_POINTER_IS_TAGGED_1_OR_2(p) ((mword)(p) & 3)
+#define SGEN_POINTER_UNTAG_12(p) ((void*)((mword)(p) & ~3))
+
+#endif
diff --git a/mono/metadata/sgen-tarjan-bridge.c b/mono/metadata/sgen-tarjan-bridge.c
index 59013f70124..5c6525e9ec7 100644
--- a/mono/metadata/sgen-tarjan-bridge.c
+++ b/mono/metadata/sgen-tarjan-bridge.c
@@ -661,6 +661,7 @@ push_all (ScanData *data)
{
MonoObject *obj = data->obj;
char *start = (char*)obj;
+ mword desc = sgen_obj_get_descriptor (start);
#if DUMP_GRAPH
printf ("**scanning %p %s\n", obj, safe_name_bridge (obj));
@@ -712,6 +713,7 @@ compute_low (ScanData *data)
{
MonoObject *obj = data->obj;
char *start = (char*)obj;
+ mword desc = sgen_obj_get_descriptor (start);
#include "sgen-scan-object.h"
}
diff --git a/mono/metadata/sgen-workers.c b/mono/metadata/sgen-workers.c
index b3eebb02d9c..2d48745762b 100644
--- a/mono/metadata/sgen-workers.c
+++ b/mono/metadata/sgen-workers.c
@@ -140,7 +140,7 @@ workers_wait (void)
static gboolean
collection_needs_workers (void)
{
- return sgen_collection_is_parallel () || sgen_collection_is_concurrent ();
+ return sgen_collection_is_concurrent ();
}
void
@@ -243,9 +243,9 @@ workers_steal (WorkerData *data, WorkerData *victim_data, gboolean lock)
n -= m;
sgen_gray_object_alloc_queue_section (queue);
- memcpy (queue->first->objects,
+ memcpy (queue->first->entries,
victim_data->stealable_stack + victim_data->stealable_stack_fill - num + n,
- sizeof (char*) * m);
+ sizeof (GrayQueueEntry) * m);
queue->first->size = m;
/*
@@ -253,10 +253,10 @@ workers_steal (WorkerData *data, WorkerData *victim_data, gboolean lock)
* Doing so trigger "assert not reached" in sgen-scan-object.h : we use the queue->cursor
* to compute the size of the first section during section allocation (via alloc_prepare_func
* -> workers_gray_queue_share_redirect -> sgen_gray_object_dequeue_section) which will be then
- * set to 0, because queue->cursor is still pointing to queue->first->objects [-1], thus
+ * set to 0, because queue->cursor is still pointing to queue->first->entries [-1], thus
* losing objects in the gray queue.
*/
- queue->cursor = (char**)queue->first->objects + queue->first->size - 1;
+ queue->cursor = queue->first->entries + queue->first->size - 1;
}
victim_data->stealable_stack_fill -= num;
@@ -301,7 +301,7 @@ workers_get_work (WorkerData *data)
* distribute gray queue.
*/
major = sgen_get_major_collector ();
- if (major->is_concurrent || major->is_parallel) {
+ if (major->is_concurrent) {
GrayQueueSection *section = sgen_section_gray_queue_dequeue (&workers_distribute_gray_queue);
if (section) {
sgen_gray_object_enqueue_section (&data->private_gray_queue, section);
@@ -338,8 +338,8 @@ workers_gray_queue_share_redirect (SgenGrayQueue *queue)
int num = MIN (section->size, STEALABLE_STACK_SIZE - data->stealable_stack_fill);
memcpy (data->stealable_stack + data->stealable_stack_fill,
- section->objects + section->size - num,
- sizeof (char*) * num);
+ section->entries + section->size - num,
+ sizeof (GrayQueueEntry) * num);
section->size -= num;
data->stealable_stack_fill += num;
@@ -441,7 +441,7 @@ sgen_workers_init_distribute_gray_queue (void)
if (!collection_needs_workers ())
return;
- init_distribute_gray_queue (sgen_get_major_collector ()->is_concurrent || sgen_get_major_collector ()->is_parallel);
+ init_distribute_gray_queue (sgen_get_major_collector ()->is_concurrent);
}
void
@@ -449,7 +449,7 @@ sgen_workers_init (int num_workers)
{
int i;
- if (!sgen_get_major_collector ()->is_parallel && !sgen_get_major_collector ()->is_concurrent)
+ if (!sgen_get_major_collector ()->is_concurrent)
return;
//g_print ("initing %d workers\n", num_workers);
@@ -462,7 +462,7 @@ sgen_workers_init (int num_workers)
MONO_SEM_INIT (&workers_waiting_sem, 0);
MONO_SEM_INIT (&workers_done_sem, 0);
- init_distribute_gray_queue (sgen_get_major_collector ()->is_concurrent || sgen_get_major_collector ()->is_parallel);
+ init_distribute_gray_queue (sgen_get_major_collector ()->is_concurrent);
if (sgen_get_major_collector ()->alloc_worker_data)
workers_gc_thread_major_collector_data = sgen_get_major_collector ()->alloc_worker_data ();
diff --git a/mono/metadata/sgen-workers.h b/mono/metadata/sgen-workers.h
index 9070623673f..d13c4609674 100644
--- a/mono/metadata/sgen-workers.h
+++ b/mono/metadata/sgen-workers.h
@@ -34,7 +34,7 @@ struct _WorkerData {
mono_mutex_t stealable_stack_mutex;
volatile int stealable_stack_fill;
- char *stealable_stack [STEALABLE_STACK_SIZE];
+ GrayQueueEntry stealable_stack [STEALABLE_STACK_SIZE];
};
typedef void (*JobFunc) (WorkerData *worker_data, void *job_data);
diff --git a/mono/metadata/socket-io.c b/mono/metadata/socket-io.c
index cbce0f77269..949164e5548 100644
--- a/mono/metadata/socket-io.c
+++ b/mono/metadata/socket-io.c
@@ -20,12 +20,6 @@
#include
#include
#include
-#ifdef HAVE_UNISTD_H
-#include
-#endif
-#include
-
-#include
#ifdef HOST_WIN32
#include
#else
@@ -36,6 +30,12 @@
#include
#include
#endif
+#ifdef HAVE_UNISTD_H
+#include
+#endif
+#include
+
+#include
#include
#include
diff --git a/mono/metadata/string-icalls.c b/mono/metadata/string-icalls.c
index 0927141e792..22b1fbbbdb4 100644
--- a/mono/metadata/string-icalls.c
+++ b/mono/metadata/string-icalls.c
@@ -65,5 +65,12 @@ ves_icall_System_String_GetLOSLimit (void)
{
int limit = mono_gc_get_los_limit ();
- return (limit - 2 - sizeof (MonoString)) / 2;
+ return (limit - 2 - offsetof (MonoString, chars)) / 2;
}
+
+void
+ves_icall_System_String_InternalSetLength (MonoString *str, gint32 new_length)
+{
+ mono_gc_set_string_length (str, new_length);
+}
+
diff --git a/mono/metadata/string-icalls.h b/mono/metadata/string-icalls.h
index a0b831a1e20..33bcf80378b 100644
--- a/mono/metadata/string-icalls.h
+++ b/mono/metadata/string-icalls.h
@@ -30,4 +30,7 @@ ves_icall_System_String_InternalIsInterned (MonoString *str) MONO_INTERNAL;
int
ves_icall_System_String_GetLOSLimit (void) MONO_INTERNAL;
+void
+ves_icall_System_String_InternalSetLength (MonoString *str, gint32 new_length) MONO_INTERNAL;
+
#endif /* _MONO_CLI_STRING_ICALLS_H_ */
diff --git a/mono/metadata/threadpool.c b/mono/metadata/threadpool.c
index 39ade54daa1..36514cc6ea8 100644
--- a/mono/metadata/threadpool.c
+++ b/mono/metadata/threadpool.c
@@ -41,6 +41,7 @@
#include
#endif
#include
+#include
#ifdef HAVE_SYS_SOCKET_H
#include
#endif
@@ -62,13 +63,6 @@
#define THREAD_WANTS_A_BREAK(t) ((t->state & (ThreadState_StopRequested | \
ThreadState_SuspendRequested)) != 0)
-#define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
-#define SPIN_LOCK(i) do { \
- if (SPIN_TRYLOCK (i)) \
- break; \
- } while (1)
-
-#define SPIN_UNLOCK(i) i = 0
#define SMALL_STACK (128 * (sizeof (gpointer) / 4) * 1024)
/* DEBUG: prints tp data every 2s */
@@ -83,6 +77,12 @@ enum {
KQUEUE_BACKEND
};
+enum {
+ MONITOR_STATE_AWAKE,
+ MONITOR_STATE_FALLING_ASLEEP,
+ MONITOR_STATE_SLEEPING
+};
+
typedef struct {
mono_mutex_t io_lock; /* access to sock_to_state */
int inited; // 0 -> not initialized , 1->initializing, 2->initialized, 3->cleaned up
@@ -127,12 +127,10 @@ typedef struct {
void *pc_nthreads; /* Performance counter for total number of active threads */
/**/
volatile gint destroy_thread;
- volatile gint ignore_times; /* Used when there's a thread being created or destroyed */
- volatile gint sp_lock; /* spin lock used to protect ignore_times */
- volatile gint64 last_check;
- volatile gint64 time_sum;
- volatile gint n_sum;
- gint64 averages [2];
+#if DEBUG
+ volatile gint32 njobs;
+#endif
+ volatile gint32 nexecuted;
gboolean is_io;
} ThreadPool;
@@ -148,6 +146,7 @@ static void threadpool_init (ThreadPool *tp, int min_threads, int max_threads, v
static void threadpool_start_idle_threads (ThreadPool *tp);
static void threadpool_kill_idle_threads (ThreadPool *tp);
static gboolean threadpool_start_thread (ThreadPool *tp);
+static void threadpool_kill_thread (ThreadPool *tp);
static void monitor_thread (gpointer data);
static void socket_io_cleanup (SocketIOData *data);
static MonoObject *get_io_event (MonoMList **list, gint event);
@@ -159,10 +158,17 @@ static MonoClass *async_call_klass;
static MonoClass *socket_async_call_klass;
static MonoClass *process_async_call_klass;
+static GPtrArray *threads;
+mono_mutex_t threads_lock;
static GPtrArray *wsqs;
mono_mutex_t wsqs_lock;
static gboolean suspended;
+static volatile gint32 monitor_njobs = 0;
+static volatile gint32 monitor_state;
+static MonoSemType monitor_sem;
+static MonoInternalThread *monitor_internal_thread;
+
/* Hooks */
static MonoThreadPoolFunc tp_start_func;
static MonoThreadPoolFunc tp_finish_func;
@@ -656,6 +662,16 @@ mono_async_invoke (ThreadPool *tp, MonoAsyncResult *ares)
mono_thread_set_execution_context (ares->original_context);
ares->original_context = NULL;
}
+
+#if DEBUG
+ InterlockedDecrement (&tp->njobs);
+#endif
+ if (!tp->is_io)
+ InterlockedIncrement (&tp->nexecuted);
+
+ if (InterlockedDecrement (&monitor_njobs) == 0)
+ monitor_state = MONITOR_STATE_FALLING_ASLEEP;
+
return exc;
}
@@ -757,21 +773,135 @@ signal_handler (int signo)
}
#endif
+#define SAMPLES_PERIOD 500
+#define HISTORY_SIZE 10
+/* number of iteration without any jobs
+ in the queue before going to sleep */
+#define NUM_WAITING_ITERATIONS 10
+
+typedef struct {
+ gint32 nexecuted;
+ gint32 nthreads;
+ gint8 nthreads_diff;
+} SamplesHistory;
+
+/*
+ * returns :
+ * - 1 if the number of threads should increase
+ * - 0 if it should not change
+ * - -1 if it should decrease
+ * - -2 in case of error
+ */
+static gint8
+monitor_heuristic (gint16 *current, gint16 *history_size, SamplesHistory *history, ThreadPool *tp)
+{
+ int i;
+ gint8 decision;
+ gint16 cur, max = 0;
+ gboolean all_waitsleepjoin;
+ MonoInternalThread *thread;
+
+ /*
+ * The following heuristic tries to approach the optimal number of threads to maximize jobs throughput. To
+ * achieve this, it simply stores the number of jobs executed (nexecuted), the number of Threads (nthreads)
+ * and the decision (nthreads_diff) for the past HISTORY_SIZE periods of time, each period being of
+ * duration SAMPLES_PERIOD ms. This history gives us an insight into what happened, and to see if we should
+ * increase or reduce the number of threads by comparing the last period (current) to the best one.
+ *
+ * The algorithm can be describe as following :
+ * - if we have a better throughput than the best period : we should either increase the number of threads
+ * in case we already have more threads, either reduce the number of threads if we have less threads; this
+ * is equivalent to move away from the number of threads of the best period, because we are currently better
+ * - if we have a worse throughput than the best period : we should either decrease the number of threads if
+ * we have more threads, either increase the number of threads if we have less threads; this is equivalent
+ * to get closer to the number of threads of the best period, because we are currently worse
+ */
+
+ *history_size = MIN (*history_size + 1, HISTORY_SIZE);
+ cur = *current = (*current + 1) % *history_size;
+
+ history [cur].nthreads = tp->nthreads;
+ history [cur].nexecuted = InterlockedExchange (&tp->nexecuted, 0);
+
+ if (tp->waiting) {
+ /* if we have waiting thread in the pool, then do not create a new one */
+ history [cur].nthreads_diff = tp->waiting > 1 ? -1 : 0;
+ decision = 0;
+ } else if (tp->nthreads < tp->min_threads) {
+ history [cur].nthreads_diff = 1;
+ decision = 1;
+ } else if (*history_size <= 1) {
+ /* first iteration, let's add a thread by default */
+ history [cur].nthreads_diff = 1;
+ decision = 2;
+ } else {
+ mono_mutex_lock (&threads_lock);
+ if (threads == NULL) {
+ mono_mutex_unlock (&threads_lock);
+ return -2;
+ }
+ all_waitsleepjoin = TRUE;
+ for (i = 0; i < threads->len; ++i) {
+ thread = g_ptr_array_index (threads, i);
+ if (!(thread->state & ThreadState_WaitSleepJoin)) {
+ all_waitsleepjoin = FALSE;
+ break;
+ }
+ }
+ mono_mutex_unlock (&threads_lock);
+
+ if (all_waitsleepjoin) {
+ /* we might be in a condition of starvation/deadlock with tasks waiting for each others */
+ history [cur].nthreads_diff = 1;
+ decision = 5;
+ } else {
+ max = cur == 0 ? 1 : 0;
+ for (i = 0; i < *history_size; i++) {
+ if (i == cur)
+ continue;
+ if (history [i].nexecuted > history [max].nexecuted)
+ max = i;
+ }
+
+ if (history [cur].nexecuted >= history [max].nexecuted) {
+ /* we improved the situation, let's continue ! */
+ history [cur].nthreads_diff = history [cur].nthreads >= history [max].nthreads ? 1 : -1;
+ decision = 3;
+ } else {
+ /* we made it worse, let's return to previous situation */
+ history [cur].nthreads_diff = history [cur].nthreads >= history [max].nthreads ? -1 : 1;
+ decision = 4;
+ }
+ }
+ }
+
+#if DEBUG
+ printf ("monitor_thread: decision: %1d, history [current]: {nexecuted: %5d, nthreads: %3d, waiting: %2d, nthreads_diff: %2d}, history [max]: {nexecuted: %5d, nthreads: %3d}\n",
+ decision, history [cur].nexecuted, history [cur].nthreads, tp->waiting, history [cur].nthreads_diff, history [max].nexecuted, history [max].nthreads);
+#endif
+
+ return history [cur].nthreads_diff;
+}
+
static void
monitor_thread (gpointer unused)
{
ThreadPool *pools [2];
MonoInternalThread *thread;
- guint32 ms;
- gboolean need_one;
int i;
+ guint32 ms;
+ gint8 num_waiting_iterations = 0;
+
+ gint16 history_size = 0, current = -1;
+ SamplesHistory *history = malloc (sizeof (SamplesHistory) * HISTORY_SIZE);
+
pools [0] = &async_tp;
pools [1] = &async_io_tp;
thread = mono_thread_internal_current ();
ves_icall_System_Threading_Thread_SetName_internal (thread, mono_string_new (mono_domain_get (), "Threadpool monitor"));
while (1) {
- ms = 500;
+ ms = SAMPLES_PERIOD;
i = 10; //number of spurious awakes we tolerate before doing a round of rebalancing.
do {
guint32 ts;
@@ -791,26 +921,44 @@ monitor_thread (gpointer unused)
if (suspended)
continue;
+ /* threadpool is cleaning up */
+ if (async_tp.pool_status == 2 || async_io_tp.pool_status == 2)
+ break;
+
+ switch (monitor_state) {
+ case MONITOR_STATE_AWAKE:
+ num_waiting_iterations = 0;
+ break;
+ case MONITOR_STATE_FALLING_ASLEEP:
+ if (++num_waiting_iterations == NUM_WAITING_ITERATIONS) {
+ if (monitor_state == MONITOR_STATE_FALLING_ASLEEP && InterlockedCompareExchange (&monitor_state, MONITOR_STATE_SLEEPING, MONITOR_STATE_FALLING_ASLEEP) == MONITOR_STATE_FALLING_ASLEEP) {
+ MONO_SEM_WAIT (&monitor_sem);
+
+ num_waiting_iterations = 0;
+ current = -1;
+ history_size = 0;
+ }
+ }
+ break;
+ case MONITOR_STATE_SLEEPING:
+ g_assert_not_reached ();
+ }
+
for (i = 0; i < 2; i++) {
ThreadPool *tp;
tp = pools [i];
- if (tp->waiting > 0)
- continue;
- need_one = (mono_cq_count (tp->queue) > 0);
- if (!need_one && !tp->is_io) {
- mono_mutex_lock (&wsqs_lock);
- for (i = 0; wsqs != NULL && i < wsqs->len; i++) {
- MonoWSQ *wsq;
- wsq = g_ptr_array_index (wsqs, i);
- if (mono_wsq_count (wsq) != 0) {
- need_one = TRUE;
- break;
- }
- }
- mono_mutex_unlock (&wsqs_lock);
+
+ if (tp->is_io) {
+ if (!tp->waiting && mono_cq_count (tp->queue) > 0)
+ threadpool_start_thread (tp);
+ } else {
+ gint8 nthreads_diff = monitor_heuristic (¤t, &history_size, history, tp);
+
+ if (nthreads_diff == 1)
+ threadpool_start_thread (tp);
+ else if (nthreads_diff == -1)
+ threadpool_kill_thread (tp);
}
- if (need_one)
- threadpool_start_thread (tp);
}
}
}
@@ -857,6 +1005,10 @@ mono_thread_pool_init (void)
async_call_klass = mono_class_from_name (mono_defaults.corlib, "System", "MonoAsyncCall");
g_assert (async_call_klass);
+ mono_mutex_init (&threads_lock);
+ threads = g_ptr_array_sized_new (thread_count);
+ g_assert (threads);
+
mono_mutex_init_recursive (&wsqs_lock);
wsqs = g_ptr_array_sized_new (MAX (100 * cpu_count, thread_count));
@@ -878,6 +1030,10 @@ mono_thread_pool_init (void)
signal (SIGALRM, signal_handler);
alarm (2);
#endif
+
+ MONO_SEM_INIT (&monitor_sem, 0);
+ monitor_state = MONITOR_STATE_AWAKE;
+ monitor_njobs = 0;
}
static MonoAsyncResult *
@@ -1004,6 +1160,14 @@ mono_thread_pool_cleanup (void)
threadpool_kill_idle_threads (&async_tp);
threadpool_free_queue (&async_tp);
}
+
+ if (threads) {
+ mono_mutex_lock (&threads_lock);
+ if (threads)
+ g_ptr_array_free (threads, FALSE);
+ threads = NULL;
+ mono_mutex_unlock (&threads_lock);
+ }
if (wsqs) {
mono_mutex_lock (&wsqs_lock);
@@ -1014,6 +1178,8 @@ mono_thread_pool_cleanup (void)
mono_mutex_unlock (&wsqs_lock);
MONO_SEM_DESTROY (&async_tp.new_job);
}
+
+ MONO_SEM_DESTROY (&monitor_sem);
}
static gboolean
@@ -1021,6 +1187,7 @@ threadpool_start_thread (ThreadPool *tp)
{
gint n;
guint32 stack_size;
+ MonoInternalThread *thread;
stack_size = (!tp->is_io) ? 0 : SMALL_STACK;
while (!mono_runtime_is_shutting_down () && (n = tp->nthreads) < tp->max_threads) {
@@ -1028,7 +1195,13 @@ threadpool_start_thread (ThreadPool *tp)
#ifndef DISABLE_PERFCOUNTERS
mono_perfcounter_update_value (tp->pc_nthreads, TRUE, 1);
#endif
- mono_thread_create_internal (mono_get_root_domain (), tp->async_invoke, tp, TRUE, stack_size);
+ thread = mono_thread_create_internal (mono_get_root_domain (), tp->async_invoke, tp, TRUE, stack_size);
+ if (!tp->is_io) {
+ mono_mutex_lock (&threads_lock);
+ g_assert (threads != NULL);
+ g_ptr_array_add (threads, thread);
+ mono_mutex_unlock (&threads_lock);
+ }
return TRUE;
}
}
@@ -1043,6 +1216,13 @@ pulse_on_new_job (ThreadPool *tp)
MONO_SEM_POST (&tp->new_job);
}
+static void
+threadpool_kill_thread (ThreadPool *tp)
+{
+ if (tp->destroy_thread == 0 && InterlockedCompareExchange (&tp->destroy_thread, 1, 0) == 0)
+ pulse_on_new_job (tp);
+}
+
void
icall_append_job (MonoObject *ar)
{
@@ -1058,7 +1238,6 @@ threadpool_append_job (ThreadPool *tp, MonoObject *ar)
static void
threadpool_append_jobs (ThreadPool *tp, MonoObject **jobs, gint njobs)
{
- static int job_counter;
MonoObject *ar;
gint i;
@@ -1067,7 +1246,8 @@ threadpool_append_jobs (ThreadPool *tp, MonoObject **jobs, gint njobs)
if (tp->pool_status == 0 && InterlockedCompareExchange (&tp->pool_status, 1, 0) == 0) {
if (!tp->is_io) {
- mono_thread_create_internal (mono_get_root_domain (), monitor_thread, NULL, TRUE, SMALL_STACK);
+ monitor_internal_thread = mono_thread_create_internal (mono_get_root_domain (), monitor_thread, NULL, TRUE, SMALL_STACK);
+ monitor_internal_thread->flags |= MONO_THREAD_FLAG_DONT_MANAGE;
threadpool_start_thread (tp);
}
/* Create on demand up to min_threads to avoid startup penalty for apps that don't use
@@ -1078,14 +1258,18 @@ threadpool_append_jobs (ThreadPool *tp, MonoObject **jobs, gint njobs)
}
}
+ InterlockedAdd (&monitor_njobs, njobs);
+
+ if (monitor_state == MONITOR_STATE_SLEEPING && InterlockedCompareExchange (&monitor_state, MONITOR_STATE_AWAKE, MONITOR_STATE_SLEEPING) == MONITOR_STATE_SLEEPING)
+ MONO_SEM_POST (&monitor_sem);
+
+ if (monitor_state == MONITOR_STATE_FALLING_ASLEEP)
+ InterlockedCompareExchange (&monitor_state, MONITOR_STATE_AWAKE, MONITOR_STATE_FALLING_ASLEEP);
+
for (i = 0; i < njobs; i++) {
ar = jobs [i];
if (ar == NULL || mono_domain_is_unloading (ar->vtable->domain))
continue; /* Might happen when cleaning domain jobs */
- if (!tp->is_io && (InterlockedIncrement (&job_counter) % 10) == 0) {
- MonoAsyncResult *o = (MonoAsyncResult *) ar;
- o->add_time = mono_100ns_ticks ();
- }
threadpool_jobs_inc (ar);
#ifndef DISABLE_PERFCOUNTERS
mono_perfcounter_update_value (tp->pc_nitems, TRUE, 1);
@@ -1096,6 +1280,10 @@ threadpool_append_jobs (ThreadPool *tp, MonoObject **jobs, gint njobs)
mono_cq_enqueue (tp->queue, ar);
}
+#if DEBUG
+ InterlockedAdd (&tp->njobs, njobs);
+#endif
+
for (i = 0; tp->waiting > 0 && i < MIN(njobs, tp->max_threads); i++)
pulse_on_new_job (tp);
}
@@ -1309,84 +1497,6 @@ dequeue_or_steal (ThreadPool *tp, gpointer *data, MonoWSQ *local_wsq)
return (*data != NULL);
}
-static void
-process_idle_times (ThreadPool *tp, gint64 t)
-{
- gint64 ticks;
- gint64 avg;
- gboolean compute_avg;
- gint new_threads;
- gint64 per1;
-
- if (tp->ignore_times || t <= 0)
- return;
-
- compute_avg = FALSE;
- ticks = mono_100ns_ticks ();
- t = ticks - t;
- SPIN_LOCK (tp->sp_lock);
- if (tp->ignore_times) {
- SPIN_UNLOCK (tp->sp_lock);
- return;
- }
- tp->time_sum += t;
- tp->n_sum++;
- if (tp->last_check == 0)
- tp->last_check = ticks;
- else if (tp->last_check > 0 && (ticks - tp->last_check) > 5000000) {
- tp->ignore_times = 1;
- compute_avg = TRUE;
- }
- SPIN_UNLOCK (tp->sp_lock);
-
- if (!compute_avg)
- return;
-
- //printf ("Items: %d Time elapsed: %.3fs\n", tp->n_sum, (ticks - tp->last_check) / 10000.0);
- tp->last_check = ticks;
- new_threads = 0;
- avg = tp->time_sum / tp->n_sum;
- if (tp->averages [1] == 0) {
- tp->averages [1] = avg;
- } else {
- per1 = ((100 * (ABS (avg - tp->averages [1]))) / tp->averages [1]);
- if (per1 > 5) {
- if (avg > tp->averages [1]) {
- if (tp->averages [1] < tp->averages [0]) {
- new_threads = -1;
- } else {
- new_threads = 1;
- }
- } else if (avg < tp->averages [1] && tp->averages [1] < tp->averages [0]) {
- new_threads = 1;
- }
- } else {
- int min, n;
- min = tp->min_threads;
- n = tp->nthreads;
- if ((n - min) < min && tp->busy_threads == n)
- new_threads = 1;
- }
- /*
- if (new_threads != 0) {
- printf ("n: %d per1: %lld avg=%lld avg1=%lld avg0=%lld\n", new_threads, per1, avg, tp->averages [1], tp->averages [0]);
- }
- */
- }
-
- tp->time_sum = 0;
- tp->n_sum = 0;
-
- tp->averages [0] = tp->averages [1];
- tp->averages [1] = avg;
- tp->ignore_times = 0;
-
- if (new_threads == -1) {
- if (tp->destroy_thread == 0 && InterlockedCompareExchange (&tp->destroy_thread, 1, 0) == 0)
- pulse_on_new_job (tp);
- }
-}
-
static gboolean
should_i_die (ThreadPool *tp)
{
@@ -1513,8 +1623,6 @@ async_invoke_thread (gpointer data)
if (tp_item_begin_func)
tp_item_begin_func (tp_item_user_data);
- if (!is_io_task && ar->add_time > 0)
- process_idle_times (tp, ar->add_time);
exc = mono_async_invoke (tp, ar);
if (tp_item_end_func)
tp_item_end_func (tp_item_user_data);
@@ -1541,8 +1649,12 @@ async_invoke_thread (gpointer data)
ar = NULL;
data = NULL;
must_die = should_i_die (tp);
- if (!must_die && (tp->is_io || !mono_wsq_local_pop (&data)))
- dequeue_or_steal (tp, &data, wsq);
+ if (must_die) {
+ mono_wsq_suspend (wsq);
+ } else {
+ if (tp->is_io || !mono_wsq_local_pop (&data))
+ dequeue_or_steal (tp, &data, wsq);
+ }
n_naps = 0;
while (!must_die && !data && n_naps < 4) {
@@ -1608,6 +1720,16 @@ async_invoke_thread (gpointer data)
if (tp_finish_func)
tp_finish_func (tp_hooks_user_data);
+
+ if (!tp->is_io) {
+ if (threads) {
+ mono_mutex_lock (&threads_lock);
+ if (threads)
+ g_ptr_array_remove_fast (threads, mono_thread_current ()->internal_thread);
+ mono_mutex_unlock (&threads_lock);
+ }
+ }
+
return;
}
}
diff --git a/mono/metadata/threads-types.h b/mono/metadata/threads-types.h
index 6aeca4acf5e..860bb5b67e9 100644
--- a/mono/metadata/threads-types.h
+++ b/mono/metadata/threads-types.h
@@ -40,8 +40,6 @@ typedef enum {
ThreadApartmentState_Unknown = 0x00000002
} MonoThreadApartmentState;
-typedef void (*MonoThreadNotifyPendingExcFunc) (void);
-
#define SPECIAL_STATIC_NONE 0
#define SPECIAL_STATIC_THREAD 1
#define SPECIAL_STATIC_CONTEXT 2
@@ -54,6 +52,8 @@ typedef LPTHREAD_START_ROUTINE WapiThreadStart;
typedef struct _MonoInternalThread MonoInternalThread;
typedef void (*MonoThreadCleanupFunc) (MonoInternalThread* thread);
+/* INFO has type MonoThreadInfo* */
+typedef void (*MonoThreadNotifyPendingExcFunc) (gpointer info);
MonoInternalThread* mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size) MONO_INTERNAL;
diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c
index a0e5f8469d6..de4917ce08d 100644
--- a/mono/metadata/threads.c
+++ b/mono/metadata/threads.c
@@ -30,9 +30,6 @@
#include
#include
#include
-#ifndef HOST_WIN32
-#include
-#endif
#include
#include
#include
@@ -1210,12 +1207,16 @@ mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, g
{
LOCK_THREAD (this_obj);
- if (this_obj->flags & MONO_THREAD_FLAG_NAME_SET) {
+ if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) {
UNLOCK_THREAD (this_obj);
mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
return;
}
+ if (this_obj->name) {
+ g_free (this_obj->name);
+ this_obj->name_len = 0;
+ }
if (name) {
this_obj->name = g_new (gunichar2, mono_string_length (name));
memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
@@ -2028,12 +2029,12 @@ static void signal_thread_state_change (MonoInternalThread *thread)
* functions in the io-layer until the signal handler calls QueueUserAPC which will
* make it return.
*/
- wait_handle = wapi_prepare_interrupt_thread (thread->handle);
+ wait_handle = mono_thread_info_prepare_interrupt (thread->handle);
/* fixme: store the state somewhere */
mono_thread_kill (thread, mono_thread_get_abort_signal ());
- wapi_finish_interrupt_thread (wait_handle);
+ mono_thread_info_finish_interrupt (wait_handle);
#endif /* HOST_WIN32 */
}
@@ -2956,9 +2957,7 @@ void mono_thread_manage (void)
* to get correct user and system times from getrusage/wait/time(1)).
* This could be removed if we avoid pthread_detach() and use pthread_join().
*/
-#ifndef HOST_WIN32
mono_thread_info_yield ();
-#endif
}
static void terminate_thread (gpointer key, gpointer value, gpointer user)
@@ -3265,14 +3264,19 @@ mono_threads_perform_thread_dump (void)
printf ("Full thread dump:\n");
- /*
- * Make a copy of the hashtable since we can't do anything with
- * threads while threads_mutex is held.
- */
+ /* We take the loader lock and the root domain lock as to increase our odds of not deadlocking if
+ something needs then in the process.
+ */
+ mono_loader_lock ();
+ mono_domain_lock (mono_get_root_domain ());
+
mono_threads_lock ();
mono_g_hash_table_foreach (threads, dump_thread, NULL);
mono_threads_unlock ();
+ mono_domain_unlock (mono_get_root_domain ());
+ mono_loader_unlock ();
+
thread_dump_requested = FALSE;
}
@@ -4110,10 +4114,8 @@ static MonoException* mono_thread_execute_interruption (MonoInternalThread *thre
WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
#endif
InterlockedDecrement (&thread_interruption_requested);
-#ifndef HOST_WIN32
/* Clear the interrupted flag of the thread so it can wait again */
- wapi_clear_interruption ();
-#endif
+ mono_thread_info_clear_interruption ();
}
if ((thread->state & ThreadState_AbortRequested) != 0) {
@@ -4195,7 +4197,7 @@ mono_thread_request_interruption (gboolean running_managed)
if (mono_thread_notify_pending_exc_fn && !running_managed)
/* The JIT will notify the thread about the interruption */
/* This shouldn't take any locks */
- mono_thread_notify_pending_exc_fn ();
+ mono_thread_notify_pending_exc_fn (NULL);
/* this will awake the thread if it is in WaitForSingleObject
or similar */
@@ -4203,7 +4205,7 @@ mono_thread_request_interruption (gboolean running_managed)
#ifdef HOST_WIN32
QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
#else
- wapi_self_interrupt ();
+ mono_thread_info_self_interrupt ();
#endif
return NULL;
}
@@ -4236,9 +4238,8 @@ mono_thread_resume_interruption (void)
return NULL;
InterlockedIncrement (&thread_interruption_requested);
-#ifndef HOST_WIN32
- wapi_self_interrupt ();
-#endif
+ mono_thread_info_self_interrupt ();
+
return mono_thread_execute_interruption (thread);
}
@@ -4555,9 +4556,7 @@ abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception,
MonoException *exc = mono_thread_request_interruption (can_raise_exception);
if (exc)
mono_raise_exception (exc);
-#ifndef HOST_WIN32
- wapi_interrupt_thread (thread->handle);
-#endif
+ mono_thread_info_interrupt (thread->handle);
return;
}
@@ -4596,14 +4595,15 @@ abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception,
* functions in the io-layer until the signal handler calls QueueUserAPC which will
* make it return.
*/
-#ifndef HOST_WIN32
gpointer interrupt_handle;
- interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
-#endif
+
+ if (mono_thread_notify_pending_exc_fn)
+ /* The JIT will notify the thread about the interruption */
+ mono_thread_notify_pending_exc_fn (info);
+
+ interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
mono_thread_info_finish_suspend_and_resume (info);
-#ifndef HOST_WIN32
- wapi_finish_interrupt_thread (interrupt_handle);
-#endif
+ mono_thread_info_finish_interrupt (interrupt_handle);
}
/*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
}
@@ -4656,21 +4656,18 @@ suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
if (running_managed && !protected_wrapper) {
transition_to_suspended (thread, info);
} else {
-#ifndef HOST_WIN32
gpointer interrupt_handle;
-#endif
if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
InterlockedIncrement (&thread_interruption_requested);
-#ifndef HOST_WIN32
if (interrupt)
- interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
-#endif
+ interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
+ if (mono_thread_notify_pending_exc_fn && !running_managed)
+ /* The JIT will notify the thread about the interruption */
+ mono_thread_notify_pending_exc_fn (info);
mono_thread_info_finish_suspend_and_resume (info);
-#ifndef HOST_WIN32
if (interrupt)
- wapi_finish_interrupt_thread (interrupt_handle);
-#endif
+ mono_thread_info_finish_interrupt (interrupt_handle);
UNLOCK_THREAD (thread);
}
}
diff --git a/mono/metadata/verify.c b/mono/metadata/verify.c
index 50781a4bbf4..95bde8efbc5 100644
--- a/mono/metadata/verify.c
+++ b/mono/metadata/verify.c
@@ -1004,11 +1004,13 @@ verifier_load_type (VerifyContext *ctx, int token, const char *opcode) {
MonoClass *class = mono_method_get_wrapper_data (ctx->method, (guint32)token);
type = class ? &class->byval_arg : NULL;
} else {
+ MonoError error;
if (!IS_TYPE_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid type token 0x%08x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
return NULL;
}
- type = mono_type_get_full (ctx->image, token, ctx->generic_context);
+ type = mono_type_get_checked (ctx->image, token, ctx->generic_context, &error);
+ mono_error_cleanup (&error); /*FIXME don't swallow the error */
}
if (!type || mono_loader_get_last_error ()) {
diff --git a/mono/mini/Makefile.am.in b/mono/mini/Makefile.am.in
index f928eec806d..d43605ce620 100755
--- a/mono/mini/Makefile.am.in
+++ b/mono/mini/Makefile.am.in
@@ -83,8 +83,6 @@ libmonoldflags=$(monoldflags) -version-info 1:0:0
endif
endif
-if JIT_SUPPORTED
-
if SUPPORT_SGEN
sgen_binaries = mono-sgen
sgen_libraries = libmonosgen-2.0.la
@@ -166,8 +164,6 @@ libmono_llvm_la_LIBADD += $(top_builddir)/mono/mini/libmonoboehm-$(API_VER).la $
endif
endif
-endif
-
mono_boehm_SOURCES = \
main.c
@@ -195,6 +191,8 @@ buildver-boehm.h: libmini-static.la $(monodir)/mono/metadata/libmonoruntime-stat
endif
@echo "const char *build_date = \"`date`\";" > buildver-boehm.h
mono_boehm-main.$(OBJEXT): buildver-boehm.h
+main.c: buildver-boehm.h
+
endif
if DISABLE_EXECUTABLES
@@ -204,6 +202,8 @@ buildver-sgen.h: libmini-static.la $(monodir)/mono/metadata/libmonoruntimesgen-s
endif
@echo "const char *build_date = \"`date`\";" > buildver-sgen.h
mono_sgen-main-sgen.$(OBJEXT): buildver-sgen.h
+main-sgen.c: buildver-sgen.h
+
if DTRACE_G_REQUIRED
LIBMONO_DTRACE_OBJECT = .libs/mono-dtrace.$(OBJEXT)
@@ -344,6 +344,7 @@ sparc_sources = \
s390x_sources = \
mini-s390x.c \
mini-s390x.h \
+ support-s390x.h \
exceptions-s390x.c \
tramp-s390x.c
@@ -726,11 +727,7 @@ clean-local:
pkgconfigdir = $(libdir)/pkgconfig
-if JIT_SUPPORTED
BUILT_SOURCES = version.h $(arch_built)
-else
-BUILT_SOURCES = version.h
-endif
CLEANFILES= $(BUILT_SOURCES) *.exe *.dll
EXTRA_DIST = TestDriver.cs ldscript ldscript.mono \
diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c
index 3c805ddae8c..44812084153 100644
--- a/mono/mini/aot-compiler.c
+++ b/mono/mini/aot-compiler.c
@@ -10,17 +10,6 @@
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
*/
-/* Remaining AOT-only work:
- * - optimize the trampolines, generate more code in the arch files.
- * - make things more consistent with how elf works, for example, use ELF
- * relocations.
- * Remaining generics sharing work:
- * - optimize the size of the data which is encoded.
- * - optimize the runtime loading of data:
- * - the trampoline code calls mono_jit_info_table_find () to find the rgctx,
- * which loads the debugging+exception handling info for the method. This is a
- * huge waste of time and code, since the rgctx structure is currently empty.
- */
#include "config.h"
#include
#ifdef HAVE_UNISTD_H
@@ -42,7 +31,6 @@
#include
#include
-
#include
#include
#include
@@ -136,6 +124,7 @@ typedef struct MonoAotOptions {
gboolean use_trampolines_page;
gboolean no_instances;
gboolean gnu_asm;
+ gboolean llvm;
int nthreads;
int ntrampolines;
int nrgctx_trampolines;
@@ -149,6 +138,7 @@ typedef struct MonoAotOptions {
char *mtriple;
char *llvm_path;
char *instances_logfile_path;
+ char *logfile;
} MonoAotOptions;
typedef struct MonoAotStats {
@@ -244,6 +234,7 @@ typedef struct MonoAotCompile {
int objc_selector_index, objc_selector_index_2;
GPtrArray *objc_selectors;
GHashTable *objc_selector_to_index;
+ FILE *logfile;
FILE *instances_logfile;
} MonoAotCompile;
@@ -303,6 +294,38 @@ get_patch_name (int info)
static char*
get_plt_entry_debug_sym (MonoAotCompile *acfg, MonoJumpInfo *ji, GHashTable *cache);
+static void
+aot_printf (MonoAotCompile *acfg, const gchar *format, ...)
+{
+ FILE *output;
+ va_list args;
+
+ if (acfg->logfile)
+ output = acfg->logfile;
+ else
+ output = stdout;
+
+ va_start (args, format);
+ vfprintf (output, format, args);
+ va_end (args);
+}
+
+static void
+aot_printerrf (MonoAotCompile *acfg, const gchar *format, ...)
+{
+ FILE *output;
+ va_list args;
+
+ if (acfg->logfile)
+ output = acfg->logfile;
+ else
+ output = stderr;
+
+ va_start (args, format);
+ vfprintf (output, format, args);
+ va_end (args);
+}
+
/* Wrappers around the image writer functions */
static inline void
@@ -667,6 +690,10 @@ arch_init (MonoAotCompile *acfg)
acfg->llvm_label_prefix = "";
acfg->user_symbol_prefix = "";
+#if defined(TARGET_X86)
+ g_string_append (acfg->llc_args, " -march=x86 -mattr=sse4.1");
+#endif
+
#if defined(TARGET_AMD64)
g_string_append (acfg->llc_args, " -march=x86-64 -mattr=sse4.1");
#endif
@@ -1235,6 +1262,11 @@ arch_emit_specific_trampoline_pages (MonoAotCompile *acfg)
g_assert (code - buf == 8);
emit_bytes (acfg, buf, code - buf);
}
+
+ acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_SPECIFIC] = 16;
+ acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_STATIC_RGCTX] = 16;
+ acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_IMT_THUNK] = 72;
+ acfg->tramp_page_code_offsets [MONO_AOT_TRAMP_GSHAREDVT_ARG] = 16;
#elif defined(TARGET_ARM64)
arm64_emit_specific_trampoline_pages (acfg);
#endif
@@ -2299,7 +2331,9 @@ find_typespec_for_class (MonoAotCompile *acfg, MonoClass *klass)
if (!acfg->typespec_classes) {
acfg->typespec_classes = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoClass*) * len);
for (i = 0; i < len; ++i) {
- acfg->typespec_classes [i] = mono_class_get_full (acfg->image, MONO_TOKEN_TYPE_SPEC | (i + 1), NULL);
+ MonoError error;
+ acfg->typespec_classes [i] = mono_class_get_and_inflate_typespec_checked (acfg->image, MONO_TOKEN_TYPE_SPEC | (i + 1), NULL, &error);
+ g_assert (mono_error_ok (&error)); /* FIXME error handling */
}
}
for (i = 0; i < len; ++i) {
@@ -3113,7 +3147,7 @@ add_extra_method_with_depth (MonoAotCompile *acfg, MonoMethod *method, int depth
method = mini_get_shared_method (method);
if (acfg->aot_opts.log_generics)
- printf ("%*sAdding method %s.\n", depth, "", mono_method_full_name (method, TRUE));
+ aot_printf (acfg, "%*sAdding method %s.\n", depth, "", mono_method_full_name (method, TRUE));
add_method_full (acfg, method, TRUE, depth);
}
@@ -3330,8 +3364,9 @@ add_wrappers (MonoAotCompile *acfg)
if (info && !has_nullable) {
/* Supported by the dynamic runtime-invoke wrapper */
skip = TRUE;
- g_free (info);
}
+ if (info)
+ mono_arch_dyn_call_free (info);
}
#endif
@@ -3503,14 +3538,15 @@ add_wrappers (MonoAotCompile *acfg)
/* delegate-invoke wrappers */
for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
+ MonoError error;
MonoClass *klass;
MonoCustomAttrInfo *cattr;
token = MONO_TOKEN_TYPE_DEF | (i + 1);
- klass = mono_class_get (acfg->image, token);
+ klass = mono_class_get_checked (acfg->image, token, &error);
if (!klass) {
- mono_loader_clear_error ();
+ mono_error_cleanup (&error);
continue;
}
@@ -3591,13 +3627,14 @@ add_wrappers (MonoAotCompile *acfg)
/* array access wrappers */
for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPESPEC].rows; ++i) {
+ MonoError error;
MonoClass *klass;
token = MONO_TOKEN_TYPE_SPEC | (i + 1);
- klass = mono_class_get (acfg->image, token);
+ klass = mono_class_get_checked (acfg->image, token, &error);
if (!klass) {
- mono_loader_clear_error ();
+ mono_error_cleanup (&error);
continue;
}
@@ -3774,13 +3811,14 @@ add_wrappers (MonoAotCompile *acfg)
/* StructureToPtr/PtrToStructure wrappers */
for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
+ MonoError error;
MonoClass *klass;
token = MONO_TOKEN_TYPE_DEF | (i + 1);
- klass = mono_class_get (acfg->image, token);
+ klass = mono_class_get_checked (acfg->image, token, &error);
if (!klass) {
- mono_loader_clear_error ();
+ mono_error_cleanup (&error);
continue;
}
@@ -3821,7 +3859,7 @@ is_vt_inst (MonoGenericInst *inst)
for (i = 0; i < inst->type_argc; ++i) {
MonoType *t = inst->type_argv [i];
- if (t->type == MONO_TYPE_VALUETYPE)
+ if (MONO_TYPE_ISSTRUCT (t) || t->type == MONO_TYPE_VALUETYPE)
return TRUE;
}
return FALSE;
@@ -3929,7 +3967,7 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth,
return;
if (acfg->aot_opts.log_generics)
- printf ("%*sAdding generic instance %s [%s].\n", depth, "", mono_type_full_name (&klass->byval_arg), ref);
+ aot_printf (acfg, "%*sAdding generic instance %s [%s].\n", depth, "", mono_type_full_name (&klass->byval_arg), ref);
g_hash_table_insert (acfg->ginst_hash, klass, klass);
@@ -3979,7 +4017,7 @@ add_generic_class_with_depth (MonoAotCompile *acfg, MonoClass *klass, int depth,
method = mono_marshal_get_delegate_invoke (method, NULL);
if (acfg->aot_opts.log_generics)
- printf ("%*sAdding method %s.\n", depth, "", mono_method_full_name (method, TRUE));
+ aot_printf (acfg, "%*sAdding method %s.\n", depth, "", mono_method_full_name (method, TRUE));
add_method (acfg, method);
}
@@ -4239,13 +4277,14 @@ add_generic_instances (MonoAotCompile *acfg)
}
for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPESPEC].rows; ++i) {
+ MonoError error;
MonoClass *klass;
token = MONO_TOKEN_TYPE_SPEC | (i + 1);
- klass = mono_class_get (acfg->image, token);
+ klass = mono_class_get_checked (acfg->image, token, &error);
if (!klass || klass->rank) {
- mono_loader_clear_error ();
+ mono_error_cleanup (&error);
continue;
}
@@ -4833,13 +4872,14 @@ get_debug_sym (MonoMethod *method, const char *prefix, GHashTable *cache)
char *name1, *name2, *cached;
int i, j, len, count;
+ name1 = mono_method_full_name (method, TRUE);
+
#ifdef TARGET_MACH
// This is so that we don't accidentally create a local symbol (which starts with 'L')
- if (!prefix || !*prefix)
+ if ((!prefix || !*prefix) && name1 [0] == 'L')
prefix = "_";
#endif
- name1 = mono_method_full_name (method, TRUE);
len = strlen (name1);
name2 = malloc (strlen (prefix) + len + 16);
memcpy (name2, prefix, strlen (prefix));
@@ -4962,7 +5002,9 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
case MONO_PATCH_INFO_MSCORLIB_GOT_ADDR:
case MONO_PATCH_INFO_JIT_TLS_ID:
case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
+ break;
case MONO_PATCH_INFO_CASTCLASS_CACHE:
+ encode_value (patch_info->data.index, p, &p);
break;
case MONO_PATCH_INFO_METHOD_REL:
encode_value ((gint)patch_info->data.offset, p, &p);
@@ -5333,18 +5375,7 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
encoded = mono_unwind_ops_encode (cfg->unwind_ops, &encoded_len);
unwind_desc = get_unwind_info_offset (acfg, encoded, encoded_len);
- g_assert (unwind_desc < 0xffff);
- if (cfg->has_unwind_info_for_epilog) {
- /*
- * The lower 16 bits identify the unwind descriptor, the upper 16 bits contain the offset of
- * the start of the epilog from the end of the method.
- */
- g_assert (cfg->code_size - cfg->epilog_begin < 0xffff);
- encode_value (((cfg->code_size - cfg->epilog_begin) << 16) | unwind_desc, p, &p);
- g_free (encoded);
- } else {
- encode_value (unwind_desc, p, &p);
- }
+ encode_value (unwind_desc, p, &p);
} else {
encode_value (jinfo->unwind_info, p, &p);
}
@@ -5443,6 +5474,7 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
eh_info = mono_jit_info_get_arch_eh_info (jinfo);
encode_value (eh_info->stack_size, p, &p);
+ encode_value (eh_info->epilog_size, p, &p);
}
if (jinfo->has_generic_jit_info) {
@@ -5576,14 +5608,15 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
static guint32
emit_klass_info (MonoAotCompile *acfg, guint32 token)
{
- MonoClass *klass = mono_class_get (acfg->image, token);
+ MonoError error;
+ MonoClass *klass = mono_class_get_checked (acfg->image, token, &error);
guint8 *p, *buf;
int i, buf_size, res;
gboolean no_special_static, cant_encode;
gpointer iter = NULL;
if (!klass) {
- mono_loader_clear_error ();
+ mono_error_cleanup (&error);
buf_size = 16;
@@ -5737,41 +5770,16 @@ emit_plt (MonoAotCompile *acfg)
plt_entry = g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
ji = plt_entry->ji;
- if (acfg->llvm) {
- /*
- * If the target is directly callable, alias the plt symbol to point to
- * the method code.
- * FIXME: Use this to simplify emit_and_reloc_code ().
- * FIXME: Avoid the got slot.
- * FIXME: Add support to the binary writer.
- */
- if (ji && is_direct_callable (acfg, NULL, ji) && !acfg->use_bin_writer) {
- MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, ji->data.method);
-
- if (callee_cfg) {
- if (acfg->thumb_mixed && !callee_cfg->compile_llvm) {
- /* LLVM calls the PLT entries using bl, so emit a stub */
- emit_set_thumb_mode (acfg);
- fprintf (acfg->fp, "\n.thumb_func\n");
- emit_label (acfg, plt_entry->llvm_symbol);
- fprintf (acfg->fp, "bx pc\n");
- fprintf (acfg->fp, "nop\n");
- emit_set_arm_mode (acfg);
- fprintf (acfg->fp, "b %s\n", callee_cfg->asm_symbol);
- } else {
- fprintf (acfg->fp, "\n.set %s, %s\n", plt_entry->llvm_symbol, callee_cfg->asm_symbol);
- }
- continue;
- }
- }
- }
-
debug_sym = plt_entry->debug_sym;
if (acfg->thumb_mixed && !plt_entry->jit_used)
/* Emit only a thumb version */
continue;
+ /* Skip plt entries not actually called */
+ if (!plt_entry->jit_used && !plt_entry->llvm_used)
+ continue;
+
if (acfg->llvm && !acfg->thumb_mixed)
emit_label (acfg, plt_entry->llvm_symbol);
@@ -5811,9 +5819,6 @@ emit_plt (MonoAotCompile *acfg)
plt_entry = g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
ji = plt_entry->ji;
- if (ji && is_direct_callable (acfg, NULL, ji) && !acfg->use_bin_writer)
- continue;
-
/* Skip plt entries not actually called by LLVM code */
if (!plt_entry->llvm_used)
continue;
@@ -6361,10 +6366,14 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
opts->instances_logfile_path = g_strdup (arg + strlen ("log-instances="));
} else if (str_begins_with (arg, "log-instances")) {
opts->log_instances = TRUE;
+ } else if (str_begins_with (arg, "internal-logfile=")) {
+ opts->logfile = g_strdup (arg + strlen ("internal-logfile="));
} else if (str_begins_with (arg, "mtriple=")) {
opts->mtriple = g_strdup (arg + strlen ("mtriple="));
} else if (str_begins_with (arg, "llvm-path=")) {
opts->llvm_path = g_strdup (arg + strlen ("llvm-path="));
+ } else if (!strcmp (arg, "llvm")) {
+ opts->llvm = TRUE;
} else if (str_begins_with (arg, "readonly-value=")) {
add_readonly_value (opts, arg + strlen ("readonly-value="));
} else if (str_begins_with (arg, "info")) {
@@ -6422,9 +6431,10 @@ add_token_info_hash (gpointer key, gpointer value, gpointer user_data)
{
MonoMethod *method = (MonoMethod*)key;
MonoJumpInfoToken *ji = (MonoJumpInfoToken*)value;
- MonoJumpInfoToken *new_ji = g_new0 (MonoJumpInfoToken, 1);
MonoAotCompile *acfg = user_data;
+ MonoJumpInfoToken *new_ji;
+ new_ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfoToken));
new_ji->image = ji->image;
new_ji->token = ji->token;
g_hash_table_insert (acfg->token_info_hash, method, new_ji);
@@ -6552,6 +6562,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
gboolean skip;
int index, depth;
MonoMethod *wrapped;
+ JitFlags flags;
if (acfg->aot_opts.metadata_only)
return;
@@ -6596,7 +6607,12 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
* the runtime will not see AOT methods during AOT compilation,so it
* does not need to support them by creating a fake GOT etc.
*/
- cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), acfg->aot_opts.full_aot ? (JIT_FLAG_AOT|JIT_FLAG_FULL_AOT) : (JIT_FLAG_AOT), 0);
+ flags = JIT_FLAG_AOT;
+ if (acfg->aot_opts.full_aot)
+ flags |= JIT_FLAG_FULL_AOT;
+ if (acfg->llvm)
+ flags |= JIT_FLAG_LLVM;
+ cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), flags, 0);
mono_loader_clear_error ();
if (cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
@@ -6637,6 +6653,8 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
mono_acfg_lock (acfg);
g_hash_table_foreach (cfg->token_info_hash, add_token_info_hash, acfg);
mono_acfg_unlock (acfg);
+ g_hash_table_destroy (cfg->token_info_hash);
+ cfg->token_info_hash = NULL;
/*
* Check for absolute addresses.
@@ -6975,6 +6993,21 @@ mono_aot_get_method_name (MonoCompile *cfg)
return get_debug_sym (cfg->orig_method, "", llvm_acfg->method_label_hash);
}
+gboolean
+mono_aot_is_direct_callable (MonoJumpInfo *patch_info)
+{
+ return is_direct_callable (llvm_acfg, NULL, patch_info);
+}
+
+void
+mono_aot_mark_unused_llvm_plt_entry (MonoJumpInfo *patch_info)
+{
+ MonoPltEntry *plt_entry;
+
+ plt_entry = get_plt_entry (llvm_acfg, patch_info);
+ plt_entry->llvm_used = FALSE;
+}
+
char*
mono_aot_get_plt_symbol (MonoJumpInfoType type, gconstpointer data)
{
@@ -7024,7 +7057,7 @@ mono_aot_patch_info_dup (MonoJumpInfo* ji)
* Emit the LLVM code into an LLVM bytecode file, and compile it using the LLVM
* tools.
*/
-static void
+static gboolean
emit_llvm_file (MonoAotCompile *acfg)
{
char *command, *opts, *tempbc;
@@ -7070,7 +7103,7 @@ emit_llvm_file (MonoAotCompile *acfg)
tempbc = g_strdup_printf ("%s.bc", acfg->tmpbasename);
- mono_llvm_emit_aot_module (tempbc, acfg->final_got_size);
+ mono_llvm_emit_aot_module (tempbc, g_path_get_basename (acfg->image->name), acfg->final_got_size);
g_free (tempbc);
/*
@@ -7104,10 +7137,9 @@ emit_llvm_file (MonoAotCompile *acfg)
opts = g_strdup ("-targetlibinfo -no-aa -basicaa -notti -instcombine -simplifycfg -sroa -domtree -early-cse -lazy-value-info -correlated-propagation -simplifycfg -instcombine -simplifycfg -reassociate -domtree -loops -loop-simplify -lcssa -loop-rotate -licm -lcssa -loop-unswitch -instcombine -scalar-evolution -loop-simplify -lcssa -indvars -loop-idiom -loop-deletion -loop-unroll -memdep -gvn -memdep -memcpyopt -sccp -instcombine -lazy-value-info -correlated-propagation -domtree -memdep -adce -simplifycfg -instcombine -strip-dead-prototypes -domtree -verify");
#if 1
command = g_strdup_printf ("%sopt -f %s -o \"%s.opt.bc\" \"%s.bc\"", acfg->aot_opts.llvm_path, opts, acfg->tmpbasename, acfg->tmpbasename);
- printf ("Executing opt: %s\n", command);
- if (system (command) != 0) {
- exit (1);
- }
+ aot_printf (acfg, "Executing opt: %s\n", command);
+ if (system (command) != 0)
+ return FALSE;
#endif
g_free (opts);
@@ -7133,11 +7165,11 @@ emit_llvm_file (MonoAotCompile *acfg)
command = g_strdup_printf ("%sllc %s -disable-gnu-eh-frame -enable-mono-eh-frame -o \"%s\" \"%s.opt.bc\"", acfg->aot_opts.llvm_path, acfg->llc_args->str, acfg->tmpfname, acfg->tmpbasename);
- printf ("Executing llc: %s\n", command);
+ aot_printf (acfg, "Executing llc: %s\n", command);
- if (system (command) != 0) {
- exit (1);
- }
+ if (system (command) != 0)
+ return FALSE;
+ return TRUE;
}
#endif
@@ -7810,10 +7842,11 @@ emit_class_name_table (MonoAotCompile *acfg)
for (i = 0; i < table_size; ++i)
g_ptr_array_add (table, NULL);
for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
+ MonoError error;
token = MONO_TOKEN_TYPE_DEF | (i + 1);
- klass = mono_class_get (acfg->image, token);
+ klass = mono_class_get_checked (acfg->image, token, &error);
if (!klass) {
- mono_loader_clear_error ();
+ mono_error_cleanup (&error);
continue;
}
full_name = mono_type_get_name_full (mono_class_get_type (klass), MONO_TYPE_NAME_FORMAT_FULL_NAME);
@@ -8381,7 +8414,7 @@ emit_dwarf_info (MonoAotCompile *acfg)
#endif
}
-static void
+static gboolean
collect_methods (MonoAotCompile *acfg)
{
int mindex, i;
@@ -8395,9 +8428,9 @@ collect_methods (MonoAotCompile *acfg)
method = mono_get_method (acfg->image, token, NULL);
if (!method) {
- printf ("Failed to load method 0x%x from '%s'.\n", token, image->name);
- printf ("Run with MONO_LOG_LEVEL=debug for more information.\n");
- exit (1);
+ aot_printerrf (acfg, "Failed to load method 0x%x from '%s'.\n", token, image->name);
+ aot_printerrf (acfg, "Run with MONO_LOG_LEVEL=debug for more information.\n");
+ return FALSE;
}
/* Load all methods eagerly to skip the slower lazy loading code */
@@ -8461,6 +8494,7 @@ collect_methods (MonoAotCompile *acfg)
if (acfg->aot_opts.full_aot)
add_wrappers (acfg);
+ return TRUE;
}
static void
@@ -8573,9 +8607,9 @@ compile_asm (MonoAotCompile *acfg)
#endif
if (acfg->aot_opts.asm_only) {
- printf ("Output file: '%s'.\n", acfg->tmpfname);
+ aot_printf (acfg, "Output file: '%s'.\n", acfg->tmpfname);
if (acfg->aot_opts.static_link)
- printf ("Linking symbol: '%s'.\n", acfg->static_linking_symbol);
+ aot_printf (acfg, "Linking symbol: '%s'.\n", acfg->static_linking_symbol);
return 0;
}
@@ -8588,7 +8622,7 @@ compile_asm (MonoAotCompile *acfg)
objfile = g_strdup_printf ("%s.o", acfg->tmpfname);
}
command = g_strdup_printf ("%s%s %s %s -o %s %s", tool_prefix, AS_NAME, AS_OPTIONS, acfg->as_args ? acfg->as_args->str : "", objfile, acfg->tmpfname);
- printf ("Executing the native assembler: %s\n", command);
+ aot_printf (acfg, "Executing the native assembler: %s\n", command);
if (system (command) != 0) {
g_free (command);
g_free (objfile);
@@ -8598,8 +8632,8 @@ compile_asm (MonoAotCompile *acfg)
g_free (command);
if (acfg->aot_opts.static_link) {
- printf ("Output file: '%s'.\n", objfile);
- printf ("Linking symbol: '%s'.\n", acfg->static_linking_symbol);
+ aot_printf (acfg, "Output file: '%s'.\n", objfile);
+ aot_printf (acfg, "Linking symbol: '%s'.\n", acfg->static_linking_symbol);
g_free (objfile);
return 0;
}
@@ -8616,7 +8650,7 @@ compile_asm (MonoAotCompile *acfg)
#else
command = g_strdup_printf ("%sld %s -shared -o %s %s.o", tool_prefix, LD_OPTIONS, tmp_outfile_name, acfg->tmpfname);
#endif
- printf ("Executing the native linker: %s\n", command);
+ aot_printf (acfg, "Executing the native linker: %s\n", command);
if (system (command) != 0) {
g_free (tmp_outfile_name);
g_free (outfile_name);
@@ -8638,7 +8672,7 @@ compile_asm (MonoAotCompile *acfg)
* happens a lot in emit_and_reloc_code (), so we need to get rid of them.
*/
command = g_strdup_printf ("%sstrip --strip-symbol=\\$a --strip-symbol=\\$d %s", tool_prefix, tmp_outfile_name);
- printf ("Stripping the binary: %s\n", command);
+ aot_printf (acfg, "Stripping the binary: %s\n", command);
if (system (command) != 0) {
g_free (tmp_outfile_name);
g_free (outfile_name);
@@ -8652,7 +8686,7 @@ compile_asm (MonoAotCompile *acfg)
#if defined(TARGET_MACH)
command = g_strdup_printf ("dsymutil %s", outfile_name);
- printf ("Executing dsymutil: %s\n", command);
+ aot_printf (acfg, "Executing dsymutil: %s\n", command);
if (system (command) != 0) {
return 1;
}
@@ -8666,7 +8700,7 @@ compile_asm (MonoAotCompile *acfg)
g_free (objfile);
if (acfg->aot_opts.save_temps)
- printf ("Retained input file.\n");
+ aot_printf (acfg, "Retained input file.\n");
else
unlink (acfg->tmpfname);
@@ -8692,7 +8726,7 @@ acfg_create (MonoAssembly *ass, guint32 opts)
acfg->patch_to_got_offset_by_type [i] = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
acfg->got_patches = g_ptr_array_new ();
acfg->method_to_cfg = g_hash_table_new (NULL, NULL);
- acfg->token_info_hash = g_hash_table_new_full (NULL, NULL, NULL, g_free);
+ acfg->token_info_hash = g_hash_table_new_full (NULL, NULL, NULL, NULL);
acfg->method_to_pinvoke_import = g_hash_table_new_full (NULL, NULL, NULL, g_free);
acfg->image_hash = g_hash_table_new (NULL, NULL);
acfg->image_table = g_ptr_array_new ();
@@ -8771,15 +8805,6 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
TV_DECLARE (atv);
TV_DECLARE (btv);
-#if !defined(MONO_ARCH_GSHAREDVT_SUPPORTED) || !defined(ENABLE_GSHAREDVT)
- if (opts & MONO_OPT_GSHAREDVT) {
- fprintf (stderr, "-O=gsharedvt not supported on this platform.\n");
- exit (1);
- }
-#endif
-
- printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
-
acfg = acfg_create (ass, opts);
memset (&acfg->aot_opts, 0, sizeof (acfg->aot_opts));
@@ -8796,21 +8821,34 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
mono_aot_parse_options (aot_options, &acfg->aot_opts);
+ if (acfg->aot_opts.logfile) {
+ acfg->logfile = fopen (acfg->aot_opts.logfile, "a+");
+ }
+
if (acfg->aot_opts.static_link)
acfg->aot_opts.autoreg = TRUE;
//acfg->aot_opts.print_skipped_methods = TRUE;
+#if !defined(MONO_ARCH_GSHAREDVT_SUPPORTED) || !defined(ENABLE_GSHAREDVT)
+ if (opts & MONO_OPT_GSHAREDVT) {
+ aot_printerrf (acfg, "-O=gsharedvt not supported on this platform.\n");
+ return 1;
+ }
+#endif
+
+ aot_printf (acfg, "Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
+
#ifndef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
if (acfg->aot_opts.full_aot) {
- printf ("--aot=full is not supported on this platform.\n");
+ aot_printerrf (acfg, "--aot=full is not supported on this platform.\n");
return 1;
}
#endif
if (acfg->aot_opts.direct_pinvoke && !acfg->aot_opts.static_link) {
- fprintf (stderr, "The 'direct-pinvoke' AOT option also requires the 'static' AOT option.\n");
- exit (1);
+ aot_printerrf (acfg, "The 'direct-pinvoke' AOT option also requires the 'static' AOT option.\n");
+ return 1;
}
if (acfg->aot_opts.static_link)
@@ -8823,21 +8861,23 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
opt->gen_seq_points = TRUE;
if (!mono_debug_enabled ()) {
- fprintf (stderr, "The soft-debug AOT option requires the --debug option.\n");
+ aot_printerrf (acfg, "The soft-debug AOT option requires the --debug option.\n");
return 1;
}
acfg->flags |= MONO_AOT_FILE_FLAG_DEBUG;
}
- if (mono_use_llvm) {
+ if (mono_use_llvm || acfg->aot_opts.llvm) {
acfg->llvm = TRUE;
acfg->aot_opts.asm_writer = TRUE;
acfg->flags |= MONO_AOT_FILE_FLAG_WITH_LLVM;
if (acfg->aot_opts.soft_debug) {
- fprintf (stderr, "The 'soft-debug' option is not supported when compiling with LLVM.\n");
- exit (1);
+ aot_printerrf (acfg, "The 'soft-debug' option is not supported when compiling with LLVM.\n");
+ return 1;
}
+
+ mini_llvm_init ();
}
if (acfg->aot_opts.full_aot)
@@ -8846,8 +8886,8 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
if (acfg->aot_opts.instances_logfile_path) {
acfg->instances_logfile = fopen (acfg->aot_opts.instances_logfile_path, "w");
if (!acfg->instances_logfile) {
- fprintf (stderr, "Unable to create logfile: '%s'.\n", acfg->aot_opts.instances_logfile_path);
- exit (1);
+ aot_printerrf (acfg, "Unable to create logfile: '%s'.\n", acfg->aot_opts.instances_logfile_path);
+ return 1;
}
}
@@ -8893,7 +8933,9 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
mono_set_partial_sharing_supported (TRUE);
*/
- collect_methods (acfg);
+ res = collect_methods (acfg);
+ if (!res)
+ return 1;
acfg->cfgs_size = acfg->methods->len + 32;
acfg->cfgs = g_new0 (MonoCompile*, acfg->cfgs_size);
@@ -8945,6 +8987,8 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
#ifdef ENABLE_LLVM
if (acfg->llvm) {
+ gboolean res;
+
if (acfg->aot_opts.asm_only) {
if (acfg->aot_opts.outfile) {
acfg->tmpfname = g_strdup_printf ("%s", acfg->aot_opts.outfile);
@@ -8958,7 +9002,9 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
acfg->tmpfname = g_strdup_printf ("%s.s", acfg->tmpbasename);
}
- emit_llvm_file (acfg);
+ res = emit_llvm_file (acfg);
+ if (!res)
+ return 1;
}
#endif
@@ -8976,7 +9022,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
acfg->fp = fopen (tmp_outfile_name, "w");
if (!acfg->fp) {
- printf ("Unable to create temporary file '%s': %s\n", tmp_outfile_name, strerror (errno));
+ aot_printf (acfg, "Unable to create temporary file '%s': %s\n", tmp_outfile_name, strerror (errno));
return 1;
}
@@ -9000,7 +9046,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
}
}
if (acfg->fp == 0) {
- fprintf (stderr, "Unable to open file '%s': %s\n", acfg->tmpfname, strerror (errno));
+ aot_printerrf (acfg, "Unable to open file '%s': %s\n", acfg->tmpfname, strerror (errno));
return 1;
}
acfg->w = img_writer_create (acfg->fp, FALSE);
@@ -9037,7 +9083,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
if (!acfg->aot_opts.nodebug || acfg->aot_opts.dwarf_debug) {
if (acfg->aot_opts.dwarf_debug && !mono_debug_enabled ()) {
- fprintf (stderr, "The dwarf AOT option requires the --debug option.\n");
+ aot_printerrf (acfg, "The dwarf AOT option requires the --debug option.\n");
return 1;
}
acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL, 0, FALSE, !acfg->gas_line_numbers);
@@ -9125,7 +9171,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
all_sizes = acfg->stats.code_size + acfg->stats.info_size + acfg->stats.ex_info_size + acfg->stats.unwind_info_size + acfg->stats.class_info_size + acfg->stats.got_info_size + acfg->stats.offsets_size + acfg->stats.plt_size;
- printf ("Code: %d(%d%%) Info: %d(%d%%) Ex Info: %d(%d%%) Unwind Info: %d(%d%%) Class Info: %d(%d%%) PLT: %d(%d%%) GOT Info: %d(%d%%) Offsets: %d(%d%%) GOT: %d\n",
+ aot_printf (acfg, "Code: %d(%d%%) Info: %d(%d%%) Ex Info: %d(%d%%) Unwind Info: %d(%d%%) Class Info: %d(%d%%) PLT: %d(%d%%) GOT Info: %d(%d%%) Offsets: %d(%d%%) GOT: %d\n",
acfg->stats.code_size, acfg->stats.code_size * 100 / all_sizes,
acfg->stats.info_size, acfg->stats.info_size * 100 / all_sizes,
acfg->stats.ex_info_size, acfg->stats.ex_info_size * 100 / all_sizes,
@@ -9135,19 +9181,19 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
acfg->stats.got_info_size, acfg->stats.got_info_size * 100 / all_sizes,
acfg->stats.offsets_size, acfg->stats.offsets_size * 100 / all_sizes,
(int)(acfg->got_offset * sizeof (gpointer)));
- printf ("Compiled: %d/%d (%d%%)%s, No GOT slots: %d (%d%%), Direct calls: %d (%d%%)\n",
+ aot_printf (acfg, "Compiled: %d/%d (%d%%)%s, No GOT slots: %d (%d%%), Direct calls: %d (%d%%)\n",
acfg->stats.ccount, acfg->stats.mcount, acfg->stats.mcount ? (acfg->stats.ccount * 100) / acfg->stats.mcount : 100,
llvm_stats_msg,
acfg->stats.methods_without_got_slots, acfg->stats.mcount ? (acfg->stats.methods_without_got_slots * 100) / acfg->stats.mcount : 100,
acfg->stats.direct_calls, acfg->stats.all_calls ? (acfg->stats.direct_calls * 100) / acfg->stats.all_calls : 100);
if (acfg->stats.genericcount)
- printf ("%d methods are generic (%d%%)\n", acfg->stats.genericcount, acfg->stats.mcount ? (acfg->stats.genericcount * 100) / acfg->stats.mcount : 100);
+ aot_printf (acfg, "%d methods are generic (%d%%)\n", acfg->stats.genericcount, acfg->stats.mcount ? (acfg->stats.genericcount * 100) / acfg->stats.mcount : 100);
if (acfg->stats.abscount)
- printf ("%d methods contain absolute addresses (%d%%)\n", acfg->stats.abscount, acfg->stats.mcount ? (acfg->stats.abscount * 100) / acfg->stats.mcount : 100);
+ aot_printf (acfg, "%d methods contain absolute addresses (%d%%)\n", acfg->stats.abscount, acfg->stats.mcount ? (acfg->stats.abscount * 100) / acfg->stats.mcount : 100);
if (acfg->stats.lmfcount)
- printf ("%d methods contain lmf pointers (%d%%)\n", acfg->stats.lmfcount, acfg->stats.mcount ? (acfg->stats.lmfcount * 100) / acfg->stats.mcount : 100);
+ aot_printf (acfg, "%d methods contain lmf pointers (%d%%)\n", acfg->stats.lmfcount, acfg->stats.mcount ? (acfg->stats.lmfcount * 100) / acfg->stats.mcount : 100);
if (acfg->stats.ocount)
- printf ("%d methods have other problems (%d%%)\n", acfg->stats.ocount, acfg->stats.mcount ? (acfg->stats.ocount * 100) / acfg->stats.mcount : 100);
+ aot_printf (acfg, "%d methods have other problems (%d%%)\n", acfg->stats.ocount, acfg->stats.mcount ? (acfg->stats.ocount * 100) / acfg->stats.mcount : 100);
TV_GETTIME (atv);
res = img_writer_emit_writeout (acfg->w);
@@ -9159,7 +9205,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
int err = rename (tmp_outfile_name, outfile_name);
if (err) {
- printf ("Unable to rename '%s' to '%s': %s\n", tmp_outfile_name, outfile_name, strerror (errno));
+ aot_printf (acfg, "Unable to rename '%s' to '%s': %s\n", tmp_outfile_name, outfile_name, strerror (errno));
return 1;
}
} else {
@@ -9175,13 +9221,13 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
if (acfg->aot_opts.stats) {
int i;
- printf ("GOT slot distribution:\n");
+ aot_printf (acfg, "GOT slot distribution:\n");
for (i = 0; i < MONO_PATCH_INFO_NONE; ++i)
if (acfg->stats.got_slot_types [i])
- printf ("\t%s: %d (%d)\n", get_patch_name (i), acfg->stats.got_slot_types [i], acfg->stats.got_slot_info_sizes [i]);
+ aot_printf (acfg, "\t%s: %d (%d)\n", get_patch_name (i), acfg->stats.got_slot_types [i], acfg->stats.got_slot_info_sizes [i]);
}
- printf ("JIT time: %d ms, Generation time: %d ms, Assembly+Link time: %d ms.\n", acfg->stats.jit_time / 1000, acfg->stats.gen_time / 1000, acfg->stats.link_time / 1000);
+ aot_printf (acfg, "JIT time: %d ms, Generation time: %d ms, Assembly+Link time: %d ms.\n", acfg->stats.jit_time / 1000, acfg->stats.gen_time / 1000, acfg->stats.link_time / 1000);
acfg_free (acfg);
diff --git a/mono/mini/aot-runtime.c b/mono/mini/aot-runtime.c
index f484f18364b..97d22706db0 100644
--- a/mono/mini/aot-runtime.c
+++ b/mono/mini/aot-runtime.c
@@ -176,6 +176,8 @@ static GHashTable *ji_to_amodule;
*/
static gboolean enable_aot_cache = FALSE;
+static gboolean mscorlib_aot_loaded;
+
/* For debugging */
static gint32 mono_last_aot_method = -1;
@@ -403,6 +405,7 @@ decode_generic_context (MonoAotModule *module, MonoGenericContext *ctx, guint8 *
static MonoClass*
decode_klass_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
{
+ MonoError error;
MonoImage *image;
MonoClass *klass = NULL, *eklass;
guint32 token, rank, idx;
@@ -421,21 +424,24 @@ decode_klass_ref (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
image = load_image (module, 0, TRUE);
if (!image)
return NULL;
- klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF + idx);
+ klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF + idx, &error);
+ g_assert (mono_error_ok (&error));
break;
case MONO_AOT_TYPEREF_TYPEDEF_INDEX_IMAGE:
idx = decode_value (p, &p);
image = load_image (module, decode_value (p, &p), TRUE);
if (!image)
return NULL;
- klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF + idx);
+ klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF + idx, &error);
+ g_assert (mono_error_ok (&error));
break;
case MONO_AOT_TYPEREF_TYPESPEC_TOKEN:
token = decode_value (p, &p);
image = module->assembly->image;
if (!image)
return NULL;
- klass = mono_class_get (image, token);
+ klass = mono_class_get_checked (image, token, &error);
+ g_assert (mono_error_ok (&error));
break;
case MONO_AOT_TYPEREF_GINST: {
MonoClass *gclass;
@@ -1374,13 +1380,15 @@ aot_cache_load_module (MonoAssembly *assembly, char **aot_name)
{
MonoAotCacheConfig *config;
GSList *l;
- char *fname, *tmp2, *aot_options;
+ char *fname, *tmp2, *aot_options, *failure_fname;
const char *home;
MonoDl *module;
gboolean res;
gint exit_status;
char *hash;
int pid;
+ gboolean enabled;
+ FILE *failure_file;
*aot_name = NULL;
@@ -1389,13 +1397,34 @@ aot_cache_load_module (MonoAssembly *assembly, char **aot_name)
/* Check in the list of assemblies enabled for aot caching */
config = mono_get_aot_cache_config ();
- for (l = config->assemblies; l; l = l->next) {
- char *n = l->data;
- if (!strcmp (assembly->aname.name, n))
- break;
+ enabled = FALSE;
+ if (config->apps) {
+ MonoDomain *domain = mono_domain_get ();
+ MonoAssembly *entry_assembly = domain->entry_assembly;
+
+ // FIXME: This cannot be used for mscorlib during startup, since entry_assembly is not set yet
+ for (l = config->apps; l; l = l->next) {
+ char *n = l->data;
+
+ if ((entry_assembly && !strcmp (entry_assembly->aname.name, n)) || (!entry_assembly && !strcmp (assembly->aname.name, n)))
+ break;
+ }
+ if (l)
+ enabled = TRUE;
}
- if (!l)
+
+ if (!enabled) {
+ for (l = config->assemblies; l; l = l->next) {
+ char *n = l->data;
+
+ if (!strcmp (assembly->aname.name, n))
+ break;
+ }
+ if (l)
+ enabled = TRUE;
+ }
+ if (!enabled)
return NULL;
if (!cache_dir) {
@@ -1423,21 +1452,38 @@ aot_cache_load_module (MonoAssembly *assembly, char **aot_name)
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: loading from cache: '%s'.", fname);
module = mono_dl_open (fname, MONO_DL_LAZY, NULL);
- if (module)
+ if (module) {
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: found in cache: '%s'.", fname);
return module;
+ }
- mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: not found.");
-
- if (!strcmp (assembly->aname.name, "mscorlib") && !mono_defaults.corlib)
- /* Can't AOT this during startup */
+ if (!strcmp (assembly->aname.name, "mscorlib") && !mscorlib_aot_loaded)
+ /*
+ * Can't AOT this during startup, so we AOT it when called later from
+ * mono_aot_get_method ().
+ */
return NULL;
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: not found.");
+
/* Only AOT one assembly per run to avoid slowing down execution too much */
if (cache_count > 0)
return NULL;
cache_count ++;
- mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: compiling assembly '%s'... ", assembly->image->name);
+ /* Check for previous failure */
+ failure_fname = g_strdup_printf ("%s.failure", fname);
+ failure_file = fopen (failure_fname, "r");
+ if (failure_file) {
+ mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: assembly '%s' previously failed to compile '%s' ('%s')... ", assembly->image->name, fname, failure_fname);
+ g_free (failure_fname);
+ return NULL;
+ } else {
+ g_free (failure_fname);
+ fclose (failure_file);
+ }
+
+ mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: compiling assembly '%s', logfile: '%s.log'... ", assembly->image->name, fname);
/*
* We need to invoke the AOT compiler here. There are multiple approaches:
@@ -1448,16 +1494,18 @@ aot_cache_load_module (MonoAssembly *assembly, char **aot_name)
* - fork a new process and do the work there.
*/
if (in_process) {
- FILE *logfile;
- char *logfile_name;
-
- logfile_name = g_strdup_printf ("%s/aot.log", cache_dir);
- logfile = fopen (logfile_name, "a+");
-
- aot_options = g_strdup_printf ("outfile=%s", fname);
+ aot_options = g_strdup_printf ("outfile=%s,internal-logfile=%s.log%s%s", fname, fname, config->aot_options ? "," : "", config->aot_options ? config->aot_options : "");
/* Maybe due this in another thread ? */
res = mono_compile_assembly (assembly, mono_parse_default_optimizations (NULL), aot_options);
- // FIXME: Cache failures
+ if (res) {
+ mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: compilation failed.");
+ failure_fname = g_strdup_printf ("%s.failure", fname);
+ failure_file = fopen (failure_fname, "a+");
+ fclose (failure_file);
+ g_free (failure_fname);
+ } else {
+ mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT: compilation succeeded.");
+ }
} else {
/*
* - Avoid waiting for the aot process to finish ?
@@ -1705,10 +1753,6 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
if (mono_security_cas_enabled ())
return;
- if (enable_aot_cache && !strcmp (assembly->aname.name, "mscorlib") && !mono_defaults.corlib && !mono_aot_only)
- /* Loaded later from mono_aot_get_method () */
- return;
-
mono_aot_lock ();
if (static_aot_modules)
info = g_hash_table_lookup (static_aot_modules, assembly->aname.name);
@@ -2064,9 +2108,7 @@ mono_aot_init (void)
if (g_getenv ("MONO_LASTAOT"))
mono_last_aot_method = atoi (g_getenv ("MONO_LASTAOT"));
-#ifdef ENABLE_AOT_CACHE
aot_cache_init ();
-#endif
}
void
@@ -2258,8 +2300,11 @@ mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const ch
name_space2 = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
if (!strcmp (name, name2) && !strcmp (name_space, name_space2)) {
+ MonoError error;
amodule_unlock (amodule);
- *klass = mono_class_get (image, token);
+ *klass = mono_class_get_checked (image, token, &error);
+ if (!mono_error_ok (&error))
+ mono_error_cleanup (&error); /* FIXME don't swallow the error */
/* Add to cache */
if (*klass) {
@@ -2299,7 +2344,8 @@ static MonoJitInfo*
decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain,
MonoMethod *method, guint8 *code,
MonoJitExceptionInfo *clauses, int num_clauses,
- int extra_size, GSList **nesting,
+ MonoJitInfoFlags flags,
+ GSList **nesting,
int *this_reg, int *this_offset)
{
guint8 *p;
@@ -2410,20 +2456,17 @@ decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain,
* allocate a new JI.
*/
jinfo =
- mono_domain_alloc0_lock_free (domain, MONO_SIZEOF_JIT_INFO + (sizeof (MonoJitExceptionInfo) * (ei_len + nested_len)) + extra_size);
+ mono_domain_alloc0_lock_free (domain, mono_jit_info_size (flags, ei_len + nested_len, 0));
+ mono_jit_info_init (jinfo, method, code, code_len, flags, ei_len + nested_len, 0);
- jinfo->code_size = code_len;
jinfo->unwind_info = mono_cache_unwind_info (info.unw_info, info.unw_info_len);
- jinfo->d.method = method;
- jinfo->code_start = code;
- jinfo->domain_neutral = 0;
/* This signals that unwind_info points to a normal cached unwind info */
jinfo->from_aot = 0;
- jinfo->num_clauses = ei_len + nested_len;
+ jinfo->from_llvm = 1;
for (i = 0; i < ei_len; ++i) {
/*
- * orig_jinfo contains the original IL exception info saved by the AOT
+ * clauses contains the original IL exception info saved by the AOT
* compiler, we have to combine that with the information produced by LLVM
*/
/* The type_info entries contain IL clause indexes */
@@ -2499,7 +2542,8 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
{
int i, buf_len, num_clauses, len;
MonoJitInfo *jinfo;
- guint unwind_info, flags;
+ MonoJitInfoFlags flags = JIT_INFO_NONE;
+ guint unwind_info, eflags;
gboolean has_generic_jit_info, has_dwarf_unwind_info, has_clauses, has_seq_points, has_try_block_holes, has_arch_eh_jit_info;
gboolean from_llvm, has_gc_map;
guint8 *p;
@@ -2511,15 +2555,15 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
async = mono_thread_info_is_async_context ();
p = ex_info;
- flags = decode_value (p, &p);
- has_generic_jit_info = (flags & 1) != 0;
- has_dwarf_unwind_info = (flags & 2) != 0;
- has_clauses = (flags & 4) != 0;
- has_seq_points = (flags & 8) != 0;
- from_llvm = (flags & 16) != 0;
- has_try_block_holes = (flags & 32) != 0;
- has_gc_map = (flags & 64) != 0;
- has_arch_eh_jit_info = (flags & 128) != 0;
+ eflags = decode_value (p, &p);
+ has_generic_jit_info = (eflags & 1) != 0;
+ has_dwarf_unwind_info = (eflags & 2) != 0;
+ has_clauses = (eflags & 4) != 0;
+ has_seq_points = (eflags & 8) != 0;
+ from_llvm = (eflags & 16) != 0;
+ has_try_block_holes = (eflags & 32) != 0;
+ has_gc_map = (eflags & 64) != 0;
+ has_arch_eh_jit_info = (eflags & 128) != 0;
if (has_dwarf_unwind_info) {
unwind_info = decode_value (p, &p);
@@ -2527,13 +2571,16 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
} else {
unwind_info = decode_value (p, &p);
}
- if (has_generic_jit_info)
+ if (has_generic_jit_info) {
+ flags |= JIT_INFO_HAS_GENERIC_JIT_INFO;
generic_info_size = sizeof (MonoGenericJitInfo);
- else
+ } else {
generic_info_size = 0;
+ }
if (has_try_block_holes) {
num_holes = decode_value (p, &p);
+ flags |= JIT_INFO_HAS_TRY_BLOCK_HOLES;
try_holes_info_size = sizeof (MonoTryBlockHoleTableJitInfo) + num_holes * sizeof (MonoTryBlockHoleJitInfo);
} else {
num_holes = try_holes_info_size = 0;
@@ -2543,10 +2590,12 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
num_clauses = decode_value (p, &p);
else
num_clauses = 0;
- if (has_arch_eh_jit_info)
+ if (has_arch_eh_jit_info) {
+ flags |= JIT_INFO_HAS_ARCH_EH_INFO;
arch_eh_jit_info_size = sizeof (MonoArchEHJitInfo);
- else
+ } else {
arch_eh_jit_info_size = 0;
+ }
if (from_llvm) {
MonoJitExceptionInfo *clauses;
@@ -2579,17 +2628,16 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
}
}
- jinfo = decode_llvm_mono_eh_frame (amodule, domain, method, code, clauses, num_clauses, generic_info_size + try_holes_info_size + arch_eh_jit_info_size, nesting, &this_reg, &this_offset);
- jinfo->from_llvm = 1;
+ jinfo = decode_llvm_mono_eh_frame (amodule, domain, method, code, clauses, num_clauses, flags, nesting, &this_reg, &this_offset);
g_free (clauses);
for (i = 0; i < num_clauses; ++i)
g_slist_free (nesting [i]);
g_free (nesting);
} else {
- len = MONO_SIZEOF_JIT_INFO + (sizeof (MonoJitExceptionInfo) * num_clauses) + generic_info_size + try_holes_info_size + arch_eh_jit_info_size;
+ len = mono_jit_info_size (flags, num_clauses, num_holes);
jinfo = alloc0_jit_info_data (domain, len, async);
- jinfo->num_clauses = num_clauses;
+ mono_jit_info_init (jinfo, method, code, code_len, flags, num_clauses, num_holes);
for (i = 0; i < jinfo->num_clauses; ++i) {
MonoJitExceptionInfo *ei = &jinfo->clauses [i];
@@ -2616,25 +2664,11 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
ei->handler_start = code + decode_value (p, &p);
}
- jinfo->code_size = code_len;
jinfo->unwind_info = unwind_info;
- jinfo->d.method = method;
- jinfo->code_start = code;
jinfo->domain_neutral = 0;
jinfo->from_aot = 1;
}
- /*
- * Set all the 'has' flags, the mono_jit_info_get () functions depends on this to
- * compute the addresses of data blocks.
- */
- if (has_generic_jit_info)
- jinfo->has_generic_jit_info = 1;
- if (has_arch_eh_jit_info)
- jinfo->has_arch_eh_info = 1;
- if (has_try_block_holes)
- jinfo->has_try_block_holes = 1;
-
if (has_try_block_holes) {
MonoTryBlockHoleTableJitInfo *table;
@@ -2659,6 +2693,7 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
eh_info = mono_jit_info_get_arch_eh_info (jinfo);
eh_info->stack_size = decode_value (p, &p);
+ eh_info->epilog_size = decode_value (p, &p);
}
if (async) {
@@ -2818,8 +2853,7 @@ mono_aot_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len)
mono_aot_unlock ();
}
- /* The upper 16 bits of ji->unwind_info might contain the epilog offset */
- p = amodule->unwind_info + (ji->unwind_info & 0xffff);
+ p = amodule->unwind_info + ji->unwind_info;
*unwind_info_len = decode_value (p, &p);
return p;
}
@@ -3240,9 +3274,11 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin
case MONO_PATCH_INFO_MONITOR_ENTER:
case MONO_PATCH_INFO_MONITOR_EXIT:
case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR:
- case MONO_PATCH_INFO_CASTCLASS_CACHE:
case MONO_PATCH_INFO_JIT_TLS_ID:
break;
+ case MONO_PATCH_INFO_CASTCLASS_CACHE:
+ ji->data.index = decode_value (p, &p);
+ break;
case MONO_PATCH_INFO_RGCTX_FETCH: {
gboolean res;
MonoJumpInfoRgctxEntry *entry;
@@ -3429,8 +3465,12 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM
MonoJitInfo *jinfo = NULL;
guint8 *code, *info;
- if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE)
+ if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE) {
+ if (mono_aot_only)
+ /* The caller cannot handle this */
+ g_assert_not_reached ();
return NULL;
+ }
if ((domain != mono_get_root_domain ()) && (!(amodule->info.opts & MONO_OPT_SHARED)))
/* Non shared AOT code can't be used in other appdomains */
@@ -3761,10 +3801,13 @@ mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
MonoAotModule *amodule = klass->image->aot_module;
guint8 *code;
- if (enable_aot_cache && !amodule && klass->image == mono_defaults.corlib) {
+ if (enable_aot_cache && !amodule && domain->entry_assembly && klass->image == mono_defaults.corlib) {
/* This cannot be AOTed during startup, so do it now */
- load_aot_module (klass->image->assembly, NULL);
- amodule = klass->image->aot_module;
+ if (!mscorlib_aot_loaded) {
+ mscorlib_aot_loaded = TRUE;
+ load_aot_module (klass->image->assembly, NULL);
+ amodule = klass->image->aot_module;
+ }
}
if (!amodule)
@@ -4433,13 +4476,6 @@ mono_aot_get_trampoline (const char *name)
#include
static TrampolinePage* trampoline_pages [MONO_AOT_TRAMP_NUM];
-/* these sizes are for ARM code, parametrize if porting to other architectures (see arch_emit_specific_trampoline_pages)
- * trampoline size is assumed to be 8 bytes below as well (8 is the minimum for 32 bit archs, since we need to store
- * two pointers for trampoline in the data page).
- * the minimum for the common code must be at least sizeof(TrampolinePage), since we store the page info at the
- * beginning of the data page.
- */
-static const int trampolines_pages_code_offsets [MONO_AOT_TRAMP_NUM] = {16, 16, 72, 16};
static unsigned char*
get_new_trampoline_from_page (int tramp_type)
@@ -4528,11 +4564,7 @@ get_new_trampoline_from_page (int tramp_type)
page = (TrampolinePage*)addr;
page->next = trampoline_pages [tramp_type];
trampoline_pages [tramp_type] = page;
-#ifdef TARGET_ARM64
page->trampolines = (void*)(taddr + amodule->info.tramp_page_code_offsets [tramp_type]);
-#else
- page->trampolines = (void*)(taddr + trampolines_pages_code_offsets [tramp_type]);
-#endif
page->trampolines_end = (void*)(taddr + psize - 64);
code = page->trampolines;
page->trampolines += specific_trampoline_size;
diff --git a/mono/mini/branch-opts.c b/mono/mini/branch-opts.c
index 44a78aa476b..2be95e73642 100644
--- a/mono/mini/branch-opts.c
+++ b/mono/mini/branch-opts.c
@@ -1299,7 +1299,7 @@ mono_optimize_branches (MonoCompile *cfg)
/* branches to the following block can be removed */
if (bb->last_ins && bb->last_ins->opcode == OP_BR && !bbn->out_of_line) {
- bb->last_ins->opcode = OP_NOP;
+ NULLIFY_INS (bb->last_ins);
changed = TRUE;
if (cfg->verbose_level > 2)
g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
diff --git a/mono/mini/cpu-amd64.md b/mono/mini/cpu-amd64.md
old mode 100644
new mode 100755
index bb6f32f9e6b..be535210a6d
--- a/mono/mini/cpu-amd64.md
+++ b/mono/mini/cpu-amd64.md
@@ -114,7 +114,7 @@ cgt: dest:c len:8
cgt.un: dest:c len:8
clt: dest:c len:8
clt.un: dest:c len:8
-localloc: dest:i src1:i len:84
+localloc: dest:i src1:i len:96
compare: src1:i src2:i len:3
lcompare: src1:i src2:i len:3
icompare: src1:i src2:i len:3
@@ -511,7 +511,7 @@ vcall2_membase: src1:b len:64 clob:c
dyn_call: src1:i src2:i len:64 clob:c nacl:128
-localloc_imm: dest:i len:84
+localloc_imm: dest:i len:96
load_mem: dest:i len:16
loadi8_mem: dest:i len:16
diff --git a/mono/mini/cpu-arm.md b/mono/mini/cpu-arm.md
index 431936113c3..b31b368ec78 100644
--- a/mono/mini/cpu-arm.md
+++ b/mono/mini/cpu-arm.md
@@ -211,7 +211,7 @@ sbb_imm: dest:i src1:i len:12
br_reg: src1:i len:8
bigmul: len:8 dest:l src1:i src2:i
bigmul_un: len:8 dest:l src1:i src2:i
-tls_get: len:8 dest:i clob:c
+tls_get: len:24 dest:i clob:c
# 32 bit opcodes
int_add: dest:i src1:i src2:i len:4
diff --git a/mono/mini/cpu-arm64.md b/mono/mini/cpu-arm64.md
index 7d9e40b2266..f45b72123aa 100644
--- a/mono/mini/cpu-arm64.md
+++ b/mono/mini/cpu-arm64.md
@@ -321,9 +321,9 @@ icompare_imm: src1:i len:12
long_conv_to_ovf_i4_2: dest:i src1:i src2:i len:36
-vcall2: len:32 clob:c
-vcall2_reg: src1:i len:32 clob:c
-vcall2_membase: src1:b len:32 clob:c
+vcall2: len:40 clob:c
+vcall2_reg: src1:i len:40 clob:c
+vcall2_membase: src1:b len:40 clob:c
dyn_call: src1:i src2:i len:120 clob:c
# This is different from the original JIT opcodes
diff --git a/mono/mini/cpu-s390x.md b/mono/mini/cpu-s390x.md
index b3dce352ec6..2eee2e4e57d 100644
--- a/mono/mini/cpu-s390x.md
+++ b/mono/mini/cpu-s390x.md
@@ -283,6 +283,7 @@ long_xor: dest:i src1:i src2:i len:8
long_neg: dest:i src1:i len:6
long_not: dest:i src1:i len:12
long_rem: dest:i src1:i src2:i len:12
+long_rem_imm: dest:i src1:i src2:i len:12
long_rem_un: dest:i src1:i src2:i len:16
long_shl: dest:i src1:i src2:i len:14
long_shl_imm: dest:i src1:i len:14
diff --git a/mono/mini/debugger-agent.c b/mono/mini/debugger-agent.c
index 59194301869..63e39501fe1 100644
--- a/mono/mini/debugger-agent.c
+++ b/mono/mini/debugger-agent.c
@@ -289,7 +289,7 @@ typedef struct {
#define HEADER_LENGTH 11
#define MAJOR_VERSION 2
-#define MINOR_VERSION 36
+#define MINOR_VERSION 37
typedef enum {
CMD_SET_VM = 1,
@@ -403,7 +403,8 @@ typedef enum {
INVOKE_FLAG_DISABLE_BREAKPOINTS = 1,
INVOKE_FLAG_SINGLE_THREADED = 2,
INVOKE_FLAG_RETURN_OUT_THIS = 4,
- INVOKE_FLAG_RETURN_OUT_ARGS = 8
+ INVOKE_FLAG_RETURN_OUT_ARGS = 8,
+ INVOKE_FLAG_VIRTUAL = 16
} InvokeFlags;
typedef enum {
@@ -2776,9 +2777,6 @@ notify_thread (gpointer key, gpointer value, gpointer user_data)
#endif
/* This is _not_ equivalent to ves_icall_System_Threading_Thread_Abort () */
-#ifdef HOST_WIN32
- QueueUserAPC (notify_thread_apc, thread->handle, (ULONG_PTR)NULL);
-#else
if (mono_thread_info_new_interrupt_enabled ()) {
MonoThreadInfo *info;
MonoJitInfo *ji;
@@ -2798,6 +2796,10 @@ notify_thread (gpointer key, gpointer value, gpointer user_data)
mono_thread_info_finish_suspend_and_resume (info);
}
} else {
+#ifdef HOST_WIN32
+ // FIXME: Remove this since new interrupt is used on win32 now
+ QueueUserAPC (notify_thread_apc, thread->handle, (ULONG_PTR)NULL);
+#else
res = mono_thread_kill (thread, mono_thread_get_abort_signal ());
if (res) {
DEBUG(1, fprintf (log_file, "[%p] mono_thread_kill () failed for %p: %d...\n", (gpointer)GetCurrentThreadId (), (gpointer)tid, res));
@@ -2806,8 +2808,8 @@ notify_thread (gpointer key, gpointer value, gpointer user_data)
*/
tls->terminated = TRUE;
}
- }
#endif
+ }
}
static void
@@ -6564,6 +6566,12 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8
return ERR_INVALID_ARGUMENT;
}
m = mono_object_get_virtual_method (this, m);
+ } else if (invoke->flags & INVOKE_FLAG_VIRTUAL) {
+ if (!this) {
+ DEBUG (1, fprintf (log_file, "[%p] Error: invoke with INVOKE_FLAG_VIRTUAL flag set without this argument.\n", (gpointer)GetCurrentThreadId ()));
+ return ERR_INVALID_ARGUMENT;
+ }
+ m = mono_object_get_virtual_method (this, m);
}
DEBUG (1, fprintf (log_file, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer)GetCurrentThreadId (), mono_method_full_name (m, TRUE), this ? this->vtable->klass->name : ""));
diff --git a/mono/mini/decompose.c b/mono/mini/decompose.c
index 07242d86138..f29e913acf9 100644
--- a/mono/mini/decompose.c
+++ b/mono/mini/decompose.c
@@ -470,7 +470,7 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
}
#endif
MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
- ins->opcode = OP_NOP;
+ NULLIFY_INS (ins);
} else {
emulate = TRUE;
}
@@ -486,6 +486,9 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
ins->opcode = OP_ICONST;
MONO_INST_NULLIFY_SREGS (ins);
ins->inst_c0 = 0;
+#if __s390__
+ }
+#else
} else if ((ins->inst_imm > 0) && (ins->inst_imm < (1LL << 32)) && (power != -1)) {
gboolean is_long = ins->opcode == OP_LREM_IMM;
int compensator_reg = alloc_ireg (cfg);
@@ -497,12 +500,12 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
if (power > 1) {
intermediate_reg = compensator_reg;
- MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_IMM : OP_SHR_IMM, intermediate_reg, ins->sreg1, is_long ? 63 : 31);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_IMM : OP_ISHR_IMM, intermediate_reg, ins->sreg1, is_long ? 63 : 31);
} else {
intermediate_reg = ins->sreg1;
}
- MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_UN_IMM : OP_SHR_UN_IMM, compensator_reg, intermediate_reg, (is_long ? 64 : 32) - power);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_UN_IMM : OP_ISHR_UN_IMM, compensator_reg, intermediate_reg, (is_long ? 64 : 32) - power);
MONO_EMIT_NEW_BIALU (cfg, is_long ? OP_LADD : OP_IADD, ins->dreg, ins->sreg1, compensator_reg);
/* Compute remainder */
MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LAND_IMM : OP_AND_IMM, ins->dreg, ins->dreg, (1 << power) - 1);
@@ -511,6 +514,7 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
NULLIFY_INS (ins);
}
+#endif
break;
}
@@ -980,7 +984,7 @@ mono_decompose_long_opts (MonoCompile *cfg)
MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
- next->opcode = OP_NOP;
+ NULLIFY_INS (next);
break;
}
case OP_LBGE:
@@ -998,7 +1002,7 @@ mono_decompose_long_opts (MonoCompile *cfg)
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
- next->opcode = OP_NOP;
+ NULLIFY_INS (next);
break;
case OP_LCEQ: {
int d1, d2;
@@ -1012,7 +1016,7 @@ mono_decompose_long_opts (MonoCompile *cfg)
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
- next->opcode = OP_NOP;
+ NULLIFY_INS (next);
break;
}
case OP_LCLT:
@@ -1034,7 +1038,7 @@ mono_decompose_long_opts (MonoCompile *cfg)
MONO_START_BB (cfg, set_to_1);
MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
MONO_START_BB (cfg, set_to_0);
- next->opcode = OP_NOP;
+ NULLIFY_INS (next);
break;
}
default:
@@ -1066,7 +1070,7 @@ mono_decompose_long_opts (MonoCompile *cfg)
MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
- next->opcode = OP_NOP;
+ NULLIFY_INS (next);
break;
}
@@ -1085,7 +1089,7 @@ mono_decompose_long_opts (MonoCompile *cfg)
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
- next->opcode = OP_NOP;
+ NULLIFY_INS (next);
break;
case OP_LCEQ: {
int d1, d2;
@@ -1099,7 +1103,7 @@ mono_decompose_long_opts (MonoCompile *cfg)
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
- next->opcode = OP_NOP;
+ NULLIFY_INS (next);
break;
}
case OP_LCLT:
@@ -1121,7 +1125,7 @@ mono_decompose_long_opts (MonoCompile *cfg)
MONO_START_BB (cfg, set_to_1);
MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
MONO_START_BB (cfg, set_to_0);
- next->opcode = OP_NOP;
+ NULLIFY_INS (next);
break;
}
default:
@@ -1330,18 +1334,18 @@ mono_decompose_vtype_opts (MonoCompile *cfg)
if (call->vret_in_reg) {
MonoCallInst *call2;
- /* Replace the vcall with an integer call */
+ /* Replace the vcall with a scalar call */
MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
memcpy (call2, call, sizeof (MonoCallInst));
switch (ins->opcode) {
case OP_VCALL:
- call2->inst.opcode = OP_CALL;
+ call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
break;
case OP_VCALL_REG:
- call2->inst.opcode = OP_CALL_REG;
+ call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
break;
case OP_VCALL_MEMBASE:
- call2->inst.opcode = OP_CALL_MEMBASE;
+ call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
break;
}
call2->inst.dreg = alloc_preg (cfg);
@@ -1367,12 +1371,19 @@ mono_decompose_vtype_opts (MonoCompile *cfg)
break;
case 3:
case 4:
- MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
+ if (call->vret_in_reg_fp)
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
+ else
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
break;
case 5:
case 6:
case 7:
case 8:
+ if (call->vret_in_reg_fp) {
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
+ break;
+ }
#if SIZEOF_REGISTER == 4
/*
FIXME Other ABIs might return in different regs than the ones used for LCALL.
diff --git a/mono/mini/driver.c b/mono/mini/driver.c
index 2929e813a4d..c6c8e20628c 100644
--- a/mono/mini/driver.c
+++ b/mono/mini/driver.c
@@ -408,8 +408,7 @@ mini_regression_step (MonoImage *image, int verbose, int *total_run, int *total,
} else {
cfailed++;
- if (verbose)
- g_print ("Test '%s' failed compilation.\n", method->name);
+ g_print ("Test '%s' failed compilation.\n", method->name);
}
if (mini_stats_fd)
fprintf (mini_stats_fd, "%f, ",
@@ -1903,6 +1902,14 @@ mono_main (int argc, char* argv[])
mono_load_coree (argv [i]);
#endif
+ /* Set rootdir before loading config */
+ mono_set_rootdir ();
+
+ /* Parse gac loading options before loading assemblies. */
+ if (mono_compile_aot || action == DO_EXEC || action == DO_DEBUGGER) {
+ mono_config_parse (config_file);
+ }
+
mono_set_defaults (mini_verbose, opt);
domain = mini_init (argv [i], forced_version);
@@ -1968,11 +1975,6 @@ mono_main (int argc, char* argv[])
break;
}
- /* Parse gac loading options before loading assemblies. */
- if (mono_compile_aot || action == DO_EXEC || action == DO_DEBUGGER) {
- mono_config_parse (config_file);
- }
-
#ifdef MONO_JIT_INFO_TABLE_TEST
if (test_jit_info_table)
jit_info_table_test (domain);
diff --git a/mono/mini/dwarfwriter.c b/mono/mini/dwarfwriter.c
index 9f68a62683e..67585763b69 100644
--- a/mono/mini/dwarfwriter.c
+++ b/mono/mini/dwarfwriter.c
@@ -1376,6 +1376,7 @@ static const guint8 *token_handler_ip;
static char*
token_handler (MonoDisHelper *dh, MonoMethod *method, guint32 token)
{
+ MonoError error;
char *res, *desc;
MonoMethod *cmethod;
MonoClass *klass;
@@ -1389,10 +1390,12 @@ token_handler (MonoDisHelper *dh, MonoMethod *method, guint32 token)
case CEE_ISINST:
case CEE_CASTCLASS:
case CEE_LDELEMA:
- if (method->wrapper_type)
+ if (method->wrapper_type) {
klass = data;
- else
- klass = mono_class_get_full (method->klass->image, token, NULL);
+ } else {
+ klass = mono_class_get_checked (method->klass->image, token, &error);
+ g_assert (mono_error_ok (&error)); /* FIXME error handling */
+ }
res = g_strdup_printf ("<%s>", klass->name);
break;
case CEE_NEWOBJ:
diff --git a/mono/mini/exceptions-amd64.c b/mono/mini/exceptions-amd64.c
index 2a253a8cef8..a0865b7e2b6 100644
--- a/mono/mini/exceptions-amd64.c
+++ b/mono/mini/exceptions-amd64.c
@@ -45,7 +45,7 @@ LPTOP_LEVEL_EXCEPTION_FILTER mono_old_win_toplevel_exception_filter;
void *mono_win_vectored_exception_handle;
#define W32_SEH_HANDLE_EX(_ex) \
- if (_ex##_handler) _ex##_handler(0, ep, sctx)
+ if (_ex##_handler) _ex##_handler(0, ep, ctx)
static LONG CALLBACK seh_unhandled_exception_filter(EXCEPTION_POINTERS* ep)
{
@@ -68,7 +68,6 @@ static LONG CALLBACK seh_vectored_exception_handler(EXCEPTION_POINTERS* ep)
{
EXCEPTION_RECORD* er;
CONTEXT* ctx;
- MonoContext* sctx;
LONG res;
MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
@@ -81,22 +80,6 @@ static LONG CALLBACK seh_vectored_exception_handler(EXCEPTION_POINTERS* ep)
er = ep->ExceptionRecord;
ctx = ep->ContextRecord;
- sctx = g_malloc(sizeof(MonoContext));
-
- /* Copy Win32 context to UNIX style context */
- sctx->rax = ctx->Rax;
- sctx->rbx = ctx->Rbx;
- sctx->rcx = ctx->Rcx;
- sctx->rdx = ctx->Rdx;
- sctx->rbp = ctx->Rbp;
- sctx->rsp = ctx->Rsp;
- sctx->rsi = ctx->Rsi;
- sctx->rdi = ctx->Rdi;
- sctx->rip = ctx->Rip;
- sctx->r12 = ctx->R12;
- sctx->r13 = ctx->R13;
- sctx->r14 = ctx->R14;
- sctx->r15 = ctx->R15;
switch (er->ExceptionCode) {
case EXCEPTION_ACCESS_VIOLATION:
@@ -126,30 +109,8 @@ static LONG CALLBACK seh_vectored_exception_handler(EXCEPTION_POINTERS* ep)
* can correctly chain the exception.
*/
res = EXCEPTION_CONTINUE_SEARCH;
- } else {
- /* Copy context back */
- /* Nonvolatile */
- ctx->Rsp = sctx->rsp;
- ctx->Rdi = sctx->rdi;
- ctx->Rsi = sctx->rsi;
- ctx->Rbx = sctx->rbx;
- ctx->Rbp = sctx->rbp;
- ctx->R12 = sctx->r12;
- ctx->R13 = sctx->r13;
- ctx->R14 = sctx->r14;
- ctx->R15 = sctx->r15;
- ctx->Rip = sctx->rip;
-
- /* Volatile But should not matter?*/
- ctx->Rax = sctx->rax;
- ctx->Rcx = sctx->rcx;
- ctx->Rdx = sctx->rdx;
}
- /* TODO: Find right place to free this in stack overflow case */
- if (er->ExceptionCode != EXCEPTION_STACK_OVERFLOW)
- g_free (sctx);
-
return res;
}
@@ -591,7 +552,7 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls,
guint8 *cfa;
guint32 unwind_info_len;
guint8 *unwind_info;
- guint8 *epilog;
+ guint8 *epilog = NULL;
frame->type = FRAME_TYPE_MANAGED;
@@ -604,7 +565,9 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls,
printf ("%s %p %p\n", ji->d.method->name, ji->code_start, ip);
mono_print_unwind_info (unwind_info, unwind_info_len);
*/
- epilog = (guint8*)ji->code_start + ji->code_size - (ji->unwind_info >> 16);
+ /* LLVM compiled code doesn't have this info */
+ if (ji->has_arch_eh_info)
+ epilog = (guint8*)ji->code_start + ji->code_size - mono_jinfo_get_epilog_size (ji);
regs [AMD64_RAX] = new_ctx->rax;
regs [AMD64_RBX] = new_ctx->rbx;
@@ -622,7 +585,7 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls,
mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start,
(guint8*)ji->code_start + ji->code_size,
- ip, &epilog, regs, MONO_MAX_IREGS + 1,
+ ip, epilog ? &epilog : NULL, regs, MONO_MAX_IREGS + 1,
save_locations, MONO_MAX_IREGS, &cfa);
new_ctx->rax = regs [AMD64_RAX];
@@ -645,12 +608,6 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls,
/* Adjust IP */
new_ctx->rip --;
-#ifndef MONO_AMD64_NO_PUSHES
- /* Pop arguments off the stack */
- if (ji->has_arch_eh_info)
- new_ctx->rsp += mono_jit_info_get_arch_eh_info (ji)->stack_size;
-#endif
-
return TRUE;
} else if (*lmf) {
guint64 rip;
@@ -841,6 +798,8 @@ mono_arch_ip_from_context (void *sigctx)
ucontext_t *ctx = (ucontext_t*)sigctx;
return (gpointer)UCONTEXT_REG_RIP (ctx);
+#elif defined(HOST_WIN32)
+ return ((CONTEXT*)sigctx)->Rip;
#else
MonoContext *ctx = sigctx;
return (gpointer)ctx->rip;
@@ -1062,10 +1021,17 @@ static gpointer throw_pending_exception;
* exception.
*/
void
-mono_arch_notify_pending_exc (void)
+mono_arch_notify_pending_exc (MonoThreadInfo *info)
{
MonoLMF *lmf = mono_get_lmf ();
+ if (!info) {
+ lmf = mono_get_lmf ();
+ } else {
+ g_assert (info->suspend_state.valid);
+ lmf = info->suspend_state.unwind_data [MONO_UNWIND_DATA_LMF];
+ }
+
if (!lmf)
/* Not yet started */
return;
diff --git a/mono/mini/exceptions-arm.c b/mono/mini/exceptions-arm.c
index d7fd3318f3d..e39248ceda1 100644
--- a/mono/mini/exceptions-arm.c
+++ b/mono/mini/exceptions-arm.c
@@ -36,6 +36,7 @@
#include "mini.h"
#include "mini-arm.h"
#include "mono/utils/mono-sigcontext.h"
+#include "mono/utils/mono-compiler.h"
/*
* arch_get_restore_context:
@@ -536,10 +537,7 @@ handle_signal_exception (gpointer obj)
* This works around a gcc 4.5 bug:
* https://bugs.launchpad.net/ubuntu/+source/gcc-4.5/+bug/721531
*/
-#if defined(__GNUC__)
-__attribute__((noinline))
-#endif
-static gpointer
+static MONO_NEVER_INLINE gpointer
get_handle_signal_exception_addr (void)
{
return handle_signal_exception;
diff --git a/mono/mini/exceptions-x86.c b/mono/mini/exceptions-x86.c
old mode 100644
new mode 100755
index d335d7ea5c6..615b3f2371f
--- a/mono/mini/exceptions-x86.c
+++ b/mono/mini/exceptions-x86.c
@@ -49,7 +49,7 @@ extern int (*gUnhandledExceptionHandler)(EXCEPTION_POINTERS*);
#endif
#define W32_SEH_HANDLE_EX(_ex) \
- if (_ex##_handler) _ex##_handler(0, ep, sctx)
+ if (_ex##_handler) _ex##_handler(0, ep, ctx)
LONG CALLBACK seh_unhandled_exception_filter(EXCEPTION_POINTERS* ep)
{
@@ -189,7 +189,6 @@ LONG CALLBACK seh_vectored_exception_handler(EXCEPTION_POINTERS* ep)
{
EXCEPTION_RECORD* er;
CONTEXT* ctx;
- struct sigcontext* sctx;
LONG res;
MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
@@ -202,22 +201,10 @@ LONG CALLBACK seh_vectored_exception_handler(EXCEPTION_POINTERS* ep)
er = ep->ExceptionRecord;
ctx = ep->ContextRecord;
- sctx = g_malloc(sizeof(struct sigcontext));
-
- /* Copy Win32 context to UNIX style context */
- sctx->eax = ctx->Eax;
- sctx->ebx = ctx->Ebx;
- sctx->ecx = ctx->Ecx;
- sctx->edx = ctx->Edx;
- sctx->ebp = ctx->Ebp;
- sctx->esp = ctx->Esp;
- sctx->esi = ctx->Esi;
- sctx->edi = ctx->Edi;
- sctx->eip = ctx->Eip;
switch (er->ExceptionCode) {
case EXCEPTION_STACK_OVERFLOW:
- win32_handle_stack_overflow (ep, sctx);
+ win32_handle_stack_overflow (ep, ctx);
break;
case EXCEPTION_ACCESS_VIOLATION:
W32_SEH_HANDLE_EX(segv);
@@ -246,23 +233,8 @@ LONG CALLBACK seh_vectored_exception_handler(EXCEPTION_POINTERS* ep)
* can correctly chain the exception.
*/
res = EXCEPTION_CONTINUE_SEARCH;
- } else {
- /* Copy context back */
- ctx->Eax = sctx->eax;
- ctx->Ebx = sctx->ebx;
- ctx->Ecx = sctx->ecx;
- ctx->Edx = sctx->edx;
- ctx->Ebp = sctx->ebp;
- ctx->Esp = sctx->esp;
- ctx->Esi = sctx->esi;
- ctx->Edi = sctx->edi;
- ctx->Eip = sctx->eip;
}
- /* TODO: Find right place to free this in stack overflow case */
- if (er->ExceptionCode != EXCEPTION_STACK_OVERFLOW)
- g_free (sctx);
-
return res;
}
@@ -278,8 +250,9 @@ void win32_seh_init()
void win32_seh_cleanup()
{
- if (mono_old_win_toplevel_exception_filter) SetUnhandledExceptionFilter(mono_old_win_toplevel_exception_filter);
- RemoveVectoredExceptionHandler (seh_unhandled_exception_filter);
+ if (mono_old_win_toplevel_exception_filter)
+ SetUnhandledExceptionFilter(mono_old_win_toplevel_exception_filter);
+ RemoveVectoredExceptionHandler (mono_win_vectored_exception_handle);
}
void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler)
@@ -835,29 +808,6 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls,
/* Adjust IP */
new_ctx->eip --;
-
-#ifndef MONO_X86_NO_PUSHES
- /* Pop arguments off the stack */
- if (ji->has_arch_eh_info) {
- int stack_size;
-
- stack_size = mono_jit_info_get_arch_eh_info (ji)->stack_size;
-
- if (stack_size) {
-#ifdef ENABLE_LLVM
- MonoJitInfo *caller_ji;
-
- caller_ji = mini_jit_info_table_find (domain, (char*)new_ctx->eip, NULL);
- /* LLVM doesn't push the arguments */
- if (caller_ji && !caller_ji->from_llvm)
- new_ctx->esp += stack_size;
-#else
- new_ctx->esp += stack_size;
-#endif
- }
- }
-#endif
-
return TRUE;
} else if (*lmf) {
@@ -952,15 +902,15 @@ mono_arch_ip_from_context (void *sigctx)
#if defined(__native_client__)
printf("WARNING: mono_arch_ip_from_context() called!\n");
return (NULL);
-#else
-#ifdef MONO_ARCH_USE_SIGACTION
+#elif defined(MONO_ARCH_USE_SIGACTION)
ucontext_t *ctx = (ucontext_t*)sigctx;
return (gpointer)UCONTEXT_REG_EIP (ctx);
+#elif defined(HOST_WIN32)
+ return ((CONTEXT*)sigctx)->Eip;
#else
struct sigcontext *ctx = sigctx;
return (gpointer)ctx->SC_EIP;
#endif
-#endif /* __native_client__ */
}
/*
diff --git a/mono/mini/generics.cs b/mono/mini/generics.cs
index cdf7b36ef68..f350710c76e 100644
--- a/mono/mini/generics.cs
+++ b/mono/mini/generics.cs
@@ -913,6 +913,7 @@ public Type getInstance() {
}
}
+ [Category ("GSHAREDVT")]
static int test_0_synchronized_gshared () {
var c = new SyncClass ();
if (c.getInstance () != typeof (string))
@@ -1088,6 +1089,36 @@ public static int test_0_delegate_callvirt_fullaot () {
var s = f2 (f);
return s == "A" ? 0 : 1;
}
+
+ public interface ICovariant
+ {
+ }
+
+ // Deleting the `out` modifier from this line stop the problem
+ public interface IExtCovariant : ICovariant
+ {
+ }
+
+ public class Sample : ICovariant
+ {
+ }
+
+ public interface IMyInterface
+ {
+ }
+
+ public static int test_0_variant_cast_cache () {
+ object covariant = new Sample();
+
+ var foo = (ICovariant)(covariant);
+
+ try {
+ var extCovariant = (IExtCovariant)covariant;
+ return 1;
+ } catch {
+ return 0;
+ }
+ }
}
#if !MOBILE
diff --git a/mono/mini/gshared.cs b/mono/mini/gshared.cs
index 27149e9085d..d0ee4fac40d 100644
--- a/mono/mini/gshared.cs
+++ b/mono/mini/gshared.cs
@@ -944,6 +944,47 @@ public static int test_0_virtual_generic () {
return 0;
}
+ public interface IFace1 {
+ void m1 ();
+ void m2 ();
+ void m3 ();
+ void m4 ();
+ void m5 ();
+ }
+
+ public class ClassIFace : IFace1 {
+ public void m1 () {
+ }
+ public void m2 () {
+ }
+ public void m3 () {
+ }
+ public void m4 () {
+ }
+ public void m5 () {
+ }
+ }
+
+ interface IFaceIFaceCall {
+ void call (IFace1