Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

11
samples/Makefile.am Normal file
View File

@@ -0,0 +1,11 @@
dist-hook:
mkdir $(distdir)/embed
mkdir $(distdir)/profiler
mkdir $(distdir)/size
cp $(srcdir)/profiler/sample.c $(distdir)/profiler
cp $(srcdir)/embed/test.cs $(srcdir)/embed/teste.c $(distdir)/embed
cp $(srcdir)/embed/test-metadata.c $(distdir)/embed
cp $(srcdir)/embed/test-invoke.c $(srcdir)/embed/invoke.cs $(distdir)/embed
cp $(srcdir)/size/sample.cs $(srcdir)/size/objectinspector.cs $(distdir)/size
cp $(srcdir)/size/size.c $(srcdir)/size/Makefile $(srcdir)/size/README $(distdir)/size

527
samples/Makefile.in Normal file

File diff suppressed because it is too large Load Diff

50
samples/embed/invoke.cs Normal file
View File

@@ -0,0 +1,50 @@
using System;
namespace Embed {
class MyType {
int val = 5;
string str = "hello";
MyType () {
Console.WriteLine ("In ctor val is: {0}", val);
Console.WriteLine ("In ctor str is: {0}", str);
}
MyType (int v, byte[] array) {
Console.WriteLine ("In ctor (int, byte[]) got value: {0}, array len: {1}", v, array.Length);
}
void method () {
Console.WriteLine ("In method val is {0}", val);
Console.WriteLine ("In method str is: {0}", str);
}
int Value {
get {
return val;
}
}
string Message {
get {
return str;
}
}
void Values (ref int v, ref string s) {
Console.WriteLine ("In Values () v is {0}", v);
Console.WriteLine ("In Values () s is: {0}", s);
v = val;
s = str;
}
static void Fail () {
throw new Exception ();
}
static void Main () {
/* we do nothing here... */
}
}
}

343
samples/embed/test-invoke.c Normal file
View File

