Example #1
0
void CLR_RT_StackFrame::Pop()
{
    NATIVE_PROFILE_CLR_CORE();

#if defined(TINYCLR_PROFILE_NEW_CALLS)
    {
        //
        // This passivates any outstanding handler.
        //
        CLR_PROF_HANDLER_CALLCHAIN(pm2,m_callchain);

        m_callchain.Leave();
    }
#endif

#if defined(TINYCLR_PROFILE_NEW_CALLS)
    g_CLR_PRF_Profiler.RecordFunctionReturn( m_owningThread, m_callchain );
#endif

#if defined(TINYCLR_ENABLE_SOURCELEVELDEBUGGING)
    if(m_owningThread->m_fHasJMCStepper || (m_flags & c_HasBreakpoint))
    {
        g_CLR_RT_ExecutionEngine.Breakpoint_StackFrame_Pop( this, false );
    }
#endif

    const CLR_UINT32 c_flagsToCheck = CLR_RT_StackFrame::c_CallOnPop | CLR_RT_StackFrame::c_Synchronized | CLR_RT_StackFrame::c_SynchronizedGlobally | CLR_RT_StackFrame::c_NativeProfiled;

    if(m_flags & c_flagsToCheck)
    {
        if(m_flags & CLR_RT_StackFrame::c_CallOnPop)
        {
            m_flags |= CLR_RT_StackFrame::c_CalledOnPop;

            if(m_nativeMethod)
            {
                (void)m_nativeMethod( *this );
            }
        }

        if(m_flags & CLR_RT_StackFrame::c_Synchronized)
        {
            m_flags &= ~CLR_RT_StackFrame::c_Synchronized;

            (void)HandleSynchronized( false, false );
        }

        if(m_flags & CLR_RT_StackFrame::c_SynchronizedGlobally)
        {
            m_flags &= ~CLR_RT_StackFrame::c_SynchronizedGlobally;

            (void)HandleSynchronized( false, true );
        }

#if defined(ENABLE_NATIVE_PROFILER)
        if(m_flags & CLR_RT_StackFrame::c_NativeProfiled)
        {
            m_owningThread->m_fNativeProfiled = false;
            m_flags &= ~CLR_RT_StackFrame::c_NativeProfiled;
            Native_Profiler_Stop();
        }
#endif
    }

    CLR_RT_StackFrame* caller = Caller();

    if(caller->Prev() != NULL)
    {
#if defined(TINYCLR_ENABLE_SOURCELEVELDEBUGGING)
        if(caller->m_flags & CLR_RT_StackFrame::c_HasBreakpoint)
        {
            g_CLR_RT_ExecutionEngine.Breakpoint_StackFrame_Step( caller, caller->m_IP );
        }
#endif

        //
        // Constructors are slightly different, they push the 'this' pointer back into the caller stack.
        //
        // This is to enable the special case for strings, where the object can be recreated by the constructor...
        //
        if(caller->m_flags & CLR_RT_StackFrame::c_ExecutingConstructor)
        {
            CLR_RT_HeapBlock& src = this  ->Arg0              (     );
            CLR_RT_HeapBlock& dst = caller->PushValueAndAssign( src );

            dst.Promote();

            //
            // Undo the special "object -> reference" hack done by CEE_NEWOBJ.
            //
            if(dst.DataType() == DATATYPE_BYREF)
            {
                dst.ChangeDataType( DATATYPE_OBJECT );
            }

            caller->m_flags &= ~CLR_RT_StackFrame::c_ExecutingConstructor;

            _ASSERTE((m_flags & CLR_RT_StackFrame::c_AppDomainTransition) == 0);
        }
        else
        {   //Note that ExecutingConstructor is checked on 'caller', whereas the other two flags are checked on 'this'
            const CLR_UINT32 c_moreFlagsToCheck = CLR_RT_StackFrame::c_PseudoStackFrameForFilter | CLR_RT_StackFrame::c_AppDomainTransition;

            if(m_flags & c_moreFlagsToCheck)
            {
                if(m_flags & CLR_RT_StackFrame::c_PseudoStackFrameForFilter)
                {
                    //Do nothing here. Pushing return values onto stack frames that don't expect them are a bad idea.
                }
#if defined(TINYCLR_APPDOMAINS)
                else if((m_flags & CLR_RT_StackFrame::c_AppDomainTransition) != 0)
                {
                    (void)PopAppDomainTransition();
                }
#endif
            }
            else //!c_moreFlagsToCheck
            {
                //
                // Push the return, if any.
                //
                if(m_call.m_target->retVal != DATATYPE_VOID)
                {
                    if(m_owningThread->m_currentException.Dereference() == NULL)
                    {
                        CLR_RT_HeapBlock& src = this  ->TopValue          (     );
                        CLR_RT_HeapBlock& dst = caller->PushValueAndAssign( src );

                        dst.Promote();
                    }
                }
            }
        }
    }
#if defined(TINYCLR_ENABLE_SOURCELEVELDEBUGGING)
    else
    {
        int idx = m_owningThread->m_scratchPad;

        if(idx >= 0)
        {
            CLR_RT_HeapBlock_Array* array = g_CLR_RT_ExecutionEngine.m_scratchPadArray;

            if(array && array->m_numOfElements > (CLR_UINT32)idx)
            {
                CLR_RT_HeapBlock* dst       = (CLR_RT_HeapBlock*)array->GetElement( (CLR_UINT32)idx );
                CLR_RT_HeapBlock* exception = m_owningThread->m_currentException.Dereference();

                dst->SetObjectReference( NULL );

                if(exception != NULL)
                {
                    dst->SetObjectReference( exception );
                }
                else if(m_call.m_target->retVal != DATATYPE_VOID)
                {
                    CLR_RT_SignatureParser sig;
                    sig.Initialize_MethodSignature( this->m_call.m_assm, this->m_call.m_target );
                    CLR_RT_SignatureParser::Element res;
                    CLR_RT_TypeDescriptor           desc;

                    dst->Assign( this->TopValue() );

                    //Perform boxing, if needed.

                    //Box to the return value type
                    _SIDE_ASSERTE(SUCCEEDED(sig.Advance( res )));
                    _SIDE_ASSERTE(SUCCEEDED(desc.InitializeFromType( res.m_cls )));


                    if(c_CLR_RT_DataTypeLookup[ this->DataType() ].m_flags & CLR_RT_DataTypeLookup::c_OptimizedValueType
                            || desc.m_handlerCls.m_target->IsEnum()
                      )
                    {
                        if(FAILED(dst->PerformBoxing( desc.m_handlerCls )))
                        {
                            dst->SetObjectReference( NULL );
                        }
                    }
                }
            }
        }
    }
#endif

    //
    // We could be jumping outside of a nested exception handler.
    //

    m_owningThread->PopEH( this, NULL );


    //
    // If this StackFrame owns a SubThread, kill it.
    //
    {
        CLR_RT_SubThread* sth = (CLR_RT_SubThread*)m_owningSubThread->Next();

        if(sth->Next() && sth->m_owningStackFrame == this)
        {
            CLR_RT_SubThread::DestroyInstance( sth->m_owningThread, sth, CLR_RT_SubThread::MODE_IncludeSelf );
        }
    }

    g_CLR_RT_EventCache.Append_Node( this );
}