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 );
}
Example #2
0
HRESULT CLR_RT_StackFrame::Push( CLR_RT_Thread* th, const CLR_RT_MethodDef_Instance& callInst, CLR_INT32 extraBlocks )
{
    NATIVE_PROFILE_CLR_CORE();
    TINYCLR_HEADER();

    CLR_RT_StackFrame*               stack;
    CLR_RT_StackFrame*               caller;
    CLR_RT_Assembly*                 assm;
    const CLR_RECORD_METHODDEF*      md;
    const CLR_RT_MethodDef_Instance* callInstPtr = &callInst;
    CLR_UINT32                       sizeLocals;
    CLR_UINT32                       sizeEvalStack;

#if defined(PLATFORM_WINDOWS)
    if(s_CLR_RT_fTrace_SimulateSpeed > c_CLR_RT_Trace_None)
    {
        CLR_PROF_Handler::SuspendTime();

        HAL_Windows_FastSleep( g_HAL_Configuration_Windows.TicksPerMethodCall );

        CLR_PROF_Handler::ResumeTime();
    }
#endif

    assm          = callInstPtr->m_assm;
    md            = callInstPtr->m_target;

    sizeLocals    = md->numLocals;
    sizeEvalStack = md->lengthEvalStack + CLR_RT_StackFrame::c_OverheadForNewObjOrInteropMethod;

    //--//

    caller = th->CurrentFrame();

    //--//

    //
    // Allocate memory for the runtime state.
    //
    {
        CLR_UINT32 memorySize = sizeLocals + sizeEvalStack;

        if(extraBlocks > 0             ) memorySize += extraBlocks;
        if(memorySize  < c_MinimumStack) memorySize  = c_MinimumStack;

        memorySize += CONVERTFROMSIZETOHEAPBLOCKS(offsetof(CLR_RT_StackFrame,m_extension));

        stack = EVENTCACHE_EXTRACT_NODE_AS_BLOCKS(g_CLR_RT_EventCache,CLR_RT_StackFrame,DATATYPE_STACK_FRAME,0,memorySize);
        CHECK_ALLOCATION(stack);
    }

    //--//

    {   //
        stack->m_owningSubThread = th->CurrentSubThread();  // CLR_RT_SubThread*         m_owningSubThread;  // EVENT HEAP - NO RELOCATION -
        stack->m_owningThread    = th;                      // CLR_RT_Thread*            m_owningThread;     // EVENT HEAP - NO RELOCATION -
        // CLR_UINT32                m_flags;
        //
        stack->m_call            = *callInstPtr;            // CLR_RT_MethodDef_Instance m_call;
        //
        // CLR_RT_MethodHandler      m_nativeMethod;
        // CLR_PMETADATA             m_IPstart;          // ANY   HEAP - DO RELOCATION -
        // CLR_PMETADATA             m_IP;               // ANY   HEAP - DO RELOCATION -
        //
        stack->m_locals          = stack->m_extension;      // CLR_RT_HeapBlock*         m_locals;           // EVENT HEAP - NO RELOCATION -
        stack->m_evalStack       = stack->m_extension + sizeLocals;                      // CLR_RT_HeapBlock*         m_evalStack;        // EVENT HEAP - NO RELOCATION -
        stack->m_evalStackPos    = stack->m_evalStack;      // CLR_RT_HeapBlock*         m_evalStackPos;     // EVENT HEAP - NO RELOCATION -
        stack->m_evalStackEnd    = stack->m_evalStack + sizeEvalStack;                      // CLR_RT_HeapBlock*         m_evalStackEnd;     // EVENT HEAP - NO RELOCATION -
        stack->m_arguments       = NULL;                    // CLR_RT_HeapBlock*         m_arguments;        // EVENT HEAP - NO RELOCATION -
        //
        // union
        // {
        stack->m_customState     = 0;                       //    CLR_UINT32             m_customState;
        //    void*                  m_customPointer;
        // };
        //
#if defined(TINYCLR_PROFILE_NEW_CALLS)
        stack->m_callchain.Enter( stack );                  // CLR_PROF_CounterCallChain m_callchain;
#endif
        //
        // CLR_RT_HeapBlock          m_extension[1];
        //
#if defined(ENABLE_NATIVE_PROFILER)
        stack->m_fNativeProfiled = stack->m_owningThread->m_fNativeProfiled;
#endif
        CLR_RT_MethodHandler impl;

#if defined(TINYCLR_APPDOMAINS)
        stack->m_appDomain = g_CLR_RT_ExecutionEngine.GetCurrentAppDomain();
#endif

        if(md->flags & CLR_RECORD_METHODDEF::MD_DelegateInvoke) // Special case for delegate calls.
        {
            stack->m_nativeMethod = (CLR_RT_MethodHandler)CLR_RT_Thread::Execute_DelegateInvoke;

            stack->m_flags   = CLR_RT_StackFrame::c_MethodKind_Native;
            stack->m_IPstart = NULL;
        }
        else if(assm->m_nativeCode && (impl = assm->m_nativeCode[ stack->m_call.Method() ]) != NULL)
        {
            stack->m_nativeMethod = impl;

            stack->m_flags   = CLR_RT_StackFrame::c_MethodKind_Native;
            stack->m_IPstart = NULL;
            stack->m_IP      = NULL;
        }
#if defined(TINYCLR_JITTER)
        else if(assm->m_jittedCode && (impl = assm->m_jittedCode[ stack->m_call.Method() ]) != NULL)
        {
            stack->m_nativeMethod = (CLR_RT_MethodHandler)(size_t)g_thunkTable.m_address__Internal_Initialize;

            stack->m_flags   = CLR_RT_StackFrame::c_MethodKind_Jitted;
            stack->m_IPstart = (CLR_PMETADATA)impl;

            if(md->flags & CLR_RECORD_METHODDEF::MD_HasExceptionHandlers)
            {
                CLR_UINT32 numEh = *(CLR_UINT32*)stack->m_IPstart;

                stack->m_IP = stack->m_IPstart + sizeof(CLR_UINT32) + numEh * sizeof(CLR_RT_ExceptionHandler);
            }
            else
            {
                stack->m_IP = stack->m_IPstart;
            }
        }
#endif
        else
        {
            stack->m_nativeMethod = (CLR_RT_MethodHandler)CLR_RT_Thread::Execute_IL;

            if(md->RVA == CLR_EmptyIndex) TINYCLR_SET_AND_LEAVE(CLR_E_NOT_SUPPORTED);

            stack->m_flags   = CLR_RT_StackFrame::c_MethodKind_Interpreted;
            stack->m_IPstart = assm->GetByteCode( md->RVA );
            stack->m_IP      = stack->m_IPstart;
        }

#if defined(ENABLE_NATIVE_PROFILER)
        if(stack->m_owningThread->m_fNativeProfiled == false && md->flags & CLR_RECORD_METHODDEF::MD_NativeProfiled)
        {
            stack->m_flags |= CLR_RT_StackFrame::c_NativeProfiled;
            stack->m_owningThread->m_fNativeProfiled = true;
        }
#endif

        //--//

        th->m_stackFrames.LinkAtBack( stack );

#if defined(TINYCLR_PROFILE_NEW_CALLS)
        g_CLR_PRF_Profiler.RecordFunctionCall( th, callInst );
#endif
    }

    if(md->numLocals)
    {
        g_CLR_RT_ExecutionEngine.InitializeLocals( stack->m_locals, assm, md );
    }

    {
        CLR_UINT32 flags = md->flags & (md->MD_Synchronized | md->MD_GloballySynchronized);

        if(flags)
        {
            if(flags & md->MD_Synchronized        ) stack->m_flags |= c_NeedToSynchronize;
            if(flags & md->MD_GloballySynchronized) stack->m_flags |= c_NeedToSynchronizeGlobally;
        }
    }

#if defined(TINYCLR_ENABLE_SOURCELEVELDEBUGGING)
    stack->m_depth = stack->Caller()->Prev() ? stack->Caller()->m_depth + 1 : 0;

    if(g_CLR_RT_ExecutionEngine.m_breakpointsNum)
    {
        if(stack->m_call.DebuggingInfo().HasBreakpoint())
        {
            stack->m_flags |= CLR_RT_StackFrame::c_HasBreakpoint;
        }

        if(stack->m_owningThread->m_fHasJMCStepper || (stack->m_flags & c_HasBreakpoint) || (caller->Prev() != NULL && (caller->m_flags & c_HasBreakpoint)))
        {
            g_CLR_RT_ExecutionEngine.Breakpoint_StackFrame_Push( stack, CLR_DBG_Commands::Debugging_Execution_BreakpointDef::c_DEPTH_STEP_CALL );
        }
    }
#endif

    //--//

#if defined(TINYCLR_JITTER)
    if(s_CLR_RT_fJitter_Enabled && (stack->m_flags & CLR_RT_StackFrame::c_MethodKind_Mask) == CLR_RT_StackFrame::c_MethodKind_Interpreted)
    {
        CLR_RT_ExecutionEngine::ExecutionConstraint_Suspend();

        g_CLR_RT_ExecutionEngine.Compile( stack->m_call, CLR_RT_ExecutionEngine::c_Compile_ARM );

        CLR_RT_ExecutionEngine::ExecutionConstraint_Resume();

        if(assm->m_jittedCode)
        {
            CLR_PMETADATA ipStart = (CLR_PMETADATA)assm->m_jittedCode[ stack->m_call.Method() ];

            if(ipStart != NULL)
            {
                stack->m_nativeMethod = (CLR_RT_MethodHandler)(size_t)g_thunkTable.m_address__Internal_Initialize;

                stack->m_IPstart = ipStart;

                if(md->flags & CLR_RECORD_METHODDEF::MD_HasExceptionHandlers)
                {
                    CLR_UINT32 numEh = *(CLR_UINT32*)ipStart;

                    stack->m_IP = ipStart + sizeof(CLR_UINT32) + numEh * sizeof(CLR_RT_ExceptionHandler);
                }
                else
                {
                    stack->m_IP = ipStart;
                }

                stack->m_flags &= ~CLR_RT_StackFrame::c_MethodKind_Mask;
                stack->m_flags |=  CLR_RT_StackFrame::c_MethodKind_Jitted;
            }
        }
    }
#endif

    if(caller->Prev() != NULL && caller->m_nativeMethod == stack->m_nativeMethod)
    {
        if(stack->m_flags & CLR_RT_StackFrame::c_ProcessSynchronize)
        {
            stack->m_flags |= CLR_RT_StackFrame::c_CallerIsCompatibleForRet;
        }
        else
        {
            stack->m_flags |= CLR_RT_StackFrame::c_CallerIsCompatibleForCall | CLR_RT_StackFrame::c_CallerIsCompatibleForRet;
        }
    }

    //
    // If the arguments are in the caller's stack frame (var == 0), let's link the two.
    //
    if(extraBlocks < 0)
    {
#if defined(PLATFORM_WINDOWS) || (defined(PLATFORM_WINCE) && defined(_DEBUG))
        if(caller->m_evalStackPos > caller->m_evalStackEnd)
        {
            TINYCLR_SET_AND_LEAVE(CLR_E_STACK_OVERFLOW);
        }
#endif

        //
        // Everything is set up correctly, pop the operands.
        //
        stack->m_arguments = &caller->m_evalStackPos[ -md->numArgs ];

        caller->m_evalStackPos = stack->m_arguments;

#if defined(PLATFORM_WINDOWS) || (defined(PLATFORM_WINCE) && defined(_DEBUG))
        if(stack->m_arguments < caller->m_evalStack)
        {
            TINYCLR_SET_AND_LEAVE(CLR_E_STACK_UNDERFLOW);
        }
#endif
    }
    else
    {
        stack->m_arguments = stack->m_evalStackEnd;
    }

    TINYCLR_CLEANUP();


    TINYCLR_CLEANUP_END();
}