[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/nolankramer/daScript/master/src/simulate/simulate.cpp [Back]  [Original]

#include "daScript/misc/platform.h"

#include "daScript/simulate/simulate.h"
#include "daScript/simulate/simulate_nodes.h"
#include "daScript/simulate/runtime_string.h"
#include "daScript/simulate/debug_print.h"
#include "daScript/misc/fpe.h"
#include "daScript/misc/string_writer.h"
#include "daScript/misc/debug_break.h"
#include "daScript/ast/ast.h"
#include "misc/include_fmt.h"

#include 
#include 

namespace das
{

    GcRootLambda::GcRootLambda( const Lambda & that, Context * _context ) : Lambda(that.capture) {
        context = _context;
        context->addGcRoot( (void *)capture, nullptr );
    }

    GcRootLambda::~GcRootLambda() {
        if ( capture && context && (context->category.value & uint32_t(das::ContextCategory::dead)) == 0u ) {
            context->removeGcRoot( (void *)capture );
        }
    }

    bool PointerDimIterator::first ( Context &, char * _value ) {
        char ** value = (char **) _value;
        if ( data != data_end ) {
            *value = *data;
            return true;
        } else {
            return false;
        }
    }

    bool PointerDimIterator::next  ( Context &, char * _value ) {
        char ** value = (char **) _value;
        if ( ++data != data_end ) {
            *value = *data;
            return true;
        } else {
            return false;
        }
    }

    void PointerDimIterator::close ( Context & context, char * _value ) {
        if ( _value ) {
            char ** value = (char **) _value;
            *value = nullptr;
        }
        context.freeIterator((char *)this, debugInfo);
    }

    // this is here to occasionally investigate untyped evaluation paths
    #define WARN_SLOW_CAST(TYPE)
    // #define WARN_SLOW_CAST(TYPE)    DAS_ASSERTF(0, "internal perofrmance issue, casting eval to eval##TYPE" );

    SimNode * SimNode::copyNode ( Context &, NodeAllocator * code ) {
        auto prefix = ((NodePrefix *)this) - 1;
#ifndef DAS_NO_ASSERTIONS
        DAS_ASSERTF(prefix->magic==0xdeadc0de,"node was allocated on the heap without prefix");
#endif
        char * newNode;
        if ( code->prefixWithHeader ) {
            newNode = code->allocate(prefix->size + sizeof(NodePrefix));
            memcpy ( newNode, ((char *)this) - sizeof(NodePrefix), sizeof(NodePrefix));
            newNode += sizeof(NodePrefix);
        } else {
            newNode = code->allocate(prefix->size);
        }
        memcpy ( newNode, (char *)this, prefix->size );
        return (SimNode *) newNode;
    }

    bool SimNode::evalBool ( Context & context ) {
        WARN_SLOW_CAST(Bool);
        return cast::to(eval(context));
    }

    float SimNode::evalFloat ( Context & context ) {
        WARN_SLOW_CAST(Float);
        return cast::to(eval(context));
    }

    double SimNode::evalDouble(Context & context) {
        WARN_SLOW_CAST(Double);
        return cast::to(eval(context));
    }

    int32_t SimNode::evalInt ( Context & context ) {
        WARN_SLOW_CAST(Int);
        return cast::to(eval(context));
    }

    uint32_t SimNode::evalUInt ( Context & context ) {
        WARN_SLOW_CAST(UInt);
        return cast::to(eval(context));
    }

    int64_t SimNode::evalInt64 ( Context & context ) {
        WARN_SLOW_CAST(Int64);
        return cast::to(eval(context));
    }

    uint64_t SimNode::evalUInt64 ( Context & context ) {
        WARN_SLOW_CAST(UInt64);
        return cast::to(eval(context));
    }

    char * SimNode::evalPtr ( Context & context ) {
        WARN_SLOW_CAST(Ptr);
        return cast::to(eval(context));
    }

    SimNode * SimNode_WithErrorMessage::copyNode ( Context & context, NodeAllocator * code ) {
        SimNode_WithErrorMessage * that = (SimNode_WithErrorMessage *) SimNode::copyNode(context, code);
        if ( errorMessage ) {
            that->errorMessage = errorMessage[0]==0 ? "" : code->allocateName(errorMessage);
        }
        return that;
    }

    vec4f SimNode_NOP::eval ( Context & ) {
        return v_zero();
    }

    vec4f SimNode_DeleteStructPtr::eval ( Context & context ) {
        DAS_PROFILE_NODE
        auto pStruct = (char **) subexpr->evalPtr(context);
        pStruct = pStruct + total - 1;
        for ( uint32_t i=0, is=total; i!=is; ++i, pStruct-- ) {
            if ( *pStruct ) {
                if ( persistent ) {
                    das_aligned_free16(*pStruct);
                } else if ( isLambda ) {
                    context.free(*pStruct - 16, structSize + 16, &debugInfo);
                } else {
                    context.free(*pStruct, structSize, &debugInfo);
                }
                *pStruct = nullptr;
            }
        }
        return v_zero();
    }

    vec4f SimNode_DeleteClassPtr::eval ( Context & context ) {
        DAS_PROFILE_NODE
        auto pStruct = (char **) subexpr->evalPtr(context);
        pStruct = pStruct + total - 1;
        auto sizeOf = sizeexpr->evalInt(context);
        for ( uint32_t i=0, is=total; i!=is; ++i, pStruct-- ) {
            if ( *pStruct ) {
                if (persistent) {
                    das_aligned_free16(*pStruct);
                } else {
                    context.free(*pStruct, sizeOf, &debugInfo);
                }
                *pStruct = nullptr;
            }
        }
        return v_zero();
    }

    vec4f SimNode_DeleteLambda::eval ( Context & context ) {
        DAS_PROFILE_NODE
        auto pLambda = (Lambda *) subexpr->evalPtr(context);
        pLambda = pLambda + total - 1;
        for ( uint32_t i=0, is=total; i!=is; ++i, pLambda-- ) {
            if ( pLambda->capture ) {
                SimFunction ** fnMnh = (SimFunction **) pLambda->capture;
                SimFunction * simFunc = fnMnh[1];
                if (!simFunc) context.throw_error_at(debugInfo, "lambda finalizer is a null function%s", errorMessage);
                vec4f argValues[1] = {
                    cast::from(pLambda->capture)
                };
                context.call(simFunc, argValues, 0);
                pLambda->capture = nullptr;
            }
        }
        return v_zero();
    }

    vec4f SimNode_Swizzle::eval ( Context & context ) {
        DAS_PROFILE_NODE
        union {
            vec4f   res;
            int32_t val[4];
        } R, S;
        S.res = value->eval(context);
        R.val[0] = S.val[fields[0]];
        R.val[1] = S.val[fields[1]];
        R.val[2] = S.val[fields[2]];
        R.val[3] = S.val[fields[3]];
        return R.res;
    }

    vec4f SimNode_Swizzle64::eval ( Context & context ) {
        DAS_PROFILE_NODE
        union {
            vec4f   res;
            int64_t val[2];
        } R, S;
        S.res = value->eval(context);
        R.val[0] = S.val[fields[0]];
        R.val[1] = S.val[fields[1]];
        return R.res;
    }

    // SimNode_MakeBlock

    vec4f SimNode_MakeBlock::eval ( Context & context )  {
        DAS_PROFILE_NODE
        Block * block = (Block *) ( context.stack.sp() + stackTop );
        block->stackOffset = context.stack.spi();
        block->argumentsOffset = argStackTop ? (context.stack.spi() + argStackTop) : 0;
        block->body = subexpr;
        block->aotFunction = nullptr;
        block->jitFunction = nullptr;
        block->functionArguments = context.abiArguments();
        block->info = info;
        return cast::from(block);
    }

    // SimNode_Debug

    void das_debug ( Context * context, TypeInfo * typeInfo, const char * FILE, int LINE, vec4f res, const char * message ) {
        TextWriter ssw;
        if ( message ) ssw source_iterators, totalSources*sizeof(SimNode *));
            that->source_iterators = new_source_iterators;
            auto newStackTop = (uint32_t *) (bytes + totalSources * sizeof(SimNode *));
            memcpy ( newStackTop, that->stackTop, totalSources * sizeof(uint32_t));
            that->stackTop = newStackTop;
        } else {
            source_iterators = nullptr;
            stackTop = nullptr;
        }
        return that;
    }

    void SimNode_ForWithIteratorBase::closeIterators ( Iterator ** sources, char ** pi, Context & context ) {
        for ( int t=int(totalSources)-1; t>=0; --t ) {
            sources[t]->close(context, pi[t]);
        }

    }

    vec4f SimNode_ForWithIteratorBase::eval ( Context & context ) {
        // note: this is the 'slow' version, to which we fall back when there are too many sources
        DAS_PROFILE_NODE
        int totalCount = int(totalSources);
        vector pi(totalCount);
        for ( int t=0; t!=totalCount; ++t ) {
            pi[t] = context.stack.sp() + stackTop[t];
        }
        vector sources(totalCount);
        for ( int t=0; t!=totalCount; ++t ) {
            vec4f ll = source_iterators[t]->eval(context);
            sources[t] = cast::to(ll);
        }
        bool needLoop = true;
        SimNode ** __restrict tail = list + total;
        for ( int t=0; t!=totalCount; ++t ) {
            sources[t]->isOpen = true;
            needLoop = sources[t]->first(context, pi[t]) && needLoop;
            if ( context.stopFlags ) goto loopend;
        }
        if ( !needLoop ) goto loopend;
        while ( !context.stopFlags ) {
            SimNode ** __restrict body = list;
        loopbegin:;
            for (; body!=tail; ++body) {
                (*body)->eval(context);
                DAS_PROCESS_LOOP_FLAGS(break);
            }
            for ( int t=0; t!=totalCount; ++t ){
                if ( !sources[t]->next(context, pi[t]) ) goto loopend;
                if ( context.stopFlags ) goto loopend;
            }
        }
    loopend:
        closeIterators(sources.data(), pi.data(), context);
        evalFinal(context);
        context.stopFlags &= ~EvalFlags::stopForBreak;
        return v_zero();
    }