@@ -0,0 +1,343 @@
#include <mono/jit/jit.h>
#include <mono/metadata/object.h>
#include <mono/metadata/environment.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/debug-helpers.h>
#include <string.h>
#include <stdlib.h>
#ifndef FALSE
#define FALSE 0
#endif
/*
* Simple mono embedding example.
* We show how to create objects and invoke methods and set fields in them.
* Compile with:
* gcc -Wall -o test-invoke test-invoke.c `pkg-config --cflags --libs mono-2` -lm
* mcs invoke.cs
* Run with:
* ./test-invoke invoke.exe
*/
static void
access_valuetype_field (MonoObject *obj)
{
MonoClass *klass;
MonoClassField *field;
int val;
klass = mono_object_get_class (obj);
/* Now we'll change the value of the 'val' field (see invoke.cs) */
field = mono_class_get_field_from_name (klass, "val");
/* This time we also add a bit of error checking... */
if (!field) {
fprintf (stderr, "Can't find field val in MyType\n");
exit (1);
}
/* Check that val is an int (if you're paranoid or if you need to
* show how this API is used)
*/
if (mono_type_get_type (mono_field_get_type (field)) != MONO_TYPE_I4) {
fprintf (stderr, "Field val is not a 32 bit integer\n");
exit (1);
}
/* Note we pass a pointer to the value */
mono_field_get_value (obj, field, &val);
printf ("Value of field is: %d\n", val);
val = 10;
/* Note we pass a pointer to the value here as well */
mono_field_set_value (obj, field, &val);
}
static void
access_reference_field (MonoObject *obj)
{
MonoClass *klass;
MonoDomain *domain;
MonoClassField *str;
MonoString *strval;
char *p;
klass = mono_object_get_class (obj);
domain = mono_object_get_domain (obj);
/* Now we'll see that a reference type is handled slightly differently.
* First, get the MonoClassField representing it.
*/
str = mono_class_get_field_from_name (klass, "str");
/* No change here, we always pass a pointer */
mono_field_get_value (obj, str, &strval);
/* get the string in UTF-8 encoding to print it */
p = mono_string_to_utf8 (strval);
printf ("Value of str is: %s\n", p);
/* we need to free the result from mono_string_to_utf8 () */
mono_free (p);
/* string are immutable, so we need to create a different string */
strval = mono_string_new (domain, "hello from the embedding API");
/* Here is the slight difference: for reference types we pass
* the pointer directly, instead of a pointer to the value.
*/
mono_field_set_value (obj, str, strval);
}
/* Demostrate how to call methods */
static void
call_methods (MonoObject *obj)
{
MonoClass *klass;
MonoDomain *domain;
MonoMethod *method = NULL, *m = NULL, *ctor = NULL, *fail = NULL, *mvalues;
MonoProperty *prop;
MonoObject *result, *exception;
MonoString *str;
char *p;
void* iter;
void* args [2];
int val;
klass = mono_object_get_class (obj);
domain = mono_object_get_domain (obj);
/* retrieve all the methods we need */
iter = NULL;
while ((m = mono_class_get_methods (klass, &iter))) {
if (strcmp (mono_method_get_name (m), "method") == 0) {
method = m;
} else if (strcmp (mono_method_get_name (m), "Fail") == 0) {
fail = m;
} else if (strcmp (mono_method_get_name (m), "Values") == 0) {
mvalues = m;
} else if (strcmp (mono_method_get_name (m), ".ctor") == 0) {
/* Check it's the ctor that takes two args:
* as you see a contrsuctor is a method like any other.
*/
MonoMethodSignature * sig = mono_method_signature (m);
if (mono_signature_get_param_count (sig) == 2) {
ctor = m;
}
}
}
/* Now we'll call method () on obj: since it takes no arguments
* we can pass NULL as the third argument to mono_runtime_invoke ().
* The method will print the updated value.
*/
mono_runtime_invoke (method, obj, NULL, NULL);
/* mono_object_new () doesn't call any constructor: this means that
* we'll have to invoke the constructor if needed ourselves. Note:
* invoking a constructor is no different than calling any other method,
* so we'll still call mono_runtime_invoke (). This also means that we
* can invoke a constructor at any time, like now.
* First, setup the array of arguments and their values.
*/
/* As usual, we use the address of the data for valuetype arguments */
val = 7;
args [0] = &val;
/* and the pointer for reference types: mono_array_new () returns a MonoArray* */
args [1] = mono_array_new (domain, mono_get_byte_class (), 256);
mono_runtime_invoke (ctor, obj, args, NULL);
/* A property exists only as a metadata entity, so getting or setting the value
* is nothing more than calling mono_runtime_invoke () on the getter or setter method.
*/
prop = mono_class_get_property_from_name (klass, "Value");
method = mono_property_get_get_method (prop);
result = mono_runtime_invoke (method, obj, NULL, NULL);
/* mono_runtime_invoke () always boxes the return value if it's a valuetype */
val = *(int*)mono_object_unbox (result);
printf ("Value of val from property is: %d\n", val);
/* we also have an helper method: note that reference types are returned as is */
prop = mono_class_get_property_from_name (klass, "Message");
str = (MonoString*)mono_property_get_value (prop, obj, NULL, NULL);
/* get the string in UTF-8 encoding to print it */
p = mono_string_to_utf8 (str);
printf ("Value of str from property is: %s\n", p);
/* we need to free the result from mono_string_to_utf8 () */
mono_free (p);
/* Now we'll show two things:
* 1) static methods are invoked with mono_runtime_invoke () as well,
* we just pass NULL as the second argument.
* 2) we can catch exceptions thrown by the called method.
* Note: fail is declared as static void Fail () in invoke.cs.
* We first set result to NULL: if after the invocation it will have
* a different value, it will be the exception that was thrown from
* the Fail () method. Note that if an exception was thrown, the return
* value (if any) is undefined and can't be used in any way (yes, the above
* invocations don't have this type of error checking to make things simpler).
*/
exception = NULL;
mono_runtime_invoke (fail, NULL, NULL, &exception);
if (exception) {
printf ("An exception was thrown in Fail ()\n");
}
/* Now let's see how to handle methods that take by ref arguments:
* Valuetypes continue to be passed as pointers to the data.
* Reference arguments passed by ref (ref or out is the same)
* are handled the same way: a pointer to the pointer is used
* (so that the result can be read back).
* Small note: in this case (a System.Int32 valuetype) we can just
* use &val where val is a C 32 bit integer. In the general case
* unmanaged code doesn't know the size of a valuetype, since the
* runtime may decide to lay it out in what it thinks is a better way
* (unless ExplicitLayout is set). To avoid issues, the best thing is to
* create an object of the valuetype's class and retrieve the pointer
* to the data with the mono_object_unbox () function.
*/
val = 100;
str = mono_string_new (domain, "another string");
args [0] = &val;
args [1] = &str;
mono_runtime_invoke (mvalues, obj, args, NULL);
/* get the string in UTF-8 encoding to print it */
p = mono_string_to_utf8 (str);
printf ("Values of str/val from Values () are: %s/%d\n", p, val);
/* we need to free the result from mono_string_to_utf8 () */
mono_free (p);
}
static void
more_methods (MonoDomain *domain)
{
MonoClass *klass;
MonoMethodDesc* mdesc;
MonoMethod *method, *vtmethod;
MonoString *str;
MonoObject *obj;
char *p;
int val;
/* Now let's call an instance method on a valuetype. There are two
* different case:
* 1) calling a virtual method defined in a base class, like ToString ():
* we need to pass the value boxed in an object
* 2) calling a normal instance method: in this case
* we pass the address to the valuetype as the second argument
* instead of an object.
* First some initialization.
*/
val = 25;
klass = mono_get_int32_class ();
obj = mono_value_box (domain, klass, &val);
/* A different way to search for a method */
mdesc = mono_method_desc_new (":ToString()", FALSE);
vtmethod = mono_method_desc_search_in_class (mdesc, klass);
str = (MonoString*)mono_runtime_invoke (vtmethod, &val, NULL, NULL);
/* get the string in UTF-8 encoding to print it */
p = mono_string_to_utf8 (str);
printf ("25.ToString (): %s\n", p);
/* we need to free the result from mono_string_to_utf8 () */
mono_free (p);
/* Now: see how the result is different if we search for the ToString ()
* method in System.Object: mono_runtime_invoke () doesn't do any sort of
* virtual method invocation: it calls the exact method that it was given
* to execute. If a virtual call is needed, mono_object_get_virtual_method ()
* can be called.
*/
method = mono_method_desc_search_in_class (mdesc, mono_get_object_class ());
str = (MonoString*)mono_runtime_invoke (method, obj, NULL, NULL);
/* get the string in UTF-8 encoding to print it */
p = mono_string_to_utf8 (str);
printf ("25.ToString (), from System.Object: %s\n", p);
/* we need to free the result from mono_string_to_utf8 () */
mono_free (p);
/* Now get the method that overrides ToString () in obj */
vtmethod = mono_object_get_virtual_method (obj, method);
if (mono_class_is_valuetype (mono_method_get_class (vtmethod))) {
printf ("Need to unbox this for call to virtual ToString () for %s\n", mono_class_get_name (klass));
}
mono_method_desc_free (mdesc);
}
static void
create_object (MonoDomain *domain, MonoImage *image)
{
MonoClass *klass;
MonoObject *obj;
klass = mono_class_from_name (image, "Embed", "MyType");
if (!klass) {
fprintf (stderr, "Can't find MyType in assembly %s\n", mono_image_get_filename (image));
exit (1);
}
obj = mono_object_new (domain, klass);
/* mono_object_new () only allocates the storage:
* it doesn't run any constructor. Tell the runtime to run
* the default argumentless constructor.
*/
mono_runtime_object_init (obj);
access_valuetype_field (obj);
access_reference_field (obj);
call_methods (obj);
more_methods (domain);
}
static void main_function (MonoDomain *domain, const char *file, int argc, char **argv)
{
MonoAssembly *assembly;
/* Loading an assembly makes the runtime setup everything
* needed to execute it. If we're just interested in the metadata
* we'd use mono_image_load (), instead and we'd get a MonoImage*.
*/
assembly = mono_domain_assembly_open (domain, file);
if (!assembly)
exit (2);
/*
* mono_jit_exec() will run the Main() method in the assembly.
* The return value needs to be looked up from
* System.Environment.ExitCode.
*/
mono_jit_exec (domain, assembly, argc, argv);
create_object (domain, mono_assembly_get_image (assembly));
}
int
main (int argc, char* argv[]) {
MonoDomain *domain;
const char *file;
int retval;
if (argc < 2){
fprintf (stderr, "Please provide an assembly to load\n");
return 1;
}
file = argv [1];
/*
* mono_jit_init() creates a domain: each assembly is
* loaded and run in a MonoDomain.
*/
domain = mono_jit_init (file);
main_function (domain, file, argc - 1, argv + 1);
retval = mono_environment_exitcode_get ();
mono_jit_cleanup (domain);
return retval;
}

