summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Marques <george@gmarqu.es>2020-11-13 16:47:45 -0300
committerGeorge Marques <george@gmarqu.es>2020-11-21 13:24:49 -0300
commit1ad5c926dc4d7a182b8621f360b7ce4697dffb25 (patch)
treede5daab39985b6203a8aed50089970276a883368
parentc707d6fe717c43fecafa0aca53182f214268ec16 (diff)
GDScript: Add faster operator for known types
It now uses the direct operator function pointer, which increases performance in evaluation.
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp28
-rw-r--r--modules/gdscript/gdscript_byte_codegen.h19
-rw-r--r--modules/gdscript/gdscript_disassembler.cpp11
-rw-r--r--modules/gdscript/gdscript_function.h4
-rw-r--r--modules/gdscript/gdscript_vm.cpp18
5 files changed, 77 insertions, 3 deletions
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index 33e3909e90..cc8790c004 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -158,6 +158,18 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
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) {
function->stack_debug = stack_debug;
}
@@ -178,7 +190,23 @@ void GDScriptByteCodeGenerator::set_initial_line(int 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) {
+ 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(p_left_operand);
append(p_right_operand);
diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h
index e8d7de21c2..cce17793f4 100644
--- a/modules/gdscript/gdscript_byte_codegen.h
+++ b/modules/gdscript/gdscript_byte_codegen.h
@@ -51,15 +51,16 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
int current_stack_size = 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;
Map<StringName, int> name_map;
#ifdef TOOLS_ENABLED
Vector<StringName> named_globals;
#endif
- int current_line = 0;
- int stack_max = 0;
- int instr_args_max = 0;
+ Map<Variant::ValidatedOperatorEvaluator, int> operator_func_map;
List<int> if_jmp_addrs; // List since this can be nested.
List<int> for_jmp_addrs;
@@ -136,6 +137,14 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
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) {
if (p_level >= stack_max)
stack_max = p_level + 1;
@@ -191,6 +200,10 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
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) {
opcodes.write[p_address] = opcodes.size();
}
diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp
index d5de126d2e..2540940332 100644
--- a/modules/gdscript/gdscript_disassembler.cpp
+++ b/modules/gdscript/gdscript_disassembler.cpp
@@ -136,6 +136,17 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr += 5;
} 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: {
text += "is object ";
text += DADDR(3);
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index ca9dda9b80..94cd30955c 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -159,6 +159,7 @@ class GDScriptFunction {
public:
enum Opcode {
OPCODE_OPERATOR,
+ OPCODE_OPERATOR_VALIDATED,
OPCODE_EXTENDS_TEST,
OPCODE_IS_BUILTIN,
OPCODE_SET,
@@ -241,6 +242,8 @@ private:
int _global_names_count = 0;
const int *_default_arg_ptr = nullptr;
int _default_arg_count = 0;
+ int _operator_funcs_count = 0;
+ const Variant::ValidatedOperatorEvaluator *_operator_funcs_ptr = nullptr;
const int *_code_ptr = nullptr;
int _code_size = 0;
int _argument_count = 0;
@@ -256,6 +259,7 @@ private:
Vector<Variant> constants;
Vector<StringName> global_names;
Vector<int> default_arguments;
+ Vector<Variant::ValidatedOperatorEvaluator> operator_funcs;
Vector<int> code;
Vector<GDScriptDataType> argument_types;
GDScriptDataType return_type;
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index a10f2a9274..ab923ec37c 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -188,6 +188,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
#define OPCODES_TABLE \
static const void *switch_table_ops[] = { \
&&OPCODE_OPERATOR, \
+ &&OPCODE_OPERATOR_VALIDATED, \
&&OPCODE_EXTENDS_TEST, \
&&OPCODE_IS_BUILTIN, \
&&OPCODE_SET, \
@@ -468,6 +469,23 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
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) {
CHECK_SPACE(4);