[M3devel] m3cc static chain stuff

Jay K jay.krell at cornell.edu
Thu May 27 14:26:18 CEST 2010


But, it reads closures?
And IF there was a reasonable portable "executable heap", and trampolines were put there..the debugability could be solved as described -- putting the parameter(s) at fixed negative offsets from the code?

 - Jay


----------------------------------------
> Subject: Re: [M3devel] m3cc static chain stuff
> From: hosking at cs.purdue.edu
> Date: Thu, 27 May 2010 08:10:50 -0400
> CC: rodney_bates at lcwb.coop; m3devel at elegosoft.com
> To: jay.krell at cornell.edu
>
> m3gdb doesn't read trampolines because the gcc-based backend does not generate them!
>
>
> On 27 May 2010, at 07:27, Jay K wrote:
>
>>
>> I also disfavor using gcc trampolines, for the same reason, they require executable stack, which is either unavailable, or probably quite slow (having to call mprotect).
>>
>>
>> I had forgotten about them, and your reminding me helps me realize why we have to hack gcc a bit.
>> Because it has a similar but inferior mechanism.
>>
>>
>> One wonders about Ada though -- does it supported nested functions?
>> I noticed it bears a striking resembles to Pascal/Modula-3. :)
>>
>> And uses the same not great trampoline mechanism?
>>
>>
>> If they could be moved to an "executable heap", and be made very debuggable, then I'd favor them.
>> Those are two very big ifs.
>>
>>
>> Why does m3gdb have to read trampolines? It has to extract a parameter from inside their code?
>> Ah.
>> We could probably..if we really ever get here..which isn't all that likely, we could probably endeavor to format them like so:
>>
>> -- pointer to function --
>> -- parameter/static chain whatever --
>> trampoline points here => -- start of code --
>> -- target dependent position independent not very optimized
>> -- *constant* hand crafted code that fetchs the data from just before itself
>>
>>
>> Would that address the m3gdb problem?
>> Putting the data at fixed negative offsets from the trampoline code?
>> Presumably putting it at fixed positive offsets is the problem -- you'd either round up the trampoline size
>> to try to account for any target, of m3gdb would have to know where in the instruction stream per-target the data is written. Fixed negative offsets seem much better.
>>
>>
>> Granted, crafting that code would be.. fun. :)
>> Actually it would just be a call to a helper routine and the helper routine would fetch the return address and go from there..still gnarly.
>>
>>
>> - Jay
>>
>>
>> ----------------------------------------
>>> From: hosking at cs.purdue.edu
>>> Date: Thu, 27 May 2010 05:33:52 -0400
>>> To: rodney_bates at lcwb.coop
>>> CC: m3devel at elegosoft.com
>>> Subject: Re: [M3devel] m3cc static chain stuff
>>>
>>> The trampoline mechanism is broken on many platforms because they disable executable stacks. I strongly favour retaining the current mechanisms.
>>>
>>> On 26 May 2010, at 19:14, Rodney M. Bates wrote:
>>>
>>>>
>>>>
>>>> Tony Hosking wrote:
>>>>> We should endeavour to use the same functionality that the C compiler uses for its own nested functions, whereever possible. The only thing is that we also build closures, so the trampoline mechanisms should be avoided.
>>>>
>>>> I don't follow the last part of this argument. If we follow the first
>>>> principle, we would just use trampolines, since they are the same
>>>> mechanism the C compiler uses. And the only place they are not possible
>>>> are places where they won't work for C either (e.g., a target where there
>>>> is no place to construct code at runtime and have it be executable).
>>>> The mere fact that we "also build closures" is not a necessity, just
>>>> the reflection of the design decision to use the closure mechanism
>>>> instead of trampolines.
>>>>
>>>> OTHO, despite all the positive things I have said here and in another post
>>>> about trampolines, I don't favor using them, because they would make m3gdb
>>>> support a lot more difficult. m3gdb needs to be able to both read and
>>>> construct closures/trampolines, whichever. Closures are almost target-
>>>> independent, except for the native word size, which is already easily
>>>> available to m3gdb. Trampolines are going to be different for every
>>>> instruction set, and the ones constructed by compiled code, at least,
>>>> could even change with compiler version. m3gdb would need a _lot_ of
>>>> highly target-dependent code to handle them.
>>>>
>>>>> Antony Hosking | Associate Professor | Computer Science | Purdue University
>>>>> 305 N. University Street | West Lafayette | IN 47907 | USA
>>>>> Office +1 765 494 6001 | Mobile +1 765 427 5484
>>>>> On 26 May 2010, at 02:05, Jay K wrote:
>>>>>>
>>>>>> Can any of this be removed?
>>>>>> Can we really not just use "unfold-nested-procs" like NT386?
>>>>>> We'd just lose a little bit of optimization, in rare cases, stop paying a bad cost/benefit ratio?
>>>>>> Part of this is actually *deoptimization*. If the compiler decides the values aren't used, then it should
>>>>>> be allowed to remove them. That is normal. Wanting to unused stuff in the debugger isn't
>>>>>> generally a considered the responsibility of optimizers.
>>>>>>
>>>>>> Therefore -- we could "unfold", remove our diffs, and gain some optimization and some deoptimization.
>>>>>> Maybe I'll try without.
>>>>>>
>>>>>>
>>>>>> diff -ur /src/orig/gcc-4.3.0/gcc/tree-nested.c /dev2/cm3/m3-sys/m3cc/gcc/gcc/tree-nested.c
>>>>>> --- /src/orig/gcc-4.3.0/gcc/tree-nested.c 2008-02-15 09:36:43.000000000 -0800
>>>>>> +++ /dev2/cm3/m3-sys/m3cc/gcc/gcc/tree-nested.c 2010-05-09 22:27:58.000000000 -0700
>>>>>>
>>>>>>
>>>>>> -/* Build or return the RECORD_TYPE that describes the frame state that is
>>>>>> - shared between INFO->CONTEXT and its nested functions. This record will
>>>>>> - not be complete until finalize_nesting_tree; up until that point we'll
>>>>>> +/* This must agree with the string defined by the same name in m3gdb, file
>>>>>> + m3-util.c */
>>>>>> +static const char * nonlocal_var_rec_name = "_nonlocal_var_rec";
>>>>>> +
>>>>>> +/* Build or return the RECORD_TYPE that describes the non-local frame struct
>>>>>> + that is shared between INFO->CONTEXT and its nested functions. This record
>>>>>> + will not be complete until finalize_nesting_tree; up until that point we'll
>>>>>> be adding fields as necessary.
>>>>>> We also build the DECL that represents this frame in the function. */
>>>>>> @@ -209,7 +224,8 @@
>>>>>> free (name);
>>>>>> info->frame_type = type;
>>>>>> - info->frame_decl = create_tmp_var_for (info, type, "FRAME");
>>>>>> + info->frame_decl
>>>>>> + = create_tmp_var_for (info, type, nonlocal_var_rec_name);
>>>>>> /* ??? Always make it addressable for now, since it is meant to
>>>>>> be pointed to by the static chain pointer. This pessimizes
>>>>>> @@ -218,6 +234,8 @@
>>>>>> reachable, but the true pessimization is to create the non-
>>>>>> local frame structure in the first place. */
>>>>>> TREE_ADDRESSABLE (info->frame_decl) = 1;
>>>>>> + /* m3gdb needs to know about this variable. */
>>>>>> + DECL_IGNORED_P (info->frame_decl) = 0; }
>>>>>> return type;
>>>>>> }
>>>>>> @@ -290,6 +308,10 @@
>>>>>> return *slot;
>>>>>> }
>>>>>> +/* This must agree with the string defined by the same name in m3gdb, file
>>>>>> + m3_util.c */
>>>>>> +static const char * static_link_var_name = "_static_link_var";
>>>>>> +
>>>>>> /* Build or return the variable that holds the static chain within
>>>>>> INFO->CONTEXT. This variable may only be used within INFO->CONTEXT. */
>>>>>> @@ -310,9 +332,14 @@
>>>>>> Note also that it's represented as a parameter. This is more
>>>>>> close to the truth, since the initial value does come from
>>>>>> the caller. */
>>>>>> - decl = build_decl (PARM_DECL, create_tmp_var_name ("CHAIN"), type);
>>>>>> + decl = build_decl
>>>>>> + (PARM_DECL, get_identifier (static_link_var_name), type);
>>>>>> + TREE_CHAIN (decl) = NULL; /* Possibly redundant, but dbxout needs it. */
>>>>>> DECL_ARTIFICIAL (decl) = 1;
>>>>>> - DECL_IGNORED_P (decl) = 1;
>>>>>> +
>>>>>> + /* m3gdb needs to know about this variable. */
>>>>>> + DECL_IGNORED_P (decl) = 0;
>>>>>> +
>>>>>> TREE_USED (decl) = 1;
>>>>>> DECL_CONTEXT (decl) = info->context;
>>>>>> DECL_ARG_TYPE (decl) = type;
>>>>>> @@ -326,7 +353,11 @@
>>>>>> return decl;
>>>>>> }
>>>>>> -/* Build or return the field within the non-local frame state that holds
>>>>>> +/* This must agree with the string defined by the same name in m3gdb, file
>>>>>> + m3_util.c */
>>>>>> +static const char * static_link_copy_field_name = "_static_link_copy_field";
>>>>>> +
>>>>>> +/* Build or return the field within the non-local frame struct that holds
>>>>>> the static chain for INFO->CONTEXT. This is the way to walk back up
>>>>>> multiple nesting levels. */
>>>>>> @@ -339,10 +370,12 @@
>>>>>> tree type = build_pointer_type (get_frame_type (info->outer));
>>>>>> field = make_node (FIELD_DECL);
>>>>>> - DECL_NAME (field) = get_identifier ("__chain");
>>>>>> + DECL_NAME (field) = get_identifier (static_link_copy_field_name);
>>>>>> TREE_TYPE (field) = type;
>>>>>> DECL_ALIGN (field) = TYPE_ALIGN (type);
>>>>>> DECL_NONADDRESSABLE_P (field) = 1;
>>>>>> + /* m3gdb should know about this field. */
>>>>>> + DECL_IGNORED_P (field) = 0; insert_field_into_struct (get_frame_type (info), field);
>>>>>> @@ -465,7 +498,7 @@
>>>>>> return *slot;
>>>>>> }
>>>>>> -/* Build or return the field within the non-local frame state that holds
>>>>>> +/* Build or return the field within the non-local frame struct that holds
>>>>>> the non-local goto "jmp_buf". The buffer itself is maintained by the
>>>>>> rtl middle-end as dynamic stack space is allocated. */
>>>>>> @@ -1620,6 +1653,9 @@
>>>>>> switch (TREE_CODE (t))
>>>>>> {
>>>>>> case ADDR_EXPR:
>>>>>> + if (TREE_STATIC (t))
>>>>>> + break;
>>>>>> +
>>>>>> /* Build
>>>>>> T.1 = &CHAIN->tramp;
>>>>>> T.2 = __builtin_adjust_trampoline (T.1);
>>>>>> @@ -1714,6 +1750,22 @@
>>>>>> }
>>>>>> break;
>>>>>> + case STATIC_CHAIN_EXPR:
>>>>>> + decl = TREE_OPERAND (t, 0);
>>>>>> + target_context = decl_function_context (decl);
>>>>>> + if (target_context)
>>>>>> + {
>>>>>> + if (info->context == target_context)
>>>>>> + {
>>>>>> + /* Make sure frame_decl gets created. */
>>>>>> + (void) get_frame_type (info);
>>>>>> + }
>>>>>> + *tp = get_static_chain (info, target_context, &wi->tsi);
>>>>>> + }
>>>>>> + else
>>>>>> + *tp = null_pointer_node;
>>>>>> + break;
>>>>>> +
>>>>>> case RETURN_EXPR:
>>>>>> case GIMPLE_MODIFY_STMT:
>>>>>> case WITH_SIZE_EXPR:
>>>>>> @@ -1768,13 +1820,22 @@
>>>>>> return NULL_TREE;
>>>>>> }
>>>>>> +static bool
>>>>>> +debug_static_links (void)
>>>>>> +{ return
>>>>>> + write_symbols != NO_DEBUG
>>>>>> + && debug_info_level != DINFO_LEVEL_NONE
>>>>>> + && debug_info_level != DINFO_LEVEL_TERSE;
>>>>>> +
>>>>>> +} /* debug_static_links */
>>>>>> +
>>>>>> /* Walk the nesting tree starting with ROOT, depth first. Convert all
>>>>>> trampolines and call expressions. On the way back up, determine if
>>>>>> a nested function actually uses its static chain; if not, remember that. */
>>>>>> static void
>>>>>> convert_all_function_calls (struct nesting_info *root)
>>>>>> -{
>>>>>> +{
>>>>>> do
>>>>>> {
>>>>>> if (root->inner)
>>>>>> @@ -1784,7 +1845,10 @@
>>>>>> walk_function (convert_call_expr, root);
>>>>>> /* If the function does not use a static chain, then remember that. */
>>>>>> - if (root->outer && !root->chain_decl && !root->chain_field)
>>>>>> + if (root->outer && !root->chain_decl && !root->chain_field
>>>>>> +/* REMOVE ME: */
>>>>>> + /* && !debug_static_links () */
>>>>>> + )
>>>>>> DECL_NO_STATIC_CHAIN (root->context) = 1;
>>>>>> else
>>>>>> gcc_assert (!DECL_NO_STATIC_CHAIN (root->context));
>>>>>> @@ -1806,6 +1870,21 @@
>>>>>> tree context = root->context;
>>>>>> struct function *sf;
>>>>>> +/* REMOVEME: */
>>>>>> + /* If this is a nested function and we are supporting debugging via
>>>>>> + m3gdb, we always need a chain_decl, so m3gdb can find the static
>>>>>> + chain, even if the programmer's code doesn't use it. */
>>>>>> + if (false && root->outer && debug_static_links () )
>>>>>> + { tree static_chain_decl, temp, stmt;
>>>>>> + /* This is a desperate attempt to get later code generation to
>>>>>> + store the static link. If it works, it'll be a miracle. */
>>>>>> + static_chain_decl = get_chain_decl (root);
>>>>>> + stmt = build_addr (static_chain_decl, root->context);
>>>>>> + temp = create_tmp_var_for (root, TREE_TYPE (static_chain_decl), NULL);
>>>>>> + stmt = build_gimple_modify_stmt (temp, static_chain_decl);
>>>>>> + append_to_statement_list (stmt, &stmt_list);
>>>>>> + }
>>>>>> +
>>>>>> /* If we created a non-local frame type or decl, we need to lay them
>>>>>> out at this time. */
>>>>>> if (root->frame_type)
>>>>>> @@ -1912,7 +1991,7 @@
>>>>>> proper BIND_EXPR. */
>>>>>> if (root->new_local_var_chain)
>>>>>> declare_vars (root->new_local_var_chain, DECL_SAVED_TREE (root->context),
>>>>>> - false);
>>>>>> + true);
>>>>>> if (root->debug_var_chain)
>>>>>> declare_vars (root->debug_var_chain, DECL_SAVED_TREE (root->context),
>>>>>> true);
>>>>>>
>>>>>>
>>>>>>
>>>
>
 		 	   		  


More information about the M3devel mailing list