diff options
author | George Marques <george@gmarqu.es> | 2020-11-13 16:47:45 -0300 |
---|---|---|
committer | George Marques <george@gmarqu.es> | 2020-11-21 13:24:49 -0300 |
commit | 1ad5c926dc4d7a182b8621f360b7ce4697dffb25 (patch) | |
tree | de5daab39985b6203a8aed50089970276a883368 | |
parent | c707d6fe717c43fecafa0aca53182f214268ec16 (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.cpp | 28 | ||||
-rw-r--r-- | modules/gdscript/gdscript_byte_codegen.h | 19 | ||||
-rw-r--r-- | modules/gdscript/gdscript_disassembler.cpp | 11 | ||||
-rw-r--r-- | modules/gdscript/gdscript_function.h | 4 | ||||
-rw-r--r-- | modules/gdscript/gdscript_vm.cpp | 18 |
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); |