diff options
author | George Marques <george@gmarqu.es> | 2020-11-18 10:32:28 -0300 |
---|---|---|
committer | George Marques <george@gmarqu.es> | 2020-11-21 13:24:50 -0300 |
commit | 52ab64db691e1359ae64ef0d61a8359a2c2a38be (patch) | |
tree | b0ad6993f661a2a1dc6a671289373d042c982646 /modules | |
parent | d8b22097f24685cd87a78a5a4fe37a3e8a21ed71 (diff) |
GDScript: Add faster call instructions for builtin methods
Methods from builtin types can be called by using the function pointer
when the argument and base types are known at compile time.
Diffstat (limited to 'modules')
-rw-r--r-- | modules/gdscript/gdscript_byte_codegen.cpp | 47 | ||||
-rw-r--r-- | modules/gdscript/gdscript_byte_codegen.h | 15 | ||||
-rw-r--r-- | modules/gdscript/gdscript_codegen.h | 1 | ||||
-rw-r--r-- | modules/gdscript/gdscript_compiler.cpp | 2 | ||||
-rw-r--r-- | modules/gdscript/gdscript_disassembler.cpp | 21 | ||||
-rw-r--r-- | modules/gdscript/gdscript_function.h | 4 | ||||
-rw-r--r-- | modules/gdscript/gdscript_vm.cpp | 35 |
7 files changed, 125 insertions, 0 deletions
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index 186ca1dfa2..2ee8e1a2fa 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -242,6 +242,18 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() { function->_indexed_getters_ptr = nullptr; } + if (builtin_method_map.size()) { + function->builtin_methods.resize(builtin_method_map.size()); + function->_builtin_methods_ptr = function->builtin_methods.ptrw(); + function->_builtin_methods_count = builtin_method_map.size(); + for (const Map<Variant::ValidatedBuiltInMethod, int>::Element *E = builtin_method_map.front(); E; E = E->next()) { + function->builtin_methods.write[E->get()] = E->key(); + } + } else { + function->_builtin_methods_ptr = nullptr; + function->_builtin_methods_count = 0; + } + if (method_bind_map.size()) { function->methods.resize(method_bind_map.size()); function->_methods_ptr = function->methods.ptrw(); @@ -647,6 +659,41 @@ void GDScriptByteCodeGenerator::write_call_builtin(const Address &p_target, GDSc append(p_function); } +void GDScriptByteCodeGenerator::write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) { + bool is_validated = false; + + // Check if all types are correct. + if (Variant::is_builtin_method_vararg(p_type, p_method)) { + is_validated = true; // Vararg works fine with any argument, since they can be any type. + } else if (p_arguments.size() == Variant::get_builtin_method_argument_count(p_type, p_method)) { + bool all_types_exact = true; + for (int i = 0; i < p_arguments.size(); i++) { + if (!IS_BUILTIN_TYPE(p_arguments[i], Variant::get_builtin_method_argument_type(p_type, p_method, i))) { + all_types_exact = false; + break; + } + } + + is_validated = all_types_exact; + } + + if (!is_validated) { + // Perform regular call. + write_call(p_target, p_base, p_method, p_arguments); + return; + } + + append(GDScriptFunction::OPCODE_CALL_BUILTIN_TYPE_VALIDATED, 2 + p_arguments.size()); + + for (int i = 0; i < p_arguments.size(); i++) { + append(p_arguments[i]); + } + append(p_base); + append(p_target); + append(p_arguments.size()); + append(Variant::get_validated_builtin_method(p_type, p_method)); +} + void GDScriptByteCodeGenerator::write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) { append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL_METHOD_BIND : GDScriptFunction::OPCODE_CALL_METHOD_BIND_RET, 2 + p_arguments.size()); for (int i = 0; i < p_arguments.size(); i++) { diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h index 9b43adcd73..cced0ecabe 100644 --- a/modules/gdscript/gdscript_byte_codegen.h +++ b/modules/gdscript/gdscript_byte_codegen.h @@ -68,6 +68,7 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { Map<Variant::ValidatedKeyedGetter, int> keyed_getters_map; Map<Variant::ValidatedIndexedSetter, int> indexed_setters_map; Map<Variant::ValidatedIndexedGetter, int> indexed_getters_map; + Map<Variant::ValidatedBuiltInMethod, int> builtin_method_map; Map<MethodBind *, int> method_bind_map; List<int> if_jmp_addrs; // List since this can be nested. @@ -201,6 +202,15 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { return pos; } + int get_builtin_method_pos(const Variant::ValidatedBuiltInMethod p_method) { + if (builtin_method_map.has(p_method)) { + return builtin_method_map[p_method]; + } + int pos = builtin_method_map.size(); + builtin_method_map[p_method] = pos; + return pos; + } + int get_method_bind_pos(MethodBind *p_method) { if (method_bind_map.has(p_method)) { return method_bind_map[p_method]; @@ -298,6 +308,10 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { opcodes.push_back(get_indexed_getter_pos(p_indexed_getter)); } + void append(const Variant::ValidatedBuiltInMethod p_method) { + opcodes.push_back(get_builtin_method_pos(p_method)); + } + void append(MethodBind *p_method) { opcodes.push_back(get_method_bind_pos(p_method)); } @@ -357,6 +371,7 @@ public: virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override; virtual void write_call_async(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override; virtual void write_call_builtin(const Address &p_target, GDScriptFunctions::Function p_function, const Vector<Address> &p_arguments) override; + virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override; virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override; virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override; virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override; diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h index ff9bdb5f9e..2616a34719 100644 --- a/modules/gdscript/gdscript_codegen.h +++ b/modules/gdscript/gdscript_codegen.h @@ -126,6 +126,7 @@ public: virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0; virtual void write_call_async(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0; virtual void write_call_builtin(const Address &p_target, GDScriptFunctions::Function p_function, const Vector<Address> &p_arguments) = 0; + virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0; virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0; virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0; virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 8383e47dec..69fe6d27cc 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -522,6 +522,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code } else { gen->write_call(result, base, call->function_name, arguments); } + } else if (base.type.has_type && base.type.kind == GDScriptDataType::BUILTIN) { + gen->write_call_builtin_type(result, base, base.type.builtin_type, call->function_name, arguments); } else { gen->write_call(result, base, call->function_name, arguments); } diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp index bb76a14cfe..b6f9a6f647 100644 --- a/modules/gdscript/gdscript_disassembler.cpp +++ b/modules/gdscript/gdscript_disassembler.cpp @@ -572,6 +572,27 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { DISASSEMBLE_PTRCALL(PACKED_VECTOR3_ARRAY); DISASSEMBLE_PTRCALL(PACKED_COLOR_ARRAY); + case OPCODE_CALL_BUILTIN_TYPE_VALIDATED: { + int argc = _code_ptr[ip + 1 + instr_var_args]; + + text += "call-builtin-method validated "; + + text += DADDR(2 + argc) + " = "; + + text += DADDR(1) + "."; + text += "<unknown method>"; + + text += "("; + + for (int i = 0; i < argc; i++) { + if (i > 0) + text += ", "; + text += DADDR(1 + i); + } + text += ")"; + + incr = 5 + argc; + } break; case OPCODE_CALL_BUILT_IN: { text += "call-built-in "; diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index 1bc5ab6f64..794da38f8c 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -190,6 +190,7 @@ public: OPCODE_CALL_RETURN, OPCODE_CALL_ASYNC, OPCODE_CALL_BUILT_IN, + OPCODE_CALL_BUILTIN_TYPE_VALIDATED, OPCODE_CALL_SELF_BASE, OPCODE_CALL_METHOD_BIND, OPCODE_CALL_METHOD_BIND_RET, @@ -300,6 +301,8 @@ private: const Variant::ValidatedIndexedSetter *_indexed_setters_ptr = nullptr; int _indexed_getters_count = 0; const Variant::ValidatedIndexedGetter *_indexed_getters_ptr = nullptr; + int _builtin_methods_count = 0; + const Variant::ValidatedBuiltInMethod *_builtin_methods_ptr = nullptr; int _methods_count = 0; MethodBind **_methods_ptr = nullptr; const int *_code_ptr = nullptr; @@ -326,6 +329,7 @@ private: Vector<Variant::ValidatedKeyedGetter> keyed_getters; Vector<Variant::ValidatedIndexedSetter> indexed_setters; Vector<Variant::ValidatedIndexedGetter> indexed_getters; + Vector<Variant::ValidatedBuiltInMethod> builtin_methods; Vector<MethodBind *> methods; Vector<int> code; Vector<GDScriptDataType> argument_types; diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index 4772163b29..3a7d422f1d 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -219,6 +219,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const &&OPCODE_CALL_RETURN, \ &&OPCODE_CALL_ASYNC, \ &&OPCODE_CALL_BUILT_IN, \ + &&OPCODE_CALL_BUILTIN_TYPE_VALIDATED, \ &&OPCODE_CALL_SELF_BASE, \ &&OPCODE_CALL_METHOD_BIND, \ &&OPCODE_CALL_METHOD_BIND_RET, \ @@ -1653,6 +1654,40 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } DISPATCH_OPCODE; + OPCODE(OPCODE_CALL_BUILTIN_TYPE_VALIDATED) { + CHECK_SPACE(3 + instr_arg_count); + + ip += instr_arg_count; + + int argc = _code_ptr[ip + 1]; + GD_ERR_BREAK(argc < 0); + + GET_INSTRUCTION_ARG(base, argc); + + GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _builtin_methods_count); + Variant::ValidatedBuiltInMethod method = _builtin_methods_ptr[_code_ptr[ip + 2]]; + Variant **argptrs = instruction_args; + +#ifdef DEBUG_ENABLED + uint64_t call_time = 0; + if (GDScriptLanguage::get_singleton()->profiling) { + call_time = OS::get_singleton()->get_ticks_usec(); + } +#endif + + GET_INSTRUCTION_ARG(ret, argc + 1); + method(base, (const Variant **)argptrs, argc, ret); + +#ifdef DEBUG_ENABLED + if (GDScriptLanguage::get_singleton()->profiling) { + function_call_time += OS::get_singleton()->get_ticks_usec() - call_time; + } +#endif + + ip += 3; + } + DISPATCH_OPCODE; + OPCODE(OPCODE_CALL_BUILT_IN) { CHECK_SPACE(3 + instr_arg_count); |