1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-16 14:00:40 +00:00

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.
This commit is contained in:
George Marques
2020-11-18 10:32:28 -03:00
parent d8b22097f2
commit 52ab64db69
7 changed files with 125 additions and 0 deletions

View File

@@ -242,6 +242,18 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
function->_indexed_getters_ptr = nullptr; 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()) { if (method_bind_map.size()) {
function->methods.resize(method_bind_map.size()); function->methods.resize(method_bind_map.size());
function->_methods_ptr = function->methods.ptrw(); function->_methods_ptr = function->methods.ptrw();
@@ -647,6 +659,41 @@ void GDScriptByteCodeGenerator::write_call_builtin(const Address &p_target, GDSc
append(p_function); 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) { 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()); 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++) { for (int i = 0; i < p_arguments.size(); i++) {

View File

@@ -68,6 +68,7 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
Map<Variant::ValidatedKeyedGetter, int> keyed_getters_map; Map<Variant::ValidatedKeyedGetter, int> keyed_getters_map;
Map<Variant::ValidatedIndexedSetter, int> indexed_setters_map; Map<Variant::ValidatedIndexedSetter, int> indexed_setters_map;
Map<Variant::ValidatedIndexedGetter, int> indexed_getters_map; Map<Variant::ValidatedIndexedGetter, int> indexed_getters_map;
Map<Variant::ValidatedBuiltInMethod, int> builtin_method_map;
Map<MethodBind *, int> method_bind_map; Map<MethodBind *, int> method_bind_map;
List<int> if_jmp_addrs; // List since this can be nested. List<int> if_jmp_addrs; // List since this can be nested.
@@ -201,6 +202,15 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
return pos; 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) { int get_method_bind_pos(MethodBind *p_method) {
if (method_bind_map.has(p_method)) { if (method_bind_map.has(p_method)) {
return method_bind_map[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)); 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) { void append(MethodBind *p_method) {
opcodes.push_back(get_method_bind_pos(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_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_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(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_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_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; virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;

View File

@@ -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_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_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(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_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_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; virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;

View File

@@ -522,6 +522,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
} else { } else {
gen->write_call(result, base, call->function_name, arguments); 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 { } else {
gen->write_call(result, base, call->function_name, arguments); gen->write_call(result, base, call->function_name, arguments);
} }

View File

@@ -572,6 +572,27 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
DISASSEMBLE_PTRCALL(PACKED_VECTOR3_ARRAY); DISASSEMBLE_PTRCALL(PACKED_VECTOR3_ARRAY);
DISASSEMBLE_PTRCALL(PACKED_COLOR_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: { case OPCODE_CALL_BUILT_IN: {
text += "call-built-in "; text += "call-built-in ";

View File

@@ -190,6 +190,7 @@ public:
OPCODE_CALL_RETURN, OPCODE_CALL_RETURN,
OPCODE_CALL_ASYNC, OPCODE_CALL_ASYNC,
OPCODE_CALL_BUILT_IN, OPCODE_CALL_BUILT_IN,
OPCODE_CALL_BUILTIN_TYPE_VALIDATED,
OPCODE_CALL_SELF_BASE, OPCODE_CALL_SELF_BASE,
OPCODE_CALL_METHOD_BIND, OPCODE_CALL_METHOD_BIND,
OPCODE_CALL_METHOD_BIND_RET, OPCODE_CALL_METHOD_BIND_RET,
@@ -300,6 +301,8 @@ private:
const Variant::ValidatedIndexedSetter *_indexed_setters_ptr = nullptr; const Variant::ValidatedIndexedSetter *_indexed_setters_ptr = nullptr;
int _indexed_getters_count = 0; int _indexed_getters_count = 0;
const Variant::ValidatedIndexedGetter *_indexed_getters_ptr = nullptr; const Variant::ValidatedIndexedGetter *_indexed_getters_ptr = nullptr;
int _builtin_methods_count = 0;
const Variant::ValidatedBuiltInMethod *_builtin_methods_ptr = nullptr;
int _methods_count = 0; int _methods_count = 0;
MethodBind **_methods_ptr = nullptr; MethodBind **_methods_ptr = nullptr;
const int *_code_ptr = nullptr; const int *_code_ptr = nullptr;
@@ -326,6 +329,7 @@ private:
Vector<Variant::ValidatedKeyedGetter> keyed_getters; Vector<Variant::ValidatedKeyedGetter> keyed_getters;
Vector<Variant::ValidatedIndexedSetter> indexed_setters; Vector<Variant::ValidatedIndexedSetter> indexed_setters;
Vector<Variant::ValidatedIndexedGetter> indexed_getters; Vector<Variant::ValidatedIndexedGetter> indexed_getters;
Vector<Variant::ValidatedBuiltInMethod> builtin_methods;
Vector<MethodBind *> methods; Vector<MethodBind *> methods;
Vector<int> code; Vector<int> code;
Vector<GDScriptDataType> argument_types; Vector<GDScriptDataType> argument_types;

View File

@@ -219,6 +219,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
&&OPCODE_CALL_RETURN, \ &&OPCODE_CALL_RETURN, \
&&OPCODE_CALL_ASYNC, \ &&OPCODE_CALL_ASYNC, \
&&OPCODE_CALL_BUILT_IN, \ &&OPCODE_CALL_BUILT_IN, \
&&OPCODE_CALL_BUILTIN_TYPE_VALIDATED, \
&&OPCODE_CALL_SELF_BASE, \ &&OPCODE_CALL_SELF_BASE, \
&&OPCODE_CALL_METHOD_BIND, \ &&OPCODE_CALL_METHOD_BIND, \
&&OPCODE_CALL_METHOD_BIND_RET, \ &&OPCODE_CALL_METHOD_BIND_RET, \
@@ -1653,6 +1654,40 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
} }
DISPATCH_OPCODE; 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) { OPCODE(OPCODE_CALL_BUILT_IN) {
CHECK_SPACE(3 + instr_arg_count); CHECK_SPACE(3 + instr_arg_count);