#if DAS_ENABLE_KEEPALIVE

    vec4f SimNodeKeepAlive_ForWithIteratorBase::eval ( Context & context ) {
        // note: this is the 'slow' version, to which we fall back when there are too many sources
        DAS_PROFILE_NODE
        int totalCount = int(totalSources);
        vector pi(totalCount);
        for ( int t=0; t!=totalCount; ++t ) {
            pi[t] = context.stack.sp() + stackTop[t];
        }
        vector sources(totalCount);
        for ( int t=0; t!=totalCount; ++t ) {
            vec4f ll = source_iterators[t]->eval(context);
            sources[t] = cast::to(ll);
        }
        bool needLoop = true;
        SimNode ** __restrict tail = list + total;
        for ( int t=0; t!=totalCount; ++t ) {
            sources[t]->isOpen = true;
            needLoop = sources[t]->first(context, pi[t]) && needLoop;
            if ( context.stopFlags ) goto loopend;
        }
        if ( !needLoop ) goto loopend;
        while ( !context.stopFlags ) {
            SimNode ** __restrict body = list;
        loopbegin:;
            DAS_KEEPALIVE_LOOP(&context);
            for (; body!=tail; ++body) {
                (*body)->eval(context);
                DAS_PROCESS_LOOP_FLAGS(break);
            }
            for ( int t=0; t!=totalCount; ++t ){
                if ( !sources[t]->next(context, pi[t]) ) goto loopend;
                if ( context.stopFlags ) goto loopend;
            }
        }
    loopend:
        closeIterators(sources.data(), pi.data(), context);
        evalFinal(context);
        context.stopFlags &= ~EvalFlags::stopForBreak;
        return v_zero();
    }


