diff options
Diffstat (limited to 'modules/gdscript/gd_script.cpp')
-rw-r--r-- | modules/gdscript/gd_script.cpp | 436 |
1 files changed, 334 insertions, 102 deletions
diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index beec314e44..cd5e35db31 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -32,7 +32,7 @@ #include "gd_compiler.h" #include "os/file_access.h" #include "io/file_access_encrypted.h" - +#include "os/os.h" @@ -199,6 +199,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a int ip=0; int line=_initial_line; + + if (p_state) { //use existing (supplied) state (yielded) stack=(Variant*)p_state->stack.ptr(); @@ -282,8 +284,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a #ifdef DEBUG_ENABLED - if (ScriptDebugger::get_singleton()) - GDScriptLanguage::get_singleton()->enter_function(p_instance,this,stack,&ip,&line); + if (ScriptDebugger::get_singleton()) + GDScriptLanguage::get_singleton()->enter_function(p_instance,this,stack,&ip,&line); #define CHECK_SPACE(m_space)\ ERR_BREAK((ip+m_space)>_code_size) @@ -292,7 +294,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a Variant *m_v; \ m_v = _get_variant(_code_ptr[ip+m_code_ofs],p_instance,_class,self,stack,err_text);\ if (!m_v)\ - break; + break; #else @@ -304,7 +306,18 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a #endif +#ifdef DEBUG_ENABLED + + uint64_t function_start_time; + uint64_t function_call_time; + if (GDScriptLanguage::get_singleton()->profiling) { + function_start_time=OS::get_singleton()->get_ticks_usec(); + function_call_time=0; + profile.call_count++; + profile.frame_call_count++; + } +#endif bool exit_ok=false; while(ip<_code_size) { @@ -461,7 +474,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a bool valid; #ifdef DEBUG_ENABLED -//allow better error message in cases where src and dst are the same stack position + //allow better error message in cases where src and dst are the same stack position Variant ret = src->get(*index,&valid); #else *dst = src->get(*index,&valid); @@ -520,7 +533,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a bool valid; #ifdef DEBUG_ENABLED -//allow better error message in cases where src and dst are the same stack position + //allow better error message in cases where src and dst are the same stack position Variant ret = src->get_named(*index,&valid); #else @@ -662,6 +675,14 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a argptrs[i]=v; } +#ifdef DEBUG_ENABLED + uint64_t call_time; + + if (GDScriptLanguage::get_singleton()->profiling) { + call_time=OS::get_singleton()->get_ticks_usec(); + } + +#endif Variant::CallError err; if (call_ret) { @@ -671,6 +692,11 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a base->call(*methodname,(const Variant**)argptrs,argc,err); } +#ifdef DEBUG_ENABLED + if (GDScriptLanguage::get_singleton()->profiling) { + function_call_time+=OS::get_singleton()->get_ticks_usec() - call_time; + } +#endif if (err.error!=Variant::CallError::CALL_OK) { @@ -774,7 +800,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a const GDScript *gds = _script; - const Map<StringName,GDFunction>::Element *E=NULL; + const Map<StringName,GDFunction*>::Element *E=NULL; while (gds->base.ptr()) { gds=gds->base.ptr(); E=gds->member_functions.find(*methodname); @@ -1082,7 +1108,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a ip+=2; if (ScriptDebugger::get_singleton()) { - // line + // line bool do_break=false; if (ScriptDebugger::get_singleton()->get_lines_left()>0) { @@ -1136,18 +1162,30 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a err_text="Internal Script Error! - opcode #"+itos(last_opcode)+" (report please)."; } - if (!GDScriptLanguage::get_singleton()->debug_break(err_text,false)) { - // debugger break did not happen + if (!GDScriptLanguage::get_singleton()->debug_break(err_text,false)) { + // debugger break did not happen - _err_print_error(err_func.utf8().get_data(),err_file.utf8().get_data(),err_line,err_text.utf8().get_data(),ERR_HANDLER_SCRIPT); - } + _err_print_error(err_func.utf8().get_data(),err_file.utf8().get_data(),err_line,err_text.utf8().get_data(),ERR_HANDLER_SCRIPT); + } break; } - if (ScriptDebugger::get_singleton()) - GDScriptLanguage::get_singleton()->exit_function(); +#ifdef DEBUG_ENABLED + if (GDScriptLanguage::get_singleton()->profiling) { + uint64_t time_taken = OS::get_singleton()->get_ticks_usec() - function_start_time; + profile.total_time+=time_taken; + profile.self_time+=time_taken-function_call_time; + profile.frame_total_time+=time_taken; + profile.frame_self_time+=time_taken-function_call_time; + GDScriptLanguage::get_singleton()->script_frame_time+=time_taken-function_call_time; + + } + +#endif + if (ScriptDebugger::get_singleton()) + GDScriptLanguage::get_singleton()->exit_function(); if (_stack_size) { @@ -1204,76 +1242,76 @@ int GDFunction::get_max_stack_size() const { struct _GDFKC { - int order; - List<int> pos; + int order; + List<int> pos; }; struct _GDFKCS { - int order; - StringName id; - int pos; + int order; + StringName id; + int pos; - bool operator<(const _GDFKCS &p_r) const { + bool operator<(const _GDFKCS &p_r) const { - return order<p_r.order; - } + return order<p_r.order; + } }; void GDFunction::debug_get_stack_member_state(int p_line,List<Pair<StringName,int> > *r_stackvars) const { - int oc=0; - Map<StringName,_GDFKC> sdmap; - for( const List<StackDebug>::Element *E=stack_debug.front();E;E=E->next()) { + int oc=0; + Map<StringName,_GDFKC> sdmap; + for( const List<StackDebug>::Element *E=stack_debug.front();E;E=E->next()) { - const StackDebug &sd=E->get(); - if (sd.line>p_line) - break; + const StackDebug &sd=E->get(); + if (sd.line>p_line) + break; - if (sd.added) { + if (sd.added) { - if (!sdmap.has(sd.identifier)) { - _GDFKC d; - d.order=oc++; - d.pos.push_back(sd.pos); - sdmap[sd.identifier]=d; + if (!sdmap.has(sd.identifier)) { + _GDFKC d; + d.order=oc++; + d.pos.push_back(sd.pos); + sdmap[sd.identifier]=d; - } else { - sdmap[sd.identifier].pos.push_back(sd.pos); - } - } else { + } else { + sdmap[sd.identifier].pos.push_back(sd.pos); + } + } else { - ERR_CONTINUE(!sdmap.has(sd.identifier)); + ERR_CONTINUE(!sdmap.has(sd.identifier)); - sdmap[sd.identifier].pos.pop_back(); - if (sdmap[sd.identifier].pos.empty()) - sdmap.erase(sd.identifier); - } + sdmap[sd.identifier].pos.pop_back(); + if (sdmap[sd.identifier].pos.empty()) + sdmap.erase(sd.identifier); + } - } + } - List<_GDFKCS> stackpositions; - for(Map<StringName,_GDFKC>::Element *E=sdmap.front();E;E=E->next() ) { + List<_GDFKCS> stackpositions; + for(Map<StringName,_GDFKC>::Element *E=sdmap.front();E;E=E->next() ) { - _GDFKCS spp; - spp.id=E->key(); - spp.order=E->get().order; - spp.pos=E->get().pos.back()->get(); - stackpositions.push_back(spp); - } + _GDFKCS spp; + spp.id=E->key(); + spp.order=E->get().order; + spp.pos=E->get().pos.back()->get(); + stackpositions.push_back(spp); + } - stackpositions.sort(); + stackpositions.sort(); - for(List<_GDFKCS>::Element *E=stackpositions.front();E;E=E->next()) { + for(List<_GDFKCS>::Element *E=stackpositions.front();E;E=E->next()) { - Pair<StringName,int> p; - p.first=E->get().id; - p.second=E->get().pos; - r_stackvars->push_back(p); - } + Pair<StringName,int> p; + p.first=E->get().id; + p.second=E->get().pos; + r_stackvars->push_back(p); + } } @@ -1294,15 +1332,47 @@ void GDFunction::clear() { } #endif -GDFunction::GDFunction() { +GDFunction::GDFunction() : function_list(this) { _stack_size=0; _call_size=0; name="<anonymous>"; #ifdef DEBUG_ENABLED _func_cname=NULL; + + if (GDScriptLanguage::get_singleton()->lock) { + GDScriptLanguage::get_singleton()->lock->lock(); + } + GDScriptLanguage::get_singleton()->function_list.add(&function_list); + + if (GDScriptLanguage::get_singleton()->lock) { + GDScriptLanguage::get_singleton()->lock->unlock(); + } + + profile.call_count=0; + profile.self_time=0; + profile.total_time=0; + profile.frame_call_count=0; + profile.frame_self_time=0; + profile.frame_total_time=0; + profile.last_frame_call_count=0; + profile.last_frame_self_time=0; + profile.last_frame_total_time=0; + #endif +} + +GDFunction::~GDFunction() { +#ifdef DEBUG_ENABLED + if (GDScriptLanguage::get_singleton()->lock) { + GDScriptLanguage::get_singleton()->lock->lock(); + } + GDScriptLanguage::get_singleton()->function_list.remove(&function_list); + if (GDScriptLanguage::get_singleton()->lock) { + GDScriptLanguage::get_singleton()->lock->unlock(); + } +#endif } ///////////////////// @@ -1935,14 +2005,14 @@ Variant GDScript::call(const StringName& p_method,const Variant** p_args,int p_a GDScript *top=this; while(top) { - Map<StringName,GDFunction>::Element *E=top->member_functions.find(p_method); + Map<StringName,GDFunction*>::Element *E=top->member_functions.find(p_method); if (E) { - if (!E->get().is_static()) { + if (!E->get()->is_static()) { WARN_PRINT(String("Can't call non-static function: '"+String(p_method)+"' in script.").utf8().get_data()); } - return E->get().call(NULL,p_args,p_argcount,r_error); + return E->get()->call(NULL,p_args,p_argcount,r_error); } top=top->_base; } @@ -2127,7 +2197,7 @@ Error GDScript::load_source_code(const String& p_path) { } -const Map<StringName,GDFunction>& GDScript::debug_get_member_functions() const { +const Map<StringName,GDFunction*>& GDScript::debug_get_member_functions() const { return member_functions; } @@ -2209,6 +2279,12 @@ GDScript::GDScript() { } +GDScript::~GDScript() { + for (Map<StringName,GDFunction*>::Element *E=member_functions.front();E;E=E->next()) { + memdelete( E->get() ); + } +} + @@ -2242,14 +2318,14 @@ bool GDInstance::set(const StringName& p_name, const Variant& p_value) { while(sptr) { - Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set); + Map<StringName,GDFunction*>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set); if (E) { Variant name=p_name; const Variant *args[2]={&name,&p_value}; Variant::CallError err; - Variant ret = E->get().call(this,(const Variant**)args,2,err); + Variant ret = E->get()->call(this,(const Variant**)args,2,err); if (err.error==Variant::CallError::CALL_OK && ret.get_type()==Variant::BOOL && ret.operator bool()) return true; } @@ -2292,14 +2368,14 @@ bool GDInstance::get(const StringName& p_name, Variant &r_ret) const { } { - const Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get); + const Map<StringName,GDFunction*>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get); if (E) { Variant name=p_name; const Variant *args[1]={&name}; Variant::CallError err; - Variant ret = const_cast<GDFunction*>(&E->get())->call(const_cast<GDInstance*>(this),(const Variant**)args,1,err); + Variant ret = const_cast<GDFunction*>(E->get())->call(const_cast<GDInstance*>(this),(const Variant**)args,1,err); if (err.error==Variant::CallError::CALL_OK && ret.get_type()!=Variant::NIL) { r_ret=ret; return true; @@ -2341,12 +2417,12 @@ void GDInstance::get_property_list(List<PropertyInfo> *p_properties) const { while(sptr) { - const Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get_property_list); + const Map<StringName,GDFunction*>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get_property_list); if (E) { Variant::CallError err; - Variant ret = const_cast<GDFunction*>(&E->get())->call(const_cast<GDInstance*>(this),NULL,0,err); + Variant ret = const_cast<GDFunction*>(E->get())->call(const_cast<GDInstance*>(this),NULL,0,err); if (err.error==Variant::CallError::CALL_OK) { if (ret.get_type()!=Variant::ARRAY) { @@ -2403,7 +2479,7 @@ void GDInstance::get_property_list(List<PropertyInfo> *p_properties) const { if (sptr->member_functions.has("_get_property_list")) { Variant::CallError err; - GDFunction *f = const_cast<GDFunction*>(&sptr->member_functions["_get_property_list"]); + GDFunction *f = const_cast<GDFunction*>(sptr->member_functions["_get_property_list"]); Variant plv = f->call(const_cast<GDInstance*>(this),NULL,0,err); if (plv.get_type()!=Variant::ARRAY) { @@ -2419,11 +2495,11 @@ void GDInstance::get_property_list(List<PropertyInfo> *p_properties) const { PropertyInfo pinfo; if (!p.has("name")) { ERR_PRINT("_get_property_list: expected 'name' key of type string.") - continue; + continue; } if (!p.has("type")) { ERR_PRINT("_get_property_list: expected 'type' key of type integer.") - continue; + continue; } pinfo.name=p["name"]; pinfo.type=Variant::Type(int(p["type"])); @@ -2457,12 +2533,12 @@ void GDInstance::get_method_list(List<MethodInfo> *p_list) const { const GDScript *sptr=script.ptr(); while(sptr) { - for (Map<StringName,GDFunction>::Element *E = sptr->member_functions.front();E;E=E->next()) { + for (Map<StringName,GDFunction*>::Element *E = sptr->member_functions.front();E;E=E->next()) { MethodInfo mi; mi.name=E->key(); mi.flags|=METHOD_FLAG_FROM_SCRIPT; - for(int i=0;i<E->get().get_argument_count();i++) + for(int i=0;i<E->get()->get_argument_count();i++) mi.arguments.push_back(PropertyInfo(Variant::NIL,"arg"+itos(i))); p_list->push_back(mi); } @@ -2475,7 +2551,7 @@ bool GDInstance::has_method(const StringName& p_method) const { const GDScript *sptr=script.ptr(); while(sptr) { - const Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(p_method); + const Map<StringName,GDFunction*>::Element *E = sptr->member_functions.find(p_method); if (E) return true; sptr = sptr->_base; @@ -2489,9 +2565,9 @@ Variant GDInstance::call(const StringName& p_method,const Variant** p_args,int p GDScript *sptr=script.ptr(); while(sptr) { - Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(p_method); + Map<StringName,GDFunction*>::Element *E = sptr->member_functions.find(p_method); if (E) { - return E->get().call(this,p_args,p_argcount,r_error); + return E->get()->call(this,p_args,p_argcount,r_error); } sptr = sptr->_base; } @@ -2505,9 +2581,9 @@ void GDInstance::call_multilevel(const StringName& p_method,const Variant** p_ar Variant::CallError ce; while(sptr) { - Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(p_method); + Map<StringName,GDFunction*>::Element *E = sptr->member_functions.find(p_method); if (E) { - E->get().call(this,p_args,p_argcount,ce); + E->get()->call(this,p_args,p_argcount,ce); } sptr = sptr->_base; } @@ -2522,9 +2598,9 @@ void GDInstance::_ml_call_reversed(GDScript *sptr,const StringName& p_method,con Variant::CallError ce; - Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(p_method); + Map<StringName,GDFunction*>::Element *E = sptr->member_functions.find(p_method); if (E) { - E->get().call(this,p_args,p_argcount,ce); + E->get()->call(this,p_args,p_argcount,ce); } } @@ -2544,10 +2620,10 @@ void GDInstance::notification(int p_notification) { GDScript *sptr=script.ptr(); while(sptr) { - Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._notification); + Map<StringName,GDFunction*>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._notification); if (E) { Variant::CallError err; - E->get().call(this,args,1,err); + E->get()->call(this,args,1,err); if (err.error!=Variant::CallError::CALL_OK) { //print error about notification call @@ -2672,11 +2748,154 @@ void GDScriptLanguage::finish() { } +void GDScriptLanguage::profiling_start() { + +#ifdef DEBUG_ENABLED + if (lock) { + lock->lock(); + } + + SelfList<GDFunction> *elem=function_list.first(); + while(elem) { + elem->self()->profile.call_count=0; + elem->self()->profile.self_time=0; + elem->self()->profile.total_time=0; + elem->self()->profile.frame_call_count=0; + elem->self()->profile.frame_self_time=0; + elem->self()->profile.frame_total_time=0; + elem->self()->profile.last_frame_call_count=0; + elem->self()->profile.last_frame_self_time=0; + elem->self()->profile.last_frame_total_time=0; + elem=elem->next(); + } + + profiling=true; + if (lock) { + lock->unlock(); + } + +#endif + +} + +void GDScriptLanguage::profiling_stop() { + +#ifdef DEBUG_ENABLED + if (lock) { + lock->lock(); + } + + profiling=false; + if (lock) { + lock->unlock(); + } + +#endif +} + +int GDScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr,int p_info_max) { + + int current=0; +#ifdef DEBUG_ENABLED + if (lock) { + lock->lock(); + } + + + SelfList<GDFunction> *elem=function_list.first(); + while(elem) { + if (current>=p_info_max) + break; + p_info_arr[current].call_count=elem->self()->profile.call_count; + p_info_arr[current].self_time=elem->self()->profile.self_time; + p_info_arr[current].total_time=elem->self()->profile.total_time; + p_info_arr[current].signature=elem->self()->profile.signature; + elem=elem->next(); + current++; + } + + + + if (lock) { + lock->unlock(); + } + + +#endif + + return current; + + +} + +int GDScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr,int p_info_max) { + + int current=0; + +#ifdef DEBUG_ENABLED + if (lock) { + lock->lock(); + } + + + SelfList<GDFunction> *elem=function_list.first(); + while(elem) { + if (current>=p_info_max) + break; + if (elem->self()->profile.last_frame_call_count>0) { + p_info_arr[current].call_count=elem->self()->profile.last_frame_call_count; + p_info_arr[current].self_time=elem->self()->profile.last_frame_self_time; + p_info_arr[current].total_time=elem->self()->profile.last_frame_total_time; + p_info_arr[current].signature=elem->self()->profile.signature; + //print_line(String(elem->self()->profile.signature)+": "+itos(elem->self()->profile.last_frame_call_count)); + current++; + } + elem=elem->next(); + + } + + + if (lock) { + lock->unlock(); + } + + +#endif + + return current; + +} + void GDScriptLanguage::frame() { -// print_line("calls: "+itos(calls)); + // print_line("calls: "+itos(calls)); calls=0; + +#ifdef DEBUG_ENABLED + if (profiling) { + if (lock) { + lock->lock(); + } + + SelfList<GDFunction> *elem=function_list.first(); + while(elem) { + elem->self()->profile.last_frame_call_count=elem->self()->profile.frame_call_count; + elem->self()->profile.last_frame_self_time=elem->self()->profile.frame_self_time; + elem->self()->profile.last_frame_total_time=elem->self()->profile.frame_total_time; + elem->self()->profile.frame_call_count=0; + elem->self()->profile.frame_self_time=0; + elem->self()->profile.frame_total_time=0; + elem=elem->next(); + } + + + if (lock) { + lock->unlock(); + } + } + +#endif } /* EDITOR FUNCTIONS */ @@ -2724,7 +2943,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { "pass", "return", "while", - 0}; + 0}; const char **w=_reserved_words; @@ -2756,30 +2975,43 @@ GDScriptLanguage::GDScriptLanguage() { _debug_parse_err_line=-1; _debug_parse_err_file=""; - _debug_call_stack_pos=0; - int dmcs=GLOBAL_DEF("debug/script_max_call_stack",1024); - if (ScriptDebugger::get_singleton()) { - //debugging enabled! +#ifdef NO_THREADS + lock=NULL; +#else + lock = Mutex::create(); +#endif + profiling=false; + script_frame_time=0; + + _debug_call_stack_pos=0; + int dmcs=GLOBAL_DEF("debug/script_max_call_stack",1024); + if (ScriptDebugger::get_singleton()) { + //debugging enabled! - _debug_max_call_stack = dmcs; - if (_debug_max_call_stack<1024) - _debug_max_call_stack=1024; - _call_stack = memnew_arr( CallLevel, _debug_max_call_stack+1 ); + _debug_max_call_stack = dmcs; + if (_debug_max_call_stack<1024) + _debug_max_call_stack=1024; + _call_stack = memnew_arr( CallLevel, _debug_max_call_stack+1 ); - } else { - _debug_max_call_stack=0; - _call_stack=NULL; - } + } else { + _debug_max_call_stack=0; + _call_stack=NULL; + } } GDScriptLanguage::~GDScriptLanguage() { - if (_call_stack) { - memdelete_arr(_call_stack); - } - singleton=NULL; + + if (lock) { + memdelete(lock); + lock=NULL; + } + if (_call_stack) { + memdelete_arr(_call_stack); + } + singleton=NULL; } /*************** RESOURCE ***************/ |