forked from dotnet/runtime
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmono-error-internals.h
383 lines (310 loc) · 12.4 KB
/
mono-error-internals.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
/**
* \file
*/
#ifndef __MONO_ERROR_INTERNALS_H__
#define __MONO_ERROR_INTERNALS_H__
#include <mono/metadata/object-forward.h>
#include <mono/utils/mono-forward.h>
#include "mono/utils/mono-compiler.h"
MONO_DISABLE_WARNING(4201) // nonstandard extension used: nameless struct/union
/*Keep in sync with MonoError*/
typedef union _MonoErrorInternal {
// Merge two uint16 into one uint32 so it can be initialized
// with one instruction instead of two.
guint32 init; // Written by JITted code
struct {
guint16 error_code;
guint16 flags;
/*These name are suggestions of their content. MonoError internals might use them for something else.*/
// type_name must be right after error_code and flags, see mono_error_init_deferred.
const char *type_name;
const char *assembly_name;
const char *member_name;
const char *exception_name_space;
const char *exception_name;
union {
/* Valid if error_code != MONO_ERROR_EXCEPTION_INSTANCE.
* Used by type or field load errors and generic error specified by class.
*/
MonoClass *klass;
/* Valid if error_code == MONO_ERROR_EXCEPTION_INSTANCE.
* Generic error specified by a managed instance.
*/
MonoGCHandle instance_handle;
} exn;
const char *full_message;
const char *full_message_with_fields;
const char *first_argument;
// MonoErrorExternal:
//void *padding [3];
};
} MonoErrorInternal;
MONO_RESTORE_WARNING
/* Invariant: the error strings are allocated in the mempool of the given image */
struct _MonoErrorBoxed {
MonoError error;
MonoImage *image;
};
/*
Historically MonoError initialization was deferred, but always had to occur,
even in success paths, as cleanup could be done unconditionally.
This was confusing.
ERROR_DECL (error)
This is the overwhelmingly common case.
Declare and initialize a local variable, named "error",
pointing to an initialized MonoError (named "error_value",
using token pasting).
MONO_API_ERROR_INIT
This is used for MonoError in/out parameter on a public interface,
which must be presumed uninitialized. These are often
marked with MONO_API, MONO_RT_EXTERNAL_ONLY, MONO_PROFILER_API, etc.
Tnis includes functions called from dis, profiler, pedump, and driver.
dis, profiler, and pedump make sense, these are actually external and
uninitialized. Driver less so.
Presently this is unused and error_init is used instead.
error_init
Initialize a MonoError. These are historical and usually
but not always redundant, and should be reduced/eliminated.
All the non-redundant ones should be renamed and all the redundant
ones removed.
error_init_reuse
This indicates an error has been cleaned up and will be reused.
A common usage is to reduce stack pressure, e.g. in the interpreter.
Consider also changing mono_error_cleanup to call error_init_internal,
and then remove these.
error_init_internal
Rare cases without a better name.
For example, setting up an icall frame, or initializing member data.
new0, calloc, static
A zeroed MonoError is valid and initialized.
Zeroing an entire MonoError is overkill, unless it is near other
bulk zeroing.
All initialization is actually bottlenecked to error_init_internal.
Different names indicate different scenarios, but the same code.
*/
#define ERROR_DECL(x) MonoError x ## _value; error_init_internal (& x ## _value); MonoError * const x = &x ## _value
#define error_init_internal(error) ((void)((error)->init = 0))
#define MONO_API_ERROR_INIT(error) error_init_internal (error)
#define error_init_reuse(error) error_init_internal (error)
#define ERROR_LOCAL_BEGIN(local, parent, skip_overwrite) do { \
MonoError local; \
gboolean local ## _overwrite_temp = skip_overwrite; \
error_init_internal (&local); \
if (!local ## _overwrite_temp) \
parent = &local; \
#define ERROR_LOCAL_END(local) if (!local ## _overwrite_temp) \
mono_error_cleanup (&local); \
} while (0) \
// Historical deferred initialization was called error_init.
// possible bug detection that did not work
//#define error_init(error) (is_ok (error))
// FIXME Eventually all error_init should be removed, however it is prudent
// to leave them in for now, at least most of them, while we sort out
// the few that are needed and to experiment with adding them back in bulk,
// i.e. in an entire source file. Some are obviously not needed.
//#define error_init(error) // nothing
#define error_init(error) error_init_internal (error)
// Function for experimentation, should go away.
//void error_init(MonoError*);
#define is_ok(error) ((error)->error_code == MONO_ERROR_NONE)
#define return_if_nok(error) do { if (!is_ok ((error))) return; } while (0)
#define return_val_if_nok(error,val) do { if (!is_ok ((error))) return (val); } while (0)
#define goto_if(expr, label) do { if (expr) goto label; } while (0)
#define goto_if_ok(error, label) goto_if (is_ok (error), label)
#define goto_if_nok(error, label) goto_if (!is_ok (error), label)
/* Only use this in icalls */
#define return_val_and_set_pending_if_nok(error, value) \
do { \
if (mono_error_set_pending_exception ((error))) \
return (value); \
} while (0) \
/*
* Three macros to assert that a MonoError is ok:
* 1. mono_error_assert_ok(e) when you just want to print the error's message on failure
* 2. mono_error_assert_ok(e,msg) when you want to print "msg, due to <e's message>"
* 3. mono_error_assertf_ok(e,fmt,args...) when you want to print "<formatted msg>, due to <e's message>"
* (fmt should specify the formatting just for args).
*
* What's the difference between mono_error_assert_msg_ok (e, "foo") and
* mono_error_assertf_ok (e, "foo") ? The former works as you expect, the
* latter unhelpfully expands to
*
* g_assertf (is_ok (e), "foo, due to %s", , mono_error_get_message (err)).
*
* Note the double commas. Turns out that to get rid of that extra comma
* portably we would have to write really ugly preprocessor macros.
*/
#define mono_error_assert_ok(error) g_assertf (is_ok (error), "%s", mono_error_get_message (error))
#define mono_error_assert_msg_ok(error, msg) g_assertf (is_ok (error), msg ", due to %s", mono_error_get_message (error))
#define mono_error_assertf_ok(error, fmt, ...) g_assertf (is_ok (error), fmt ", due to %s", __VA_ARGS__, mono_error_get_message (error))
/*
* Returns a pointer to the error message, without fields, empty string if no message is available.
* Caller should NOT release returned pointer, owned by MonoError.
*/
static inline
const char *
mono_error_get_message_without_fields (MonoError *oerror)
{
MonoErrorInternal *error = (MonoErrorInternal*)oerror;
return error->full_message ? error->full_message : "";
}
void
mono_error_dup_strings (MonoError *error, gboolean dup_strings);
/* This function is not very useful as you can't provide any details beyond the message.*/
MONO_COMPONENT_API
void
mono_error_set_error (MonoError *error, int error_code, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(3,4);
void
mono_error_set_type_load_class (MonoError *error, MonoClass *klass, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(3,4);
void
mono_error_vset_type_load_class (MonoError *error, MonoClass *klass, const char *msg_format, va_list args);
MONO_COMPONENT_API
void
mono_error_set_type_load_name (MonoError *error, const char *type_name, const char *assembly_name, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(4,5);
void
mono_error_set_out_of_memory (MonoError *error, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(2,3);
void
mono_error_set_argument_format (MonoError *error, const char *argument, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(3,4);
void
mono_error_set_argument (MonoError *error, const char *argument, const char *msg);
void
mono_error_set_argument_null (MonoError *oerror, const char *argument, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(3,4);
void
mono_error_set_argument_out_of_range (MonoError *error, const char *name, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(3,4);
void
mono_error_set_not_verifiable (MonoError *oerror, MonoMethod *method, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(3,4);
void
mono_error_set_generic_error (MonoError *error, const char * name_space, const char *name, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(4,5);
void
mono_error_set_execution_engine (MonoError *error, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(2,3);
MONO_COMPONENT_API
void
mono_error_set_not_implemented (MonoError *error, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(2,3);
MONO_COMPONENT_API
void
mono_error_set_not_supported (MonoError *error, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(2,3);
void
mono_error_set_ambiguous_implementation (MonoError *error, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(2,3);
MONO_COMPONENT_API
void
mono_error_set_invalid_operation (MonoError *error, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(2,3);
void
mono_error_set_exception_instance (MonoError *error, MonoException *exc);
void
mono_error_set_invalid_program (MonoError *oerror, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(2,3);
void
mono_error_set_member_access (MonoError *error, const char *msg_format, ...) MONO_ATTR_FORMAT_PRINTF(2,3);
void
mono_error_set_invalid_cast (MonoError *oerror);
static inline void
mono_error_set_divide_by_zero (MonoError *error)
{
mono_error_set_generic_error (error, "System", "DivideByZeroException", NULL);
}
static inline void
mono_error_set_index_out_of_range (MonoError *error)
{
mono_error_set_generic_error (error, "System", "IndexOutOfRangeException", NULL);
}
static inline void
mono_error_set_overflow (MonoError *error)
{
mono_error_set_generic_error (error, "System", "OverflowException", NULL);
}
static inline void
mono_error_set_synchronization_lock (MonoError *error, const char *message)
{
mono_error_set_generic_error (error, "System.Threading", "SynchronizationLockException", "%s", message);
}
static inline void
mono_error_set_thread_interrupted (MonoError *error)
{
mono_error_set_generic_error (error, "System.Threading", "ThreadInterruptedException", NULL);
}
static inline void
mono_error_set_null_reference (MonoError *error)
{
mono_error_set_generic_error (error, "System", "NullReferenceException", NULL);
}
static inline void
mono_error_set_duplicate_wait_object (MonoError *error)
{
mono_error_set_generic_error (error, "System", "DuplicateWaitObjectException", "Duplicate objects in argument.");
}
static inline void
mono_error_set_cannot_unload_appdomain (MonoError *error, const char *message)
{
mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "%s", message);
}
static inline void
mono_error_set_platform_not_supported (MonoError *error, const char *message)
{
mono_error_set_generic_error (error, "System", "PlatformNotSupportedException", "%s", message);
}
MonoException*
mono_error_prepare_exception (MonoError *error, MonoError *error_out);
MONO_COMPONENT_API MonoException*
mono_error_convert_to_exception (MonoError *error);
void
mono_error_move (MonoError *dest, MonoError *src);
MonoErrorBoxed*
mono_error_box (const MonoError *error, MonoImage *image);
gboolean
mono_error_set_from_boxed (MonoError *error, const MonoErrorBoxed *from);
const char*
mono_error_get_exception_name (MonoError *oerror);
const char*
mono_error_get_exception_name_space (MonoError *oerror);
void
mono_error_set_specific (MonoError *error, int error_code, const char *missing_method);
void
mono_error_set_first_argument (MonoError *oerror, const char *first_argument);
#if HOST_WIN32
#if HOST_X86 || HOST_AMD64
#include <windows.h>
// Single instruction inlinable form of GetLastError.
//
// Naming violation so can search disassembly for GetLastError.
//
#define GetLastError mono_GetLastError
static inline
unsigned long
__stdcall
GetLastError (void)
{
#if HOST_X86
return __readfsdword (0x34);
#elif HOST_AMD64
return __readgsdword (0x68);
#else
#error Unreachable, see above.
#endif
}
// Single instruction inlinable valid subset of SetLastError.
//
// Naming violation so can search disassembly for SetLastError.
//
// This is useful, for example, if you want to set a breakpoint
// on SetLastError, but do not want to break on merely "restoring" it,
// only "originating" it.
//
// A generic name is used in case there are other use-cases.
//
static inline
void
__stdcall
mono_SetLastError (unsigned long err)
{
#if HOST_X86
__writefsdword (0x34, err);
#elif HOST_AMD64
__writegsdword (0x68, err);
#else
#error Unreachable, see above.
#endif
}
#else // arm, arm64, etc.
#define mono_SetLastError SetLastError
#endif // processor
#endif // win32
#endif