#endif

#if DAS_DEBUGGER

    vec4f SimNodeDebug_ForWithIteratorBase::eval ( Context & context ) {
        DAS_PROFILE_NODE
        auto totalCount = int(totalSources);
        vector pi(totalCount);
        for ( int t=0; t!=totalCount; ++t ) {
            pi[t] = context.stack.sp() + this->stackTop[t];
        }
        vector sources(totalCount);
        for ( int t=0; t!=totalCount; ++t ) {
            vec4f ll = this->source_iterators[t]->eval(context);
            sources[t] = cast::to(ll);
        }
        bool needLoop = true;
        SimNode ** __restrict tail = this-> list + this->total;
        for ( int t=0; t!=totalCount; ++t ) {
            sources[t]->isOpen = true;
            needLoop = sources[t]->first(context, pi[t]) && needLoop;
            if ( context.stopFlags ) goto loopend;
        }
        if ( !needLoop ) goto loopend;
        while ( !context.stopFlags ) {
            SimNode ** __restrict body = this->list;
        loopbegin:;
            for (; body!=tail; ++body) {
                DAS_SINGLE_STEP(context,(*body)->debugInfo,true);
                (*body)->eval(context);
                DAS_PROCESS_LOOP_FLAGS(break);
            }
            for ( int t=0; t!=totalCount; ++t ){
                if ( !sources[t]->next(context, pi[t]) ) goto loopend;
                if ( context.stopFlags ) goto loopend;
            }
        }
    loopend:
        closeIterators(sources.data(), pi.data(), context);
        this->evalFinal(context);
        context.stopFlags &= ~EvalFlags::stopForBreak;
        return v_zero();
    }

#endif

    // SimNode_CallBase

    SimNode * SimNode_CallBase::copyNode ( Context & context, NodeAllocator * code ) {
        SimNode_CallBase * that = (SimNode_CallBase *) SimNode_WithErrorMessage::copyNode(context, code);
        if ( nArguments ) {
            SimNode ** newArguments = (SimNode **) code->allocate(nArguments * sizeof(SimNode *));
            memcpy ( newArguments, that->arguments, nArguments * sizeof(SimNode *));
            that->arguments = newArguments;
            if ( that->types ) {
                TypeInfo ** newTypes = (TypeInfo **) code->allocate(nArguments * sizeof(TypeInfo **));
                memcpy ( newTypes, that->types, nArguments * sizeof(TypeInfo **));
                that->types = newTypes;
            }
        }
        if ( fnPtr ) {
            that->fnPtr = context.fnByMangledName(fnPtr->mangledNameHash);
            // printf("CALL %p -> %p\n", fnPtr, fnPtr );
        }
        return that;
    }

    // SimNode_Final

    SimNode * SimNode_Final::copyNode ( Context & context, NodeAllocator * code ) {
        SimNode_Final * that = (SimNode_Final *) SimNode::copyNode(context, code);
        if ( totalFinal ) {
            SimNode ** newList = (SimNode **) code->allocate(totalFinal * sizeof(SimNode *));
            memcpy ( newList, that->finalList, totalFinal*sizeof(SimNode *));
            that->finalList = newList;
        }
        return that;
    }

    // SimNode_Block

    SimNode * SimNode_Block::copyNode ( Context & context, NodeAllocator * code ) {
        SimNode_Block * that = (SimNode_Block *) SimNode_Final::copyNode(context, code);
        if ( total ) {
            SimNode ** newList = (SimNode **) code->allocate(total * sizeof(SimNode *));
            memcpy ( newList, that->list, total*sizeof(SimNode *));
            that->list = newList;
        }
        if ( totalLabels ) {
            uint32_t * newLabels = (uint32_t *) code->allocate(totalLabels * sizeof(uint32_t));
            memcpy ( newLabels, that->labels, totalLabels*sizeof(uint32_t));
            that->labels = newLabels;
        }
        return that;
    }

    vec4f SimNode_Block::eval ( Context & context ) {
        DAS_PROFILE_NODE
        SimNode ** __restrict tail = list + total;
        for (SimNode ** __restrict body = list; body!=tail; ++body) {
            (*body)->eval(context);
            if ( context.stopFlags ) break;
        }
        evalFinal(context);
        return v_zero();
    }

