#include "daScript/simulate/simulate.h"
#include "daScript/ast/ast.h"
#include "daScript/misc/fpe.h"
#include
namespace das
{
// Context
std::recursive_mutex g_DebugAgentMutex;
das_safe_map g_DebugAgents;
static DAS_THREAD_LOCAL(bool) g_isInDebugAgentCreation;
extern atomic g_envTotal;
template
void on_debug_agent_mutex ( const TT & lmbd ) {
std::lock_guard guard(g_DebugAgentMutex);
lmbd ();
}
template
void for_each_debug_agent ( const TT & lmbd ) {
if ( g_envTotal > 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) {
ref_count_magic = TRACK_PTR_CONTEXT;
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);
gcLogTime = options.getBoolOption("log_gc_time", policies.log_gc_time);
persistent = options.getBoolOption("persistent_heap", policies.persistent_heap);
if ( persistent ) {
heap = make_unique();
stringHeap = make_unique();
} else {
heap = make_unique();
stringHeap = make_unique();
}
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) );
bool track = options.getBoolOption("track_allocations", policies.track_allocations);
heap->setTrackAllocations(track);
stringHeap->setTrackAllocations(track);
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 eval(*this);
#if DAS_ENABLE_STACK_WALK
pp->info = nullptr;
#endif
}
}
}
}
abiArg = nullptr;
stack.pop(EP,SP);
// run init functions
for ( int j=0, js=totalInitFunctions; j!=js && !stopFlags; ++j ) {
auto & pf = initFunctions[j];
callOrFastcall(pf, nullptr, 0);
}
// now, share the data
if ( sharedOwner && shared ) {
SharedDataWalker sdw;
for ( int i=0, is=totalVariables; i!=is; ++i ) {
auto & pv = globalVariables[i];
if ( pv.init && pv.shared ) {
sdw.walk(shared + pv.offset, pv.debugInfo);
}
}
}
}
bool Context::runShutdownScript ( ) {
DAS_ASSERTF(insideContext==0,"can't run init script on the locked context");
if ( shutdown ) return false;
shutdown = true;
auto ssz = 16384 + globalInitStackSize;
StackAllocator init_stack(ssz);
SharedStackGuard guard(*this, init_stack);
return runWithCatch([&](){
vector lateShutdown;
for ( int j=0, js=totalFunctions; j!=js && !stopFlags; ++j ) {
auto & pf = functions[j];
DAS_ASSERTF(pf.debugInfo, "Missing debug info for %s", pf.name);
if ( pf.debugInfo->flags & FuncInfo::flag_shutdown ) {
if ( pf.debugInfo->flags & FuncInfo::flag_late_shutdown ) {
lateShutdown.push_back(&pf);
} else {
callOrFastcall(&pf, nullptr, 0);
}
}
}
if ( !stopFlags && !lateShutdown.empty() ) {
for ( auto pf : lateShutdown ) {
callOrFastcall(pf, nullptr, 0);
if ( stopFlags ) break;
}
}
});
}
vector Context::findFunctions ( const char * fnname ) const {
vector res;
for ( auto & kv : *tabMnLookup ) {
auto fn = kv.second;
if ( fn!=nullptr && strcmp(fn->name, fnname)==0 ) {
res.push_back(fn);
}
}
return res;
}
SimFunction * Context::findFunction ( const char * fnname ) const {
for ( auto & kv : *tabMnLookup ) {
auto fn = kv.second;
if ( fn!=nullptr && strcmp(fn->name, fnname)==0 ) {
return fn;
}
}
return nullptr;
}
SimFunction * Context::findFunction ( const char * fnname, bool & isUnique ) const {
int candidates = 0;
SimFunction * found = nullptr;
for ( auto & kv : *tabMnLookup ) {
auto fn = kv.second;
if ( fn!=nullptr && strcmp(fn->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 " : "\n ");
}
} else {
if ( row>=ROW-3 && rowdebugAgent ) {
(*daScriptEnvironment::g_threadLocalDebugAgent)->debugAgent->onInstrumentFunction(this, sim, entering, userData);
}
}
void Context::instrumentFunctionCallback ( SimFunction * sim, bool entering, uint64_t userData ) {
for_each_debug_agent([&](const DebugAgentPtr & pAgent){
pAgent->onInstrumentFunction(this, sim, entering, userData);
});
}
void Context::bpcallback( const LineInfo & at ) {
for_each_debug_agent([&](const DebugAgentPtr & pAgent){
pAgent->onSingleStep(this, at);
});
}
void Context::runVisitor ( SimVisitor * vis ) const {
for ( int gvi=0, gvis=totalVariables; gvi!=gvis; ++gvi ) {
const auto & gv = globalVariables[gvi];
if ( gv.init ) gv.init->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 ) return;
for_each_debug_agent([&](const DebugAgentPtr & pAgent){
pAgent->onAllocateString(this, ptr, size, tempString, at);
});
}
void Context::onFreeString ( void * ptr, bool tempString, const LineInfo & at ) {
if ( g_envTotal == 0 ) return;
for_each_debug_agent([&](const DebugAgentPtr & pAgent){
pAgent->onFreeString(this, ptr, tempString, at);
});
}
void Context::onAllocate ( void * ptr, uint64_t size, const LineInfo & at ) {
if ( g_envTotal == 0 ) return;
for_each_debug_agent([&](const DebugAgentPtr & pAgent){
pAgent->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 ) return;
for_each_debug_agent([&](const DebugAgentPtr & pAgent){
pAgent->onReallocate(this, ptr, size, newPtr, newSize, at);
});
}
void Context::onFree ( void * ptr, const LineInfo & at ) {
if ( g_envTotal == 0 ) return;
for_each_debug_agent([&](const DebugAgentPtr & pAgent){
pAgent->onFree(this, ptr, at);
});
}
}