View File

@@ -0,0 +1,133 @@
#include <mono/jit/jit.h>
#include <glib.h>
/*
* Very simple mono embedding example.
* This sample shows how to access metadata elements from an image.
* Compile with:
* gcc -o test-metadata test-metadata.c `pkg-config --cflags --libs mono-2` -lm
* Run with:
* ./test-metadata namespace name
*/
void
output_desc (MonoClass* klass) {
printf ("Class name: %s.%s\n", mono_class_get_namespace (klass), mono_class_get_name (klass));
printf ("Rank: %d, flags 0x%0x\n", mono_class_get_rank (klass), mono_class_get_flags (klass));
}
void
output_ifaces (MonoClass* klass) {
MonoClass *iface;
gpointer iter = NULL;
printf ("Implements: ");
while ((iface = mono_class_get_interfaces (klass, &iter))) {
printf ("%s ", mono_class_get_name (iface));
}
printf ("\n");
}
void
output_nested (MonoClass* klass) {
MonoClass *nested;
gpointer iter = NULL;
printf ("Has nested types: ");
while ((nested = mono_class_get_nested_types (klass, &iter))) {
printf ("%s ", mono_class_get_name (nested));
}
printf ("\n");
}
void
output_fields (MonoClass* klass) {
MonoClassField *field;
gpointer iter = NULL;
while ((field = mono_class_get_fields (klass, &iter))) {
printf ("Field: %s, flags 0x%x\n", mono_field_get_name (field),
mono_field_get_flags (field));
}
}
void
output_methods (MonoClass* klass) {
MonoMethod *method;
gpointer iter = NULL;
while ((method = mono_class_get_methods (klass, &iter))) {
guint32 flags, iflags;
flags = mono_method_get_flags (method, &iflags);
printf ("Method: %s, flags 0x%x, iflags 0x%x\n",
mono_method_get_name (method), flags, iflags);
}
}
void
output_properties (MonoClass* klass) {
MonoProperty *prop;
gpointer iter = NULL;
while ((prop = mono_class_get_properties (klass, &iter))) {
printf ("Property: %s, flags 0x%x\n", mono_property_get_name (prop),
mono_property_get_flags (prop));
}
}
void
output_events (MonoClass* klass) {
MonoEvent *event;
gpointer iter = NULL;
while ((event = mono_class_get_events (klass, &iter))) {
printf ("Event: %s, flags: 0x%x\n", mono_event_get_name (event),
mono_event_get_flags (event));
}
}
int
main (int argc, char* argv[]) {
MonoDomain *domain;
MonoClass *klass;
MonoImage *image;
const char *ns, *name;
if (argc < 3){
fprintf (stderr, "Please provide namespace and name of a type in mscorlib.\n");
return 1;
}
ns = argv [1];
name = argv [2];
/*
* mono_jit_init() creates a domain: each assembly is
* loaded and run in a MonoDomain.
*/
domain = mono_jit_init (argv [0]);
if (argc > 3) {
MonoImageOpenStatus status;
image = mono_image_open (argv [3], &status);
if (!image) {
fprintf (stderr, "Can't load assembly \"%s\".\n", argv [3]);
return 1;
}
} else {
/* we default to using mscorlib */
image = mono_get_corlib ();
}
klass = mono_class_from_name (image, ns, name);
if (!klass) {
fprintf (stderr, "Class \"%s.%s\" not found.\n", ns, name);
return 1;
}
output_desc (klass);
output_ifaces (klass);
output_nested (klass);
output_fields (klass);
output_methods (klass);
output_properties (klass);
output_events (klass);
mono_jit_cleanup (domain);
return 0;
}