#if DAS_DEBUGGER

    vec4f SimNodeDebug_Block::eval ( Context & context ) {
        DAS_PROFILE_NODE
        SimNode ** __restrict tail = list + total;
        for (SimNode ** __restrict body = list; body!=tail; ++body) {
            DAS_SINGLE_STEP(context,(*body)->debugInfo,false);
            (*body)->eval(context);
            if ( context.stopFlags ) break;
        }
        evalFinalSingleStep(context);
        return v_zero();
    }

#endif

    vec4f SimNode_BlockNF::eval ( Context & context ) {
        DAS_PROFILE_NODE
        SimNode ** __restrict tail = list + total;
        for (SimNode ** __restrict body = list; body!=tail; ++body) {
            (*body)->eval(context);
            if ( context.stopFlags ) break;
        }
        return v_zero();
    }

#if DAS_DEBUGGER

    vec4f SimNodeDebug_BlockNF::eval ( Context & context ) {
        DAS_PROFILE_NODE
        SimNode ** __restrict tail = list + total;
        for (SimNode ** __restrict body = list; body!=tail; ++body) {
            DAS_SINGLE_STEP(context,(*body)->debugInfo,false);
            (*body)->eval(context);
            if ( context.stopFlags ) break;
        }
        return v_zero();
    }

#endif

    vec4f SimNode_ClosureBlock::eval ( Context & context ) {
        DAS_PROFILE_NODE
        SimNode ** __restrict tail = list + total;
        for (SimNode ** __restrict body = list; body!=tail; ++body) {
            (*body)->eval(context);
            if ( context.stopFlags ) break;
        }
        evalFinal(context);
        if ( context.stopFlags & EvalFlags::stopForReturn ) {
            context.stopFlags &= ~EvalFlags::stopForReturn;
            return context.abiResult();
        } else {
            if ( needResult ) context.throw_error_at(debugInfo,"end of block without return");
            return v_zero();
        }
    }

#if DAS_DEBUGGER

    vec4f SimNodeDebug_ClosureBlock::eval ( Context & context ) {
        DAS_PROFILE_NODE
        SimNode ** __restrict tail = list + total;
        for (SimNode ** __restrict body = list; body!=tail; ++body) {
            DAS_SINGLE_STEP(context,(*body)->debugInfo,false);
            (*body)->eval(context);
            if ( context.stopFlags ) break;
        }
        evalFinalSingleStep(context);
        if ( context.stopFlags & EvalFlags::stopForReturn ) {
            context.stopFlags &= ~EvalFlags::stopForReturn;
            return context.abiResult();
        } else {
            if ( needResult ) context.throw_error_at(debugInfo,"end of block without return");
            return v_zero();
        }
    }

#endif

// SimNode_BlockWithLabels

    vec4f SimNode_BlockWithLabels::eval ( Context & context ) {
        DAS_PROFILE_NODE
        SimNode ** __restrict tail = list + total;
        SimNode ** __restrict body = list;
    loopbegin:;
        for (; body!=tail; ++body) {
            (*body)->eval(context);
            { if ( context.stopFlags ) {
                if (context.stopFlags&EvalFlags::jumpToLabel) {
                    if (  context.gotoLabel>=totalLabels ) {
                        context.throw_error_at(debugInfo, "invalid label index %u", context.gotoLabel);
                    }
                    body=list+labels[context.gotoLabel];
                    if ( body>=list && bodydebugInfo,false);
            (*body)->eval(context);
            { if ( context.stopFlags ) {
                if (context.stopFlags&EvalFlags::jumpToLabel) {
                    if (  context.gotoLabel>=totalLabels ) {
                        context.throw_error_at(debugInfo, "invalid label index %u", context.gotoLabel);
                    }
                    body=list+labels[context.gotoLabel];
                    if ( body>=list && bodyeval(context);
        }
        return v_zero();
    }

    // SimNode_While

    vec4f SimNode_While::eval ( Context & context ) {
        DAS_PROFILE_NODE
        SimNode ** __restrict tail = list + total;
        while ( cond->evalBool(context) && !context.stopFlags ) {
            SimNode ** __restrict body = list;
        loopbegin:;
            for (; body!=tail; ++body) {
                (*body)->eval(context);
                DAS_PROCESS_LOOP_FLAGS(break);
            }
        }
    loopend:;
        evalFinal(context);
        context.stopFlags &= ~EvalFlags::stopForBreak;
        return v_zero();
    }

#if DAS_DEBUGGER

    vec4f SimNodeDebug_While::eval ( Context & context ) {
        DAS_PROFILE_NODE
        SimNode ** __restrict tail = list + total;
        while ( cond->evalBool(context) && !context.stopFlags ) {
            SimNode ** __restrict body = list;
        loopbegin:;
            for (; body!=tail; ++body) {
                DAS_SINGLE_STEP(context,(*body)->debugInfo,true);
                (*body)->eval(context);
                DAS_PROCESS_LOOP_FLAGS(break);
            }
        }
    loopend:;
        evalFinalSingleStep(context);
        context.stopFlags &= ~EvalFlags::stopForBreak;
        return v_zero();
    }

#endif

#if DAS_ENABLE_KEEPALIVE
    vec4f SimNodeKeepAlive_While::eval ( Context & context ) {
        DAS_PROFILE_NODE
        SimNode ** __restrict tail = list + total;
        while ( cond->evalBool(context) && !context.stopFlags ) {
            SimNode ** __restrict body = list;
        loopbegin:;
            DAS_KEEPALIVE_LOOP(&context);
            for (; body!=tail; ++body) {
                (*body)->eval(context);
                DAS_PROCESS_LOOP_FLAGS(break);
            }
        }
    loopend:;
        evalFinal(context);
        context.stopFlags &= ~EvalFlags::stopForBreak;
        return v_zero();
    }
#endif

    // Return

    vec4f SimNode_Return::eval ( Context & context ) {
        DAS_PROFILE_NODE
        if ( subexpr ) context.abiResult() = subexpr->eval(context);
        context.stopFlags |= EvalFlags::stopForReturn;
        return v_zero();
    }

    vec4f SimNode_ReturnNothing::eval ( Context & context ) {
        DAS_PROFILE_NODE
        context.stopFlags |= EvalFlags::stopForReturn;
        return v_zero();
    }

    vec4f SimNode_ReturnConst::eval ( Context & context ) {
        DAS_PROFILE_NODE
        context.abiResult() = value;
        context.stopFlags |= EvalFlags::stopForReturn;
        return v_zero();
    }

    vec4f SimNode_ReturnConstString::eval ( Context & context ) {
        DAS_PROFILE_NODE
        context.abiResult() = cast::from(value);
        context.stopFlags |= EvalFlags::stopForReturn;
        return v_zero();
    }

    vec4f SimNode_ReturnRefAndEval::eval ( Context & context ) {
        DAS_PROFILE_NODE
        auto pl = context.abiCopyOrMoveResult();
        DAS_ASSERT(pl);
        auto pR = ((char **)(context.stack.sp() + stackTop));
        *pR = pl;
        subexpr->evalPtr(context);;
        context.abiResult() = cast::from(pl);
        context.stopFlags |= EvalFlags::stopForReturn;
        return v_zero();
    }

    vec4f SimNode_ReturnAndCopy::eval ( Context & context ) {
        DAS_PROFILE_NODE
        auto pr = subexpr->evalPtr(context);
        auto pl = context.abiCopyOrMoveResult();
        DAS_ASSERT(pl);
        memcpy ( pl, pr, size);
        context.abiResult() = cast::from(pl);
        context.stopFlags |= EvalFlags::stopForReturn;
        return v_zero();
    }

    vec4f SimNode_ReturnAndMove::eval ( Context & context ) {
        DAS_PROFILE_NODE
        auto pr = subexpr->evalPtr(context);
        auto pl = context.abiCopyOrMoveResult();
        DAS_ASSERT(pl);
        if ( pl != pr ) {
            memcpy ( pl, pr, size);
            memset ( pr, 0, size);
        }
        context.abiResult() = cast::from(pl);
        context.stopFlags |= EvalFlags::stopForReturn;
        return v_zero();
    }

    vec4f SimNode_ReturnReference::eval ( Context & context ) {
        DAS_PROFILE_NODE
        char * ref = subexpr->evalPtr(context);
        if ( context.stack.bottom()stackSize;
        if ( context.stack.sp()evalPtr(context);;
        context.abiResult() = cast::from(pl);
        context.stopFlags |= EvalFlags::stopForReturn;
        return v_zero();
    }

    vec4f SimNode_ReturnAndCopyFromBlock::eval ( Context & context ) {
        DAS_PROFILE_NODE
        auto pr = subexpr->evalPtr(context);
        auto ba = (BlockArguments *) ( context.stack.sp() + argStackTop );
        auto pl = ba->copyOrMoveResult;
        memcpy ( pl, pr, size);
        context.abiResult() = cast::from(pl);
        context.stopFlags |= EvalFlags::stopForReturn;
        return v_zero();
    }

    vec4f SimNode_ReturnAndMoveFromBlock::eval ( Context & context ) {
        DAS_PROFILE_NODE
        auto pr = subexpr->evalPtr(context);
        auto ba = (BlockArguments *) ( context.stack.sp() + argStackTop );
        auto pl = ba->copyOrMoveResult;
        if ( pl != pr ) {
            memcpy ( pl, pr, size);
            memset ( pr, 0, size);
        }
        context.abiResult() = cast::from(pl);
        context.stopFlags |= EvalFlags::stopForReturn;
        return v_zero();
    }

    vec4f SimNode_ReturnReferenceFromBlock::eval ( Context & context ) {
        DAS_PROFILE_NODE
        char * ref = subexpr->evalPtr(context);
        if ( context.stack.bottom() 0 && *daScriptEnvironment::g_threadLocalDebugAgent && (*daScriptEnvironment::g_threadLocalDebugAgent)->debugAgent ) {
            lmbd ( (*daScriptEnvironment::g_threadLocalDebugAgent)->debugAgent );
        }
        std::lock_guard guard(g_DebugAgentMutex);
        for ( auto & it : g_DebugAgents ) {
            if ( !it.second.debugAgent ) continue;
            lmbd ( it.second.debugAgent );
        }
    }

    void dapiReportContextState ( Context & ctx, const char * category, const char * name, const TypeInfo * info, void * data ) {
        for_each_debug_agent([&](const DebugAgentPtr & pAgent){
            pAgent->onVariable(&ctx,category,name,(TypeInfo*)info,data);
        });
    }

    void dapiSimulateContext ( Context & ctx ) {
        for_each_debug_agent([&]( const DebugAgentPtr & pAgent ){
            pAgent->onSimulateContext(&ctx);
        });
    }

    void dapiUserCommand ( const char * command ) {
        if ( !command ) command = "";
        bool any = false;
        for_each_debug_agent([&]( const DebugAgentPtr & pAgent ){
            if ( !any ) any = pAgent->onUserCommand(command);
        });
    }

    void dapiOnBeforeGC ( Context & ctx ) {
        for_each_debug_agent([&]( const DebugAgentPtr & pAgent ){
            pAgent->onBeforeGC(&ctx);
        });
    }

    void dapiOnAfterGC ( Context & ctx ) {
        for_each_debug_agent([&]( const DebugAgentPtr & pAgent ){
            pAgent->onAfterGC(&ctx);
        });
    }

    Context::Context(uint32_t stackSize, bool ph) : stack(stackSize) {
        code = make_shared();
        constStringHeap = make_shared();
        debugInfo = make_shared();
        ownStack = (stackSize != 0);
        persistent = ph;
    }

    void Context::setup(int totalVars, uint32_t globalStringHeapSize, CodeOfPolicies policies, AnnotationArgumentList options) {
        verySafeContext = options.getBoolOption("very_safe_context",policies.very_safe_context);
        breakOnException |= policies.debugger;
        gcEnabled = options.getBoolOption("gc", false);
        persistent = options.getBoolOption("persistent_heap", policies.persistent_heap);
        if ( persistent ) {
            heap = make_smart();
            stringHeap = make_smart();
        } else {
            heap = make_smart();
            stringHeap = make_smart();
        }
        heap->setInitialSize ( options.getIntOption("heap_size_hint", policies.heap_size_hint) );
        heap->setLimit ( options.getUInt64OptionEx("heap_size_limit", "max_heap_allocated", policies.max_heap_allocated) );
        stringHeap->setInitialSize ( options.getIntOption("string_heap_size_hint", policies.string_heap_size_hint) );
        stringHeap->setLimit ( options.getUInt64OptionEx("string_heap_size_limit", "max_string_heap_allocated", policies.max_string_heap_allocated) );
        constStringHeap = make_shared();
        totalVariables = totalVars;
        if ( globalStringHeapSize ) {
            constStringHeap->setInitialSize(globalStringHeapSize);
        }
        globalVariables = (GlobalVariable *) code->allocate( uint32_t(totalVars*sizeof(GlobalVariable)) );
        globalsSize = 0;
        sharedSize = 0;
    }

    void Context::strip() {
        stringHeap.reset();
        heap.reset();
        stack.strip();
        if ( globals && globalsOwner ) {
            das_aligned_free16(globals);
            globals = nullptr;
        }
        if ( shared && sharedOwner ) {
            das_aligned_free16(shared);
            shared = nullptr;
        }
    }

    void Context::logMemInfo(TextWriter & tw) {
        uint64_t bytesTotal = 0, bytesUsed = 0;
    // context
        tw name, fnname)==0 ) {
                found = fn;
                candidates++;
            }
        }
        isUnique = candidates == 1;
        return found;
    }

    int Context::findVariable ( const char * fnname ) const {
        for ( int vni=0, vnis=totalVariables; vni!=vnis; ++vni ) {
            if ( strcmp(globalVariables[vni].name, fnname)==0 ) {
                return vni;
            }
        }
        return -1;
    }

    void Context::stackWalk( const LineInfo * at, bool showArguments, bool showLocalVariables ) {
        auto str = getStackWalk(at, showArguments, showLocalVariables);
        to_out(at, str.c_str());
    }

    class StackWalkerTextWriter : public StackWalker {
    public:
        StackWalkerTextWriter ( TextWriter & tw, Context * ctx ) : ssw(tw), context(ctx) {}
        virtual bool canWalkArguments () override {
            return showArguments;
        }
        virtual bool canWalkVariables () override {
            return showLocalVariables;
        }
        virtual bool canWalkOutOfScopeVariables() override {
            return showOutOfScope;
        }
        virtual void onCallAOT ( Prologue *, const char * fileName ) override {
            ssw callOrFastcall(fun, args, lineinfo);
    }

    bool isInDebugAgentCreation() {
        return *g_isInDebugAgentCreation;
    }

    void shutdownDebugAgent() {
        bool hasThreadLocal = *daScriptEnvironment::g_threadLocalDebugAgent && (*daScriptEnvironment::g_threadLocalDebugAgent)->debugAgent;
        DebugAgent * threadLocalDebugAgent = hasThreadLocal ? (*daScriptEnvironment::g_threadLocalDebugAgent)->debugAgent.get() : nullptr;
        for_each_debug_agent([&](const DebugAgentPtr & pAgent){
            if ( hasThreadLocal ) {
                threadLocalDebugAgent->onUninstall(pAgent.get());
            }
            for ( auto & ap : g_DebugAgents ) {
                if ( ap.second.debugAgent ) {
                    ap.second.debugAgent->onUninstall(pAgent.get());
                }
            }
        });
        das_safe_map agents;
        {
            std::lock_guard guard(g_DebugAgentMutex);
            swap(agents, g_DebugAgents);
            delete (*daScriptEnvironment::g_threadLocalDebugAgent);
            (*daScriptEnvironment::g_threadLocalDebugAgent) = {};
        }
        // release agents before contexts to avoid use-after-free
        // (agent objects live on the context heap)
        for ( auto & ap : agents ) {
            ap.second.debugAgent.reset();
        }
    }

    void shutdownThreadLocalDebugAgent() {
        bool hasThreadLocal = *daScriptEnvironment::g_threadLocalDebugAgent && (*daScriptEnvironment::g_threadLocalDebugAgent)->debugAgent;
        if ( hasThreadLocal ) {
            DebugAgent * threadLocalDebugAgent = (*daScriptEnvironment::g_threadLocalDebugAgent)->debugAgent.get();
            for_each_debug_agent([&](const DebugAgentPtr & pAgent){
                pAgent->onUninstall(threadLocalDebugAgent);
            });
            {
                std::lock_guard guard(g_DebugAgentMutex);
                delete (*daScriptEnvironment::g_threadLocalDebugAgent);
                (*daScriptEnvironment::g_threadLocalDebugAgent) = {};
            }
        }
    }

    void Context::triggerHwBreakpoint ( void * addr, int index ) {
        singleStepMode = true;
        hwBpAddress = addr;
        hwBpIndex = index;
    }

    void Context::breakPoint(const LineInfo & at, const char * reason, const char * text) {
        if ( debugger ) {
            bool any = false;
            for_each_debug_agent([&](const DebugAgentPtr & pAgent){
                pAgent->onBreakpoint(this, at, reason, text);
                any = true;
            });
            if ( any ) return;
        }
        os_debug_break();
    }

    static DAS_THREAD_LOCAL(bool) g_inLogger;

    void Context::to_out ( const LineInfo * at, int level, const char * message ) {
        if (message) {
            if ( !*g_inLogger ) {
                *g_inLogger = true;
                bool any = false;
                for_each_debug_agent([&](const DebugAgentPtr & pAgent){
                    any |= pAgent->onLog(this, at, level, message);
                });
                *g_inLogger = false;
                if ( any ) return;
            }
            const char * prefix = getLogMarker(level);
            das_to_stdout_level_prefix_text(level, prefix, message);
        }
    }

    void Context::throw_error_at ( const LineInfo * at, DAS_FORMAT_STRING_PREFIX const char * message, ... ) {
        const int PRINT_BUFFER_SIZE = 8192;
        char buffer[PRINT_BUFFER_SIZE];
        va_list args;
        va_start (args, message);
        vsnprintf (buffer,PRINT_BUFFER_SIZE,message, args);
        va_end (args);
        throw_fatal_error(buffer, at ? *at : LineInfo());
    }

    void Context::throw_error_at ( const LineInfo & at, DAS_FORMAT_STRING_PREFIX const char * message, ... ) {
        const int PRINT_BUFFER_SIZE = 8192;
        char buffer[PRINT_BUFFER_SIZE];
        va_list args;
        va_start (args, message);
        vsnprintf (buffer,PRINT_BUFFER_SIZE,message, args);
        va_end (args);
        throw_fatal_error(buffer, at);
    }

    void Context::throw_out_of_memory ( bool isStringHeap, uint32_t size, const LineInfo * at ) {
        if ( isStringHeap ) {
            throw_error_at(at, "out of string heap memory, requested %u bytes, used %llu / limit %llu", size, (unsigned long long) stringHeap->bytesAllocated(), (unsigned long long) stringHeap->getLimit());
        } else {
            throw_error_at(at, "out of heap memory, requested %u bytes, used %llu / limit %llu", size, (unsigned long long) heap->bytesAllocated(), (unsigned long long) heap->getLimit());
        }
    }

    void Context::throw_error_ex ( DAS_FORMAT_STRING_PREFIX const char * message, ... ) {
        const int PRINT_BUFFER_SIZE = 8192;
        char buffer[PRINT_BUFFER_SIZE];
        va_list args;
        va_start (args, message);
        vsnprintf (buffer,PRINT_BUFFER_SIZE,message, args);
        va_end (args);
        throw_fatal_error(buffer, LineInfo());
    }

    void Context::throw_error ( const char * message ) {
        throw_fatal_error(message, LineInfo());
    }

    struct FileInfoCollector : SimVisitor {
        virtual void preVisit ( SimNode * node ) override {
            SimVisitor::preVisit(node);
            if ( auto fi = node->debugInfo.fileInfo ) {
                allFiles.insert(fi);
            }
        }
        das_hash_set    allFiles;
    };

    vector Context::getAllFiles() const {
        vector allFiles;
        FileInfoCollector collector;
        runVisitor(&collector);
        for ( auto & it : collector.allFiles ) {
            allFiles.push_back(it);
        }
        sort ( allFiles.begin(), allFiles.end(), [&]( FileInfo * a, FileInfo * b ){
            return a->name > b->name;
        });
        return allFiles;
    }

    void Context::resetProfiler() {
#if DAS_ENABLE_PROFILER
        auto allFiles = getAllFiles();
        for ( auto fi : allFiles ) {
            fi->profileData.clear();
        }
#endif
    }

    void Context::collectProfileInfo( TextWriter & tout ) {
#if DAS_ENABLE_PROFILER
        uint64_t totalGoo = 0;
        auto allFiles = getAllFiles();
        for ( auto info : allFiles ) {
            for ( auto counter : info->profileData ) {
                totalGoo += counter;
            }
        }
        tout profileData.size()>size_t(line) && fi->profileData[line] ) {
                        uint64_t samples = fi->profileData[line];
                        auto result = fmt::format_to(total, FMT_STRING("{:6.2f}"), samples*100.0/totalGoo); *result = 0;
                        tout visit(*vis);
        }
        for ( int fni=0, fnis=totalFunctions; fni!=fnis; ++fni ) {
            const auto & fn = functions[fni];
            if ( fn.code ) fn.code->visit(*vis);
        }
    }

    void Context::onAllocateString ( void * ptr, uint64_t size, bool tempString, const LineInfo & at ) {
        if ( g_envTotal > 0 && *daScriptEnvironment::g_threadLocalDebugAgent && (*daScriptEnvironment::g_threadLocalDebugAgent)->debugAgent ) {
            (*daScriptEnvironment::g_threadLocalDebugAgent)->debugAgent->onAllocateString(this, ptr, size, tempString, at);
        }
    }

    void Context::onFreeString ( void * ptr, bool tempString, const LineInfo & at ) {
        if ( g_envTotal > 0 && *daScriptEnvironment::g_threadLocalDebugAgent && (*daScriptEnvironment::g_threadLocalDebugAgent)->debugAgent ) {
            (*daScriptEnvironment::g_threadLocalDebugAgent)->debugAgent->onFreeString(this, ptr, tempString, at);
        }
    }

    void Context::onAllocate ( void * ptr, uint64_t size, const LineInfo & at ) {
        if ( g_envTotal > 0 && *daScriptEnvironment::g_threadLocalDebugAgent && (*daScriptEnvironment::g_threadLocalDebugAgent)->debugAgent ) {
            (*daScriptEnvironment::g_threadLocalDebugAgent)->debugAgent->onAllocate(this, ptr, size, at);
        }
    }

    void Context::onReallocate ( void * ptr, uint64_t size, void * newPtr, uint64_t newSize, const LineInfo & at ) {
        if ( g_envTotal > 0 && *daScriptEnvironment::g_threadLocalDebugAgent && (*daScriptEnvironment::g_threadLocalDebugAgent)->debugAgent ) {
            (*daScriptEnvironment::g_threadLocalDebugAgent)->debugAgent->onReallocate(this, ptr, size, newPtr, newSize, at);
        }
    }

    void Context::onFree ( void * ptr, const LineInfo & at ) {
        if ( g_envTotal > 0 && *daScriptEnvironment::g_threadLocalDebugAgent && (*daScriptEnvironment::g_threadLocalDebugAgent)->debugAgent ) {
            (*daScriptEnvironment::g_threadLocalDebugAgent)->debugAgent->onFree(this, ptr, at);
        }
    }

    const LineInfo * SimFunction::getLineInfo() const { return &code->debugInfo; }
}

//workaround compiler bug in MSVC 32 bit
#if defined(_MSC_VER) && !defined(__clang__) && INTPTR_MAX == INT32_MAX
VECTORCALL vec4i v_ldu_ptr(const void * a) {return v_seti_x((int32_t)a);}
#endif

Web Proxy Viewer  |  New URL  |  Original Page