You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-10 13:00:37 +00:00
GDScript: Add faster operator for known types
It now uses the direct operator function pointer, which increases performance in evaluation.
This commit is contained in:
@@ -158,6 +158,18 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
|
|||||||
function->_default_arg_ptr = nullptr;
|
function->_default_arg_ptr = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (operator_func_map.size()) {
|
||||||
|
function->operator_funcs.resize(operator_func_map.size());
|
||||||
|
function->_operator_funcs_count = function->operator_funcs.size();
|
||||||
|
function->_operator_funcs_ptr = function->operator_funcs.ptr();
|
||||||
|
for (const Map<Variant::ValidatedOperatorEvaluator, int>::Element *E = operator_func_map.front(); E; E = E->next()) {
|
||||||
|
function->operator_funcs.write[E->get()] = E->key();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
function->_operator_funcs_count = 0;
|
||||||
|
function->_operator_funcs_ptr = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (debug_stack) {
|
if (debug_stack) {
|
||||||
function->stack_debug = stack_debug;
|
function->stack_debug = stack_debug;
|
||||||
}
|
}
|
||||||
@@ -178,7 +190,23 @@ void GDScriptByteCodeGenerator::set_initial_line(int p_line) {
|
|||||||
function->_initial_line = p_line;
|
function->_initial_line = p_line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define HAS_BUILTIN_TYPE(m_var) \
|
||||||
|
(m_var.type.has_type && m_var.type.kind == GDScriptDataType::BUILTIN)
|
||||||
|
|
||||||
void GDScriptByteCodeGenerator::write_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) {
|
void GDScriptByteCodeGenerator::write_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) {
|
||||||
|
if (HAS_BUILTIN_TYPE(p_left_operand) && HAS_BUILTIN_TYPE(p_right_operand)) {
|
||||||
|
// Gather specific operator.
|
||||||
|
Variant::ValidatedOperatorEvaluator op_func = Variant::get_validated_operator_evaluator(p_operator, p_left_operand.type.builtin_type, p_right_operand.type.builtin_type);
|
||||||
|
|
||||||
|
append(GDScriptFunction::OPCODE_OPERATOR_VALIDATED, 3);
|
||||||
|
append(p_left_operand);
|
||||||
|
append(p_right_operand);
|
||||||
|
append(p_target);
|
||||||
|
append(op_func);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No specific types, perform variant evaluation.
|
||||||
append(GDScriptFunction::OPCODE_OPERATOR, 3);
|
append(GDScriptFunction::OPCODE_OPERATOR, 3);
|
||||||
append(p_left_operand);
|
append(p_left_operand);
|
||||||
append(p_right_operand);
|
append(p_right_operand);
|
||||||
|
|||||||
@@ -51,15 +51,16 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
|
|||||||
|
|
||||||
int current_stack_size = 0;
|
int current_stack_size = 0;
|
||||||
int current_temporaries = 0;
|
int current_temporaries = 0;
|
||||||
|
int current_line = 0;
|
||||||
|
int stack_max = 0;
|
||||||
|
int instr_args_max = 0;
|
||||||
|
|
||||||
HashMap<Variant, int, VariantHasher, VariantComparator> constant_map;
|
HashMap<Variant, int, VariantHasher, VariantComparator> constant_map;
|
||||||
Map<StringName, int> name_map;
|
Map<StringName, int> name_map;
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
Vector<StringName> named_globals;
|
Vector<StringName> named_globals;
|
||||||
#endif
|
#endif
|
||||||
int current_line = 0;
|
Map<Variant::ValidatedOperatorEvaluator, int> operator_func_map;
|
||||||
int stack_max = 0;
|
|
||||||
int instr_args_max = 0;
|
|
||||||
|
|
||||||
List<int> if_jmp_addrs; // List since this can be nested.
|
List<int> if_jmp_addrs; // List since this can be nested.
|
||||||
List<int> for_jmp_addrs;
|
List<int> for_jmp_addrs;
|
||||||
@@ -136,6 +137,14 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
|
|||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int get_operation_pos(const Variant::ValidatedOperatorEvaluator p_operation) {
|
||||||
|
if (operator_func_map.has(p_operation))
|
||||||
|
return operator_func_map[p_operation];
|
||||||
|
int pos = operator_func_map.size();
|
||||||
|
operator_func_map[p_operation] = pos;
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
void alloc_stack(int p_level) {
|
void alloc_stack(int p_level) {
|
||||||
if (p_level >= stack_max)
|
if (p_level >= stack_max)
|
||||||
stack_max = p_level + 1;
|
stack_max = p_level + 1;
|
||||||
@@ -191,6 +200,10 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
|
|||||||
opcodes.push_back(get_name_map_pos(p_name));
|
opcodes.push_back(get_name_map_pos(p_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void append(const Variant::ValidatedOperatorEvaluator p_operation) {
|
||||||
|
opcodes.push_back(get_operation_pos(p_operation));
|
||||||
|
}
|
||||||
|
|
||||||
void patch_jump(int p_address) {
|
void patch_jump(int p_address) {
|
||||||
opcodes.write[p_address] = opcodes.size();
|
opcodes.write[p_address] = opcodes.size();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,6 +136,17 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
|
|||||||
|
|
||||||
incr += 5;
|
incr += 5;
|
||||||
} break;
|
} break;
|
||||||
|
case OPCODE_OPERATOR_VALIDATED: {
|
||||||
|
text += "validated operator ";
|
||||||
|
|
||||||
|
text += DADDR(3);
|
||||||
|
text += " = ";
|
||||||
|
text += DADDR(1);
|
||||||
|
text += " <operator function> ";
|
||||||
|
text += DADDR(2);
|
||||||
|
|
||||||
|
incr += 5;
|
||||||
|
} break;
|
||||||
case OPCODE_EXTENDS_TEST: {
|
case OPCODE_EXTENDS_TEST: {
|
||||||
text += "is object ";
|
text += "is object ";
|
||||||
text += DADDR(3);
|
text += DADDR(3);
|
||||||
|
|||||||
@@ -159,6 +159,7 @@ class GDScriptFunction {
|
|||||||
public:
|
public:
|
||||||
enum Opcode {
|
enum Opcode {
|
||||||
OPCODE_OPERATOR,
|
OPCODE_OPERATOR,
|
||||||
|
OPCODE_OPERATOR_VALIDATED,
|
||||||
OPCODE_EXTENDS_TEST,
|
OPCODE_EXTENDS_TEST,
|
||||||
OPCODE_IS_BUILTIN,
|
OPCODE_IS_BUILTIN,
|
||||||
OPCODE_SET,
|
OPCODE_SET,
|
||||||
@@ -241,6 +242,8 @@ private:
|
|||||||
int _global_names_count = 0;
|
int _global_names_count = 0;
|
||||||
const int *_default_arg_ptr = nullptr;
|
const int *_default_arg_ptr = nullptr;
|
||||||
int _default_arg_count = 0;
|
int _default_arg_count = 0;
|
||||||
|
int _operator_funcs_count = 0;
|
||||||
|
const Variant::ValidatedOperatorEvaluator *_operator_funcs_ptr = nullptr;
|
||||||
const int *_code_ptr = nullptr;
|
const int *_code_ptr = nullptr;
|
||||||
int _code_size = 0;
|
int _code_size = 0;
|
||||||
int _argument_count = 0;
|
int _argument_count = 0;
|
||||||
@@ -256,6 +259,7 @@ private:
|
|||||||
Vector<Variant> constants;
|
Vector<Variant> constants;
|
||||||
Vector<StringName> global_names;
|
Vector<StringName> global_names;
|
||||||
Vector<int> default_arguments;
|
Vector<int> default_arguments;
|
||||||
|
Vector<Variant::ValidatedOperatorEvaluator> operator_funcs;
|
||||||
Vector<int> code;
|
Vector<int> code;
|
||||||
Vector<GDScriptDataType> argument_types;
|
Vector<GDScriptDataType> argument_types;
|
||||||
GDScriptDataType return_type;
|
GDScriptDataType return_type;
|
||||||
|
|||||||
@@ -188,6 +188,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
|
|||||||
#define OPCODES_TABLE \
|
#define OPCODES_TABLE \
|
||||||
static const void *switch_table_ops[] = { \
|
static const void *switch_table_ops[] = { \
|
||||||
&&OPCODE_OPERATOR, \
|
&&OPCODE_OPERATOR, \
|
||||||
|
&&OPCODE_OPERATOR_VALIDATED, \
|
||||||
&&OPCODE_EXTENDS_TEST, \
|
&&OPCODE_EXTENDS_TEST, \
|
||||||
&&OPCODE_IS_BUILTIN, \
|
&&OPCODE_IS_BUILTIN, \
|
||||||
&&OPCODE_SET, \
|
&&OPCODE_SET, \
|
||||||
@@ -468,6 +469,23 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||||||
}
|
}
|
||||||
DISPATCH_OPCODE;
|
DISPATCH_OPCODE;
|
||||||
|
|
||||||
|
OPCODE(OPCODE_OPERATOR_VALIDATED) {
|
||||||
|
CHECK_SPACE(5);
|
||||||
|
|
||||||
|
int operator_idx = _code_ptr[ip + 4];
|
||||||
|
GD_ERR_BREAK(operator_idx < 0 || operator_idx >= _operator_funcs_count);
|
||||||
|
Variant::ValidatedOperatorEvaluator operator_func = _operator_funcs_ptr[operator_idx];
|
||||||
|
|
||||||
|
GET_INSTRUCTION_ARG(a, 0);
|
||||||
|
GET_INSTRUCTION_ARG(b, 1);
|
||||||
|
GET_INSTRUCTION_ARG(dst, 2);
|
||||||
|
|
||||||
|
operator_func(a, b, dst);
|
||||||
|
|
||||||
|
ip += 5;
|
||||||
|
}
|
||||||
|
DISPATCH_OPCODE;
|
||||||
|
|
||||||
OPCODE(OPCODE_EXTENDS_TEST) {
|
OPCODE(OPCODE_EXTENDS_TEST) {
|
||||||
CHECK_SPACE(4);
|
CHECK_SPACE(4);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user