Skip to content

Commit

Permalink
[WIP][interp] Unify execution and valuetype stacks (#43681)
Browse files Browse the repository at this point in the history
Before this change, an InterpFrame contained 3 regions of data : args + locals, valuetype stack, execution stack. Each entry on the execution stack was a stackval structure. The space for valuetypes, was allocated separately, since they have various sizes. When pushing a valuetype on the stack, we allocated first the space for it on the vtstack and then pushed the address of the region on the execution stack. This change merges the execution stack with the valuetype stack, meaning we push now variable sized data on the execution stack. In order to keep track of the current stack location, whenever we push a type on stack, during transform phase, we also keep track of the offset where this value will reside on stack, as well as the size it occupies. All callsites need to be informed how much they need to pop the stack for the arguments. While called code can access this space normally (the args are special locals belonging to the frame and are accessed directly as such), external code needs a new mechanism to detect each argument for a given frame. This is achieved with the lazily initialized arg_offsets array on an InterpMethod. The method doesn't need to be compiled for this array to be correctly initialized.

Why :
- this simplifies handling of valuetypes, their storage follows the same rules as a normal objref/primitive type
- removes the common use of the vt_sp variable. The compiler no longer needs to reserve it in a register during the switch loop, we no longer need to save it with each call. The sp and ip become now the only variables describing the execution state in a method.
- the flow of the data on the execution stack is well behaved now (with the exception of a few opcodes that update directly based on the stack offset). We were using the vtstack for some magic storage (MINT_VTRESULT for example)
- this makes it such that the stack offset of every value is easily known at compile time, making it possible to completely drop the execution stack approach, and have every opcode have a unique dreg and a list of sregs (which are mapped to a certain stack offset). This will enable more advanced optimizations during compile stage.

Co-authored-by: BrzVlad <[email protected]>
  • Loading branch information
monojenkins and BrzVlad authored Oct 26, 2020
1 parent c107fa8 commit dd23c81
Show file tree
Hide file tree
Showing 13 changed files with 999 additions and 1,397 deletions.
3 changes: 2 additions & 1 deletion src/mono/mono/metadata/remoting.c
Original file line number Diff line number Diff line change
Expand Up @@ -761,9 +761,10 @@ mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, in

mono_mb_emit_ldarg (mb, 1);
mono_mb_emit_byte (mb, CEE_LDIND_REF);
mono_mb_emit_byte (mb, CEE_DUP);
pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);

mono_mb_emit_ldarg (mb, 1);
mono_mb_emit_byte (mb, CEE_LDIND_REF);
mono_marshal_emit_xdomain_copy_value (mb, byte_array_class);
mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL);

Expand Down
4 changes: 1 addition & 3 deletions src/mono/mono/mini/ee.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#ifndef __MONO_EE_H__
#define __MONO_EE_H__

#define MONO_EE_API_VERSION 0xf
#define MONO_EE_API_VERSION 0x10

typedef struct _MonoInterpStackIter MonoInterpStackIter;

Expand Down Expand Up @@ -49,11 +49,9 @@ typedef gpointer MonoInterpFrameHandle;
MONO_EE_CALLBACK (gpointer, frame_get_arg, (MonoInterpFrameHandle frame, int pos)) \
MONO_EE_CALLBACK (gpointer, frame_get_local, (MonoInterpFrameHandle frame, int pos)) \
MONO_EE_CALLBACK (gpointer, frame_get_this, (MonoInterpFrameHandle frame)) \
MONO_EE_CALLBACK (gpointer, frame_get_res, (MonoInterpFrameHandle frame)) \
MONO_EE_CALLBACK (void, frame_arg_to_data, (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer data)) \
MONO_EE_CALLBACK (void, data_to_frame_arg, (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gconstpointer data)) \
MONO_EE_CALLBACK (gpointer, frame_arg_to_storage, (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index)) \
MONO_EE_CALLBACK (void, frame_arg_set_storage, (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer storage)) \
MONO_EE_CALLBACK (MonoInterpFrameHandle, frame_get_parent, (MonoInterpFrameHandle frame)) \
MONO_EE_CALLBACK (void, start_single_stepping, (void)) \
MONO_EE_CALLBACK (void, stop_single_stepping, (void)) \
Expand Down
6 changes: 0 additions & 6 deletions src/mono/mono/mini/interp-stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,12 +211,6 @@ stub_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig
return NULL;
}

static void
stub_frame_arg_set_storage (MonoInterpFrameHandle frame, MonoMethodSignature *sig, int index, gpointer storage)
{
g_assert_not_reached ();
}

static void
stub_free_context (gpointer context)
{
Expand Down
3 changes: 2 additions & 1 deletion src/mono/mono/mini/interp/interp-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#define PROFILING_FLAG 0x2

#define MINT_VT_ALIGNMENT 8
#define MINT_STACK_SLOT_SIZE (sizeof (stackval))

#define INTERP_STACK_SIZE (1024*1024)

Expand Down Expand Up @@ -116,6 +117,7 @@ struct InterpMethod {
MonoExceptionClause *clauses; // num_clauses
void **data_items;
guint32 *local_offsets;
guint32 *arg_offsets;
guint32 *clause_data_offsets;
gpointer jit_call_info;
gpointer jit_entry;
Expand All @@ -127,7 +129,6 @@ struct InterpMethod {

guint32 total_locals_size;
guint32 stack_size;
guint32 vt_stack_size;
guint32 alloca_size;
int num_clauses; // clauses
int transformed; // boolean
Expand Down
Loading

0 comments on commit dd23c81

Please sign in to comment.