11
samples/embed/test.cs Normal file
View File

@@ -0,0 +1,11 @@
using System;
using System.Runtime.CompilerServices;
class MonoEmbed {
[MethodImplAttribute(MethodImplOptions.InternalCall)]
extern static string gimme();
static void Main() {
Console.WriteLine (gimme ());
}
}

71
samples/embed/teste.c Normal file
View File

@@ -0,0 +1,71 @@
#include <mono/jit/jit.h>
#include <mono/metadata/environment.h>
#include <stdlib.h>
/*
* Very simple mono embedding example.
* Compile with:
* gcc -o teste teste.c `pkg-config --cflags --libs mono-2` -lm
* mcs test.cs
* Run with:
* ./teste test.exe
*/
static MonoString*
gimme () {
return mono_string_new (mono_domain_get (), "All your monos are belong to us!");
}
static void main_function (MonoDomain *domain, const char *file, int argc, char** argv)
{
MonoAssembly *assembly;
assembly = mono_domain_assembly_open (domain, file);
if (!assembly)
exit (2);
/*
* mono_jit_exec() will run the Main() method in the assembly.
* The return value needs to be looked up from
* System.Environment.ExitCode.
*/
mono_jit_exec (domain, assembly, argc, argv);
}
int
main(int argc, char* argv[]) {
MonoDomain *domain;
const char *file;
int retval;
if (argc < 2){
fprintf (stderr, "Please provide an assembly to load\n");
return 1;
}
file = argv [1];
/*
* Load the default Mono configuration file, this is needed
* if you are planning on using the dllmaps defined on the
* system configuration
*/
mono_config_parse (NULL);
/*
* mono_jit_init() creates a domain: each assembly is
* loaded and run in a MonoDomain.
*/
domain = mono_jit_init (file);
/*
* We add our special internal call, so that C# code
* can call us back.
*/
mono_add_internal_call ("MonoEmbed::gimme", gimme);
main_function (domain, file, argc - 1, argv + 1);
retval = mono_environment_exitcode_get ();
mono_jit_cleanup (domain);
return retval;
}

