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:
parent
d8b22097f2
commit
52ab64db69
|
@ -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++) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 ";
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue