From 60790c8c5aca9435d1b54ffd8a51a9137c9ad617 Mon Sep 17 00:00:00 2001 From: Hein-Pieter van Braam Date: Tue, 19 Sep 2017 00:06:27 +0200 Subject: Remove more GDScript runtime checks on release As a preparation for other performance enhancements to GDScript:call() start by removing more of the GDScript runtime checks on release. This code has been tested with 2d/platformer, 3d/platformer, 3d/materials_test, and goltorus. No regressions were found. --- modules/gdscript/gd_function.cpp | 87 +++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 33 deletions(-) diff --git a/modules/gdscript/gd_function.cpp b/modules/gdscript/gd_function.cpp index ddee7b2521..438d484a41 100644 --- a/modules/gdscript/gd_function.cpp +++ b/modules/gdscript/gd_function.cpp @@ -271,6 +271,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a if (ScriptDebugger::get_singleton()) GDScriptLanguage::get_singleton()->enter_function(p_instance, this, stack, &ip, &line); +#define GD_ERR_BREAK(m_cond) ERR_BREAK(m_cond) + #define CHECK_SPACE(m_space) \ ERR_BREAK((ip + m_space) > _code_size) @@ -281,6 +283,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a break; #else +#define GD_ERR_BREAK(m_cond) #define CHECK_SPACE(m_space) #define GET_VARIANT_PTR(m_v, m_code_ofs) \ Variant *m_v; \ @@ -302,9 +305,13 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a #endif bool exit_ok = false; +#ifdef DEBUG_ENABLED while (ip < _code_size) { - int last_opcode = _code_ptr[ip]; +#else + while (true) { +#endif + switch (_code_ptr[ip]) { case OPCODE_OPERATOR: { @@ -313,21 +320,21 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a bool valid; Variant::Operator op = (Variant::Operator)_code_ptr[ip + 1]; - ERR_BREAK(op >= Variant::OP_MAX); + GD_ERR_BREAK(op >= Variant::OP_MAX); GET_VARIANT_PTR(a, 2); GET_VARIANT_PTR(b, 3); GET_VARIANT_PTR(dst, 4); #ifdef DEBUG_ENABLED + Variant ret; Variant::evaluate(op, *a, *b, ret, valid); #else Variant::evaluate(op, *a, *b, *dst, valid); #endif - - if (!valid) { #ifdef DEBUG_ENABLED + if (!valid) { if (ret.get_type() == Variant::STRING) { //return a string when invalid with the error @@ -336,13 +343,10 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a } else { err_text = "Invalid operands '" + Variant::get_type_name(a->get_type()) + "' and '" + Variant::get_type_name(b->get_type()) + "' in operator '" + Variant::get_operator_name(op) + "'."; } -#endif break; } -#ifdef DEBUG_ENABLED *dst = ret; #endif - ip += 5; continue; } @@ -355,7 +359,6 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a GET_VARIANT_PTR(dst, 3); #ifdef DEBUG_ENABLED - if (a->get_type() != Variant::OBJECT || a->operator Object *() == NULL) { err_text = "Left operand of 'is' is not an instance of anything."; @@ -367,7 +370,6 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a break; } #endif - Object *obj_A = *a; Object *obj_B = *b; @@ -399,12 +401,13 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a GDNativeClass *nc = Object::cast_to(obj_B); +#ifdef DEBUG_ENABLED if (!nc) { err_text = "Right operand of 'is' is not a class (type: '" + obj_B->get_class() + "')."; break; } - +#endif extends_ok = ClassDB::is_parent_class(obj_A->get_class_name(), nc->get_name()); } @@ -423,6 +426,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a bool valid; dst->set(*index, *value, &valid); +#ifdef DEBUG_ENABLED if (!valid) { String v = index->operator String(); if (v != "") { @@ -433,7 +437,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a err_text = "Invalid set index " + v + " (on base: '" + _get_var_type(dst) + "')."; break; } - +#endif ip += 4; continue; } @@ -453,6 +457,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a *dst = src->get(*index, &valid); #endif +#ifdef DEBUG_ENABLED if (!valid) { String v = index->operator String(); if (v != "") { @@ -463,7 +468,6 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a err_text = "Invalid get index " + v + " (on base: '" + _get_var_type(src) + "')."; break; } -#ifdef DEBUG_ENABLED *dst = ret; #endif ip += 4; @@ -478,18 +482,19 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a int indexname = _code_ptr[ip + 2]; - ERR_BREAK(indexname < 0 || indexname >= _global_names_count); + GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count); const StringName *index = &_global_names_ptr[indexname]; bool valid; dst->set_named(*index, *value, &valid); +#ifdef DEBUG_ENABLED if (!valid) { String err_type; err_text = "Invalid set index '" + String(*index) + "' (on base: '" + _get_var_type(dst) + "')."; break; } - +#endif ip += 4; continue; } @@ -502,7 +507,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a int indexname = _code_ptr[ip + 2]; - ERR_BREAK(indexname < 0 || indexname >= _global_names_count); + GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count); const StringName *index = &_global_names_ptr[indexname]; bool valid; @@ -513,7 +518,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a #else *dst = src->get_named(*index, &valid); #endif - +#ifdef DEBUG_ENABLED if (!valid) { if (src->has_method(*index)) { err_text = "Invalid get index '" + index->operator String() + "' (on base: '" + _get_var_type(src) + "'). Did you mean '." + index->operator String() + "()' ?"; @@ -522,7 +527,6 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a } break; } -#ifdef DEBUG_ENABLED *dst = ret; #endif ip += 4; @@ -532,7 +536,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a CHECK_SPACE(3); int indexname = _code_ptr[ip + 1]; - ERR_BREAK(indexname < 0 || indexname >= _global_names_count); + GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count); const StringName *index = &_global_names_ptr[indexname]; GET_VARIANT_PTR(src, 2); @@ -554,7 +558,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a CHECK_SPACE(3); int indexname = _code_ptr[ip + 1]; - ERR_BREAK(indexname < 0 || indexname >= _global_names_count); + GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count); const StringName *index = &_global_names_ptr[indexname]; GET_VARIANT_PTR(dst, 2); bool ok = ClassDB::get_property(p_instance->owner, *index, *dst); @@ -615,11 +619,13 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a Variant::CallError err; *dst = Variant::construct(t, (const Variant **)argptrs, argc, err); +#ifdef DEBUG_ENABLED if (err.error != Variant::CallError::CALL_OK) { err_text = _get_call_error(err, "'" + Variant::get_type_name(t) + "' constructor", (const Variant **)argptrs); break; } +#endif ip += 4 + argc; //construct a basic type @@ -677,10 +683,10 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a GET_VARIANT_PTR(base, 2); int nameg = _code_ptr[ip + 3]; - ERR_BREAK(nameg < 0 || nameg >= _global_names_count); + GD_ERR_BREAK(nameg < 0 || nameg >= _global_names_count); const StringName *methodname = &_global_names_ptr[nameg]; - ERR_BREAK(argc < 0); + GD_ERR_BREAK(argc < 0); ip += 4; CHECK_SPACE(argc + 1); Variant **argptrs = call_args; @@ -711,7 +717,6 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a if (GDScriptLanguage::get_singleton()->profiling) { function_call_time += OS::get_singleton()->get_ticks_usec() - call_time; } -#endif if (err.error != Variant::CallError::CALL_OK) { @@ -742,6 +747,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a err_text = _get_call_error(err, "function '" + methodstr + "' in base '" + basestr + "'", (const Variant **)argptrs); break; } +#endif //_call_func(NULL,base,*methodname,ip,argc,p_instance,stack); ip += argc + 1; @@ -753,7 +759,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a GDFunctions::Function func = GDFunctions::Function(_code_ptr[ip + 1]); int argc = _code_ptr[ip + 2]; - ERR_BREAK(argc < 0); + GD_ERR_BREAK(argc < 0); ip += 3; CHECK_SPACE(argc + 1); @@ -770,6 +776,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a GDFunctions::call(func, (const Variant **)argptrs, argc, *dst, err); +#ifdef DEBUG_ENABLED if (err.error != Variant::CallError::CALL_OK) { String methodstr = GDFunctions::get_func_name(func); @@ -781,6 +788,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a } break; } +#endif ip += argc + 1; continue; } @@ -792,8 +800,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a CHECK_SPACE(2); int self_fun = _code_ptr[ip + 1]; -#ifdef DEBUG_ENABLED +#ifdef DEBUG_ENABLED if (self_fun < 0 || self_fun >= _global_names_count) { err_text = "compiler bug, function name not found"; @@ -898,10 +906,11 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a retvalue = gdfs; if (_code_ptr[ip] == OPCODE_YIELD_SIGNAL) { + //do the oneshot connect GET_VARIANT_PTR(argobj, 1); GET_VARIANT_PTR(argname, 2); - //do the oneshot connect +#ifdef DEBUG_ENABLED if (argobj->get_type() != Variant::OBJECT) { err_text = "First argument of yield() not of type object."; break; @@ -910,6 +919,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a err_text = "Second argument of yield() not a string (for signal name)."; break; } +#endif Object *obj = argobj->operator Object *(); String signal = argname->operator String(); #ifdef DEBUG_ENABLED @@ -932,10 +942,12 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a #endif Error err = obj->connect(signal, gdfs.ptr(), "_signal_callback", varray(gdfs), Object::CONNECT_ONESHOT); +#ifdef DEBUG_ENABLED if (err != OK) { err_text = "Error connecting to signal: " + signal + " during yield()."; break; } +#endif } exit_ok = true; @@ -944,10 +956,12 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a case OPCODE_YIELD_RESUME: { CHECK_SPACE(2); +#ifdef DEBUG_ENABLED if (!p_state) { err_text = ("Invalid Resume (bug?)"); break; } +#endif GET_VARIANT_PTR(result, 1); *result = p_state->result; ip += 2; @@ -958,7 +972,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a CHECK_SPACE(2); int to = _code_ptr[ip + 1]; - ERR_BREAK(to < 0 || to > _code_size); + GD_ERR_BREAK(to < 0 || to > _code_size); ip = to; continue; } @@ -979,7 +993,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a #endif if (result) { int to = _code_ptr[ip + 2]; - ERR_BREAK(to < 0 || to > _code_size); + GD_ERR_BREAK(to < 0 || to > _code_size); ip = to; continue; } @@ -1003,7 +1017,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a #endif if (!result) { int to = _code_ptr[ip + 2]; - ERR_BREAK(to < 0 || to > _code_size); + GD_ERR_BREAK(to < 0 || to > _code_size); ip = to; continue; } @@ -1033,23 +1047,26 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a bool valid; if (!container->iter_init(*counter, valid)) { +#ifdef DEBUG_ENABLED if (!valid) { err_text = "Unable to iterate on object of type " + Variant::get_type_name(container->get_type()) + "'."; break; } +#endif int jumpto = _code_ptr[ip + 3]; - ERR_BREAK(jumpto < 0 || jumpto > _code_size); + GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size); ip = jumpto; continue; } GET_VARIANT_PTR(iterator, 4); *iterator = container->iter_get(*counter, valid); +#ifdef DEBUG_ENABLED if (!valid) { err_text = "Unable to obtain iterator object of type " + Variant::get_type_name(container->get_type()) + "'."; break; } - +#endif ip += 5; //skip regular iterate which is always next continue; } @@ -1062,23 +1079,26 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a bool valid; if (!container->iter_next(*counter, valid)) { +#ifdef DEBUG_ENABLED if (!valid) { err_text = "Unable to iterate on object of type " + Variant::get_type_name(container->get_type()) + "' (type changed since first iteration?)."; break; } +#endif int jumpto = _code_ptr[ip + 3]; - ERR_BREAK(jumpto < 0 || jumpto > _code_size); + GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size); ip = jumpto; continue; } GET_VARIANT_PTR(iterator, 4); *iterator = container->iter_get(*counter, valid); +#ifdef DEBUG_ENABLED if (!valid) { err_text = "Unable to obtain iterator object of type " + Variant::get_type_name(container->get_type()) + "' (but was obtained on first iteration?)."; break; } - +#endif ip += 5; //loop again continue; } @@ -1103,7 +1123,6 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a } #endif - ip += 2; continue; } @@ -1157,6 +1176,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a } } +#ifdef DEBUG_ENABLED if (exit_ok) break; //error @@ -1182,6 +1202,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a _err_print_error(err_func.utf8().get_data(), err_file.utf8().get_data(), err_line, err_text.utf8().get_data(), ERR_HANDLER_SCRIPT); } +#endif break; } -- cgit v1.2.3 From d05965963d402b54b7e7c662802ecea69ad50745 Mon Sep 17 00:00:00 2001 From: Hein-Pieter van Braam Date: Tue, 19 Sep 2017 01:46:48 +0200 Subject: Don't call Variant::reference() unnecessarily operator= does not need to call reference() if the new value is of the same type as the old. This saves us zeroing the Variant, This speeds up reuse of a Variant in a loop by roughly 50%. --- core/variant.cpp | 161 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 131 insertions(+), 30 deletions(-) diff --git a/core/variant.cpp b/core/variant.cpp index 10d86152ee..52bdd4e22d 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -903,9 +903,6 @@ bool Variant::is_one() const { void Variant::reference(const Variant &p_variant) { - if (this == &p_variant) - return; - clear(); type = p_variant.type; @@ -924,17 +921,14 @@ void Variant::reference(const Variant &p_variant) { case INT: { _data._int = p_variant._data._int; - } break; case REAL: { _data._real = p_variant._data._real; - } break; case STRING: { memnew_placement(_data._mem, String(*reinterpret_cast(p_variant._data._mem))); - } break; // math types @@ -942,33 +936,24 @@ void Variant::reference(const Variant &p_variant) { case VECTOR2: { memnew_placement(_data._mem, Vector2(*reinterpret_cast(p_variant._data._mem))); - } break; case RECT2: { memnew_placement(_data._mem, Rect2(*reinterpret_cast(p_variant._data._mem))); - } break; case TRANSFORM2D: { _data._transform2d = memnew(Transform2D(*p_variant._data._transform2d)); - } break; case VECTOR3: { memnew_placement(_data._mem, Vector3(*reinterpret_cast(p_variant._data._mem))); - } break; case PLANE: { memnew_placement(_data._mem, Plane(*reinterpret_cast(p_variant._data._mem))); - } break; - /* - case QUAT: { - - } break;*/ case RECT3: { _data._rect3 = memnew(Rect3(*p_variant._data._rect3)); @@ -986,7 +971,6 @@ void Variant::reference(const Variant &p_variant) { case TRANSFORM: { _data._transform = memnew(Transform(*p_variant._data._transform)); - } break; // misc types @@ -1058,6 +1042,7 @@ void Variant::reference(const Variant &p_variant) { default: {} } } + void Variant::zero() { switch (type) { case NIL: break; @@ -1073,6 +1058,7 @@ void Variant::zero() { default: this->clear(); break; } } + void Variant::clear() { switch (type) { @@ -1092,12 +1078,10 @@ void Variant::clear() { case TRANSFORM2D: { memdelete(_data._transform2d); - } break; case RECT3: { memdelete(_data._rect3); - } break; case BASIS: { @@ -1106,14 +1090,12 @@ void Variant::clear() { case TRANSFORM: { memdelete(_data._transform); - } break; // misc types case NODE_PATH: { reinterpret_cast(_data._mem)->~NodePath(); - } break; case OBJECT: { @@ -1127,48 +1109,39 @@ void Variant::clear() { case DICTIONARY: { reinterpret_cast(_data._mem)->~Dictionary(); - } break; case ARRAY: { reinterpret_cast(_data._mem)->~Array(); - } break; // arrays case POOL_BYTE_ARRAY: { reinterpret_cast *>(_data._mem)->~PoolVector(); - } break; case POOL_INT_ARRAY: { reinterpret_cast *>(_data._mem)->~PoolVector(); - } break; case POOL_REAL_ARRAY: { reinterpret_cast *>(_data._mem)->~PoolVector(); - } break; case POOL_STRING_ARRAY: { reinterpret_cast *>(_data._mem)->~PoolVector(); - } break; case POOL_VECTOR2_ARRAY: { reinterpret_cast *>(_data._mem)->~PoolVector(); - } break; case POOL_VECTOR3_ARRAY: { reinterpret_cast *>(_data._mem)->~PoolVector(); - } break; case POOL_COLOR_ARRAY: { reinterpret_cast *>(_data._mem)->~PoolVector(); - } break; default: {} /* not needed */ } @@ -2496,7 +2469,135 @@ Variant::Variant(const Vector &p_array) { void Variant::operator=(const Variant &p_variant) { - reference(p_variant); + if (this == &p_variant) + return; + + if (type != p_variant.type) { + reference(p_variant); + return; + } + + switch (p_variant.type) { + case NIL: { + + // none + } break; + + // atomic types + case BOOL: { + + _data._bool = p_variant._data._bool; + } break; + case INT: { + + _data._int = p_variant._data._int; + } break; + case REAL: { + + _data._real = p_variant._data._real; + } break; + case STRING: { + + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + + // math types + + case VECTOR2: { + + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case RECT2: { + + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case TRANSFORM2D: { + + *_data._transform2d = *(p_variant._data._transform2d); + } break; + case VECTOR3: { + + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case PLANE: { + + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + + case RECT3: { + + *_data._rect3 = *(p_variant._data._rect3); + } break; + case QUAT: { + + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case BASIS: { + + *_data._basis = *(p_variant._data._basis); + } break; + case TRANSFORM: { + + *_data._transform = *(p_variant._data._transform); + } break; + + // misc types + case COLOR: { + + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case _RID: { + + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case OBJECT: { + + *reinterpret_cast(_data._mem) = p_variant._get_obj(); + } break; + case NODE_PATH: { + + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case DICTIONARY: { + + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case ARRAY: { + + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + + // arrays + case POOL_BYTE_ARRAY: { + + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_INT_ARRAY: { + + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_REAL_ARRAY: { + + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_STRING_ARRAY: { + + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_VECTOR2_ARRAY: { + + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_VECTOR3_ARRAY: { + + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_COLOR_ARRAY: { + + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + default: {} + } } Variant::Variant(const IP_Address &p_address) { -- cgit v1.2.3