48
samples/profiler/sample.c Normal file
View File

@@ -0,0 +1,48 @@
#include <mono/metadata/profiler.h>
/*
* Bare bones profiler. Compile with:
* gcc -shared -o mono-profiler-sample.so sample.c `pkg-config --cflags --libs mono`
* Install the binary where the dynamic loader can find it.
* Then run mono with:
* mono --profile=sample your_application.exe
*/
struct _MonoProfiler {
int ncalls;
};
/* called at the end of the program */
static void
sample_shutdown (MonoProfiler *prof)
{
g_print ("total number of calls: %d\n", prof->ncalls);
}
static void
sample_method_enter (MonoProfiler *prof, MonoMethod *method)
{
prof->ncalls++;
}
static void
sample_method_leave (MonoProfiler *prof, MonoMethod *method)
{
}
/* the entry point */
void
mono_profiler_startup (const char *desc)
{
MonoProfiler *prof;
prof = g_new0 (MonoProfiler, 1);
mono_profiler_install (prof, sample_shutdown);
mono_profiler_install_enter_leave (sample_method_enter, sample_method_leave);
mono_profiler_set_events (MONO_PROFILE_ENTER_LEAVE);
}

12
samples/size/Makefile Normal file
View File

@@ -0,0 +1,12 @@
all: objectinspector.dll libmono-profiler-size.so sample.exe
LD_LIBRARY_PATH=. mono --profile=size sample.exe
sample.exe: objectinspector.dll sample.cs
mcs -r:objectinspector.dll sample.cs
objectinspector.dll: objectinspector.cs
mcs -target:library objectinspector.cs
libmono-profiler-size.so: size.c
gcc -Wall -g -shared -o libmono-profiler-size.so size.c `pkg-config --cflags --libs mono`

28
samples/size/README Normal file
View File

@@ -0,0 +1,28 @@
* Size sample
This sample provides a new internal call that can be used to
obtain the size of an object and all of the referenced objects
that this object holds.
This is exposed in the method:
int Mono.ObjectServices.ObjectInspector.GetMemoryUsage (object x)
Available in the objectinspector.dll file; To use this, you
must run Mono with the --profile=size argument (and have the
libmono-profile-size.so module in your path).
* Inner Details.
This implementation used a profiler hook at jit-end to install
a new internal call, and exposes a small DLL
(objectinspector.dll).
There is no need to use the profiler, the method body that
does the object size computation can be copy/pasted elsewhere,
particularly on embedded uses of Mono.

View File

@@ -0,0 +1,37 @@
//
// Copyright (C) 2004 Novell, Inc (http://www.novell.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.Runtime.CompilerServices;
using System;
using System.Security;
using System.Reflection;
using System.Threading;
namespace Mono.ObjectServices {
public class ObjectInspector {
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public extern static int GetMemoryUsage (object x);
}
}

44
samples/size/sample.cs Normal file
View File

@@ -0,0 +1,44 @@
using System;
using Mono.ObjectServices;
class Demo {
int a;
static void Main ()
{
Demo d = new Demo ();
prints ("d", d);
prints ("dd", new DD ());
prints ("short str", "short");
prints ("long str", "this is a longer string which we want to measure the size of");
object[] obj_array = new object [100];
prints ("obj array", obj_array);
for (int i = 0; i < 100; i++)
obj_array [i] = new Demo ();
prints ("obj array w/ demos", obj_array);
}
static void prints (string s, object x)
{
Console.WriteLine ("size of " + s + ":" + ObjectInspector.GetMemoryUsage (x));
}
}
class DD {
Demo d = new Demo ();
object [] o = new object [10];
char [] ch = new char [10];
int junk;
public DD ()
{
o [0] = new Demo ();
o [5] = new Demo ();
}
}

138
samples/size/size.c Normal file
View File

@@ -0,0 +1,138 @@
#include <glib.h>
#include <mono/jit/jit.h>
#include <mono/metadata/environment.h>
#include <mono/metadata/profiler.h>
#include <mono/metadata/tokentype.h>
#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/assembly.h>
#include <string.h>
#define FIELD_ATTRIBUTE_STATIC 0x10
#define FIELD_ATTRIBUTE_HAS_FIELD_RVA 0x100
static int memory_usage (MonoObject *obj, GHashTable *visited);
static int
memory_usage_array (MonoArray *array, GHashTable *visited)
{
int total = 0;
MonoClass *array_class = mono_object_get_class ((MonoObject *) array);
MonoClass *element_class = mono_class_get_element_class (array_class);
MonoType *element_type = mono_class_get_type (element_class);
if (MONO_TYPE_IS_REFERENCE (element_type)) {
int i;
for (i = 0; i < mono_array_length (array); i++) {
MonoObject *element = mono_array_get (array, gpointer, i);
if (element != NULL)
total += memory_usage (element, visited);
}
}
return total;
}
static int
memory_usage (MonoObject *obj, GHashTable *visited)
{
int total = 0;
MonoClass *klass;
MonoType *type;
gpointer iter = NULL;
MonoClassField *field;
if (g_hash_table_lookup (visited, obj))
return 0;
g_hash_table_insert (visited, obj, obj);
klass = mono_object_get_class (obj);
type = mono_class_get_type (klass);
/* This is an array, so drill down into it */
if (type->type == MONO_TYPE_SZARRAY)
total += memory_usage_array ((MonoArray *) obj, visited);
while ((field = mono_class_get_fields (klass, &iter)) != NULL) {
MonoType *ftype = mono_field_get_type (field);
gpointer value;
if ((ftype->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)) != 0)
continue;
/* FIXME: There are probably other types we need to drill down into */
switch (ftype->type) {
case MONO_TYPE_CLASS:
case MONO_TYPE_OBJECT:
mono_field_get_value (obj, field, &value);
if (value != NULL)
total += memory_usage ((MonoObject *) value, visited);
break;
case MONO_TYPE_STRING:
mono_field_get_value (obj, field, &value);
if (value != NULL)
total += mono_object_get_size ((MonoObject *) value);
break;
case MONO_TYPE_SZARRAY:
mono_field_get_value (obj, field, &value);
if (value != NULL) {
total += memory_usage_array ((MonoArray *) value, visited);
total += mono_object_get_size ((MonoObject *) value);
}
break;
default:
/* printf ("Got type 0x%x\n", ftype->type); */
/* ignore, this will be included in mono_object_get_size () */
break;
}
}
total += mono_object_get_size (obj);
return total;
}
/*
* Only returns data for instances, not for static fields, those might
* be larger, or hold larger structures
*/
static int
GetMemoryUsage (MonoObject *this)
{
GHashTable *visited = g_hash_table_new (NULL, NULL);
int n;
n = memory_usage (this, visited);
g_hash_table_destroy (visited);
return n;
}
static int installed = 0;
void install_icall (MonoProfiler *prof, MonoMethod *method, MonoJitInfo* jinfo, int result)
{
if (installed)
return;
mono_add_internal_call ("Mono.ObjectServices.ObjectInspector::GetMemoryUsage", GetMemoryUsage);
installed = 1;
}
void
mono_profiler_startup (const char *desc)
{
mono_profiler_install_jit_end (install_icall);
mono_profiler_set_events (MONO_PROFILE_JIT_COMPILATION);
}