From c707d6fe717c43fecafa0aca53182f214268ec16 Mon Sep 17 00:00:00 2001 From: George Marques Date: Fri, 13 Nov 2020 10:31:14 -0300 Subject: GDScript: Gather instructions arguments beforehand Almost all instructions need variant arguments. With this change they are loaded in an array before each instruction call. This makes the addressing code be localized to less places, improving compilation overhead and binary size by a small margin. This should not affect performance. --- modules/gdscript/gdscript_vm.cpp | 293 +++++++++++++++++++-------------------- 1 file changed, 143 insertions(+), 150 deletions(-) (limited to 'modules/gdscript/gdscript_vm.cpp') diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index 65bea37b94..a10f2a9274 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -231,13 +231,14 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const #define OPCODE(m_op) \ m_op: -#define OPCODE_WHILE(m_test) +#define OPCODE_WHILE(m_test) \ + OPSWHILE: #define OPCODES_END \ OPSEXIT: #define OPCODES_OUT \ OPSOUT: -#define DISPATCH_OPCODE goto *switch_table_ops[_code_ptr[ip]] -#define OPCODE_SWITCH(m_test) DISPATCH_OPCODE; +#define DISPATCH_OPCODE goto OPSWHILE +#define OPCODE_SWITCH(m_test) goto *switch_table_ops[m_test]; #define OPCODE_BREAK goto OPSEXIT #define OPCODE_OUT goto OPSOUT #else @@ -265,7 +266,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a Variant static_ref; Variant retvalue; Variant *stack = nullptr; - Variant **call_args; + Variant **instruction_args; int defarg = 0; #ifdef DEBUG_ENABLED @@ -282,7 +283,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a if (p_state) { //use existing (supplied) state (awaited) stack = (Variant *)p_state->stack.ptr(); - call_args = (Variant **)&p_state->stack.ptr()[sizeof(Variant) * p_state->stack_size]; //ptr() to avoid bounds check + instruction_args = (Variant **)&p_state->stack.ptr()[sizeof(Variant) * p_state->stack_size]; //ptr() to avoid bounds check line = p_state->line; ip = p_state->ip; alloca_size = p_state->stack.size(); @@ -307,7 +308,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } } - alloca_size = sizeof(Variant *) * _call_size + sizeof(Variant) * _stack_size; + alloca_size = sizeof(Variant *) * _instruction_args_size + sizeof(Variant) * _stack_size; if (alloca_size) { uint8_t *aptr = (uint8_t *)alloca(alloca_size); @@ -341,15 +342,15 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a stack = nullptr; } - if (_call_size) { - call_args = (Variant **)&aptr[sizeof(Variant) * _stack_size]; + if (_instruction_args_size) { + instruction_args = (Variant **)&aptr[sizeof(Variant) * _stack_size]; } else { - call_args = nullptr; + instruction_args = nullptr; } } else { stack = nullptr; - call_args = nullptr; + instruction_args = nullptr; } if (p_instance) { @@ -400,6 +401,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #endif +#define GET_INSTRUCTION_ARG(m_v, m_idx) \ + Variant *m_v = instruction_args[m_idx] + #ifdef DEBUG_ENABLED uint64_t function_start_time = 0; @@ -421,18 +425,24 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #else OPCODE_WHILE(true) { #endif + // Load arguments for the instruction before each instruction. + int instr_arg_count = ((_code_ptr[ip]) & INSTR_ARGS_MASK) >> INSTR_BITS; + for (int i = 0; i < instr_arg_count; i++) { + GET_VARIANT_PTR(v, i + 1); + instruction_args[i] = v; + } - OPCODE_SWITCH(_code_ptr[ip]) { + OPCODE_SWITCH(_code_ptr[ip] & INSTR_MASK) { OPCODE(OPCODE_OPERATOR) { CHECK_SPACE(5); bool valid; - Variant::Operator op = (Variant::Operator)_code_ptr[ip + 1]; + Variant::Operator op = (Variant::Operator)_code_ptr[ip + 4]; GD_ERR_BREAK(op >= Variant::OP_MAX); - GET_VARIANT_PTR(a, 2); - GET_VARIANT_PTR(b, 3); - GET_VARIANT_PTR(dst, 4); + GET_INSTRUCTION_ARG(a, 0); + GET_INSTRUCTION_ARG(b, 1); + GET_INSTRUCTION_ARG(dst, 2); #ifdef DEBUG_ENABLED @@ -461,9 +471,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE(OPCODE_EXTENDS_TEST) { CHECK_SPACE(4); - GET_VARIANT_PTR(a, 1); - GET_VARIANT_PTR(b, 2); - GET_VARIANT_PTR(dst, 3); + GET_INSTRUCTION_ARG(a, 0); + GET_INSTRUCTION_ARG(b, 1); + GET_INSTRUCTION_ARG(dst, 2); #ifdef DEBUG_ENABLED if (b->get_type() != Variant::OBJECT || b->operator Object *() == nullptr) { @@ -536,9 +546,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE(OPCODE_IS_BUILTIN) { CHECK_SPACE(4); - GET_VARIANT_PTR(value, 1); - Variant::Type var_type = (Variant::Type)_code_ptr[ip + 2]; - GET_VARIANT_PTR(dst, 3); + GET_INSTRUCTION_ARG(value, 0); + GET_INSTRUCTION_ARG(dst, 1); + Variant::Type var_type = (Variant::Type)_code_ptr[ip + 3]; GD_ERR_BREAK(var_type < 0 || var_type >= Variant::VARIANT_MAX); @@ -550,9 +560,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE(OPCODE_SET) { CHECK_SPACE(3); - GET_VARIANT_PTR(dst, 1); - GET_VARIANT_PTR(index, 2); - GET_VARIANT_PTR(value, 3); + GET_INSTRUCTION_ARG(dst, 0); + GET_INSTRUCTION_ARG(index, 1); + GET_INSTRUCTION_ARG(value, 2); bool valid; dst->set(*index, *value, &valid); @@ -576,9 +586,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE(OPCODE_GET) { CHECK_SPACE(3); - GET_VARIANT_PTR(src, 1); - GET_VARIANT_PTR(index, 2); - GET_VARIANT_PTR(dst, 3); + GET_INSTRUCTION_ARG(src, 0); + GET_INSTRUCTION_ARG(index, 1); + GET_INSTRUCTION_ARG(dst, 2); bool valid; #ifdef DEBUG_ENABLED @@ -608,10 +618,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE(OPCODE_SET_NAMED) { CHECK_SPACE(3); - GET_VARIANT_PTR(dst, 1); - GET_VARIANT_PTR(value, 3); + GET_INSTRUCTION_ARG(dst, 0); + GET_INSTRUCTION_ARG(value, 1); - int indexname = _code_ptr[ip + 2]; + int indexname = _code_ptr[ip + 3]; GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count); const StringName *index = &_global_names_ptr[indexname]; @@ -633,10 +643,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE(OPCODE_GET_NAMED) { CHECK_SPACE(4); - GET_VARIANT_PTR(src, 1); - GET_VARIANT_PTR(dst, 3); + GET_INSTRUCTION_ARG(src, 0); + GET_INSTRUCTION_ARG(dst, 1); - int indexname = _code_ptr[ip + 2]; + int indexname = _code_ptr[ip + 3]; GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count); const StringName *index = &_global_names_ptr[indexname]; @@ -666,10 +676,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE(OPCODE_SET_MEMBER) { CHECK_SPACE(3); - int indexname = _code_ptr[ip + 1]; + GET_INSTRUCTION_ARG(src, 0); + int indexname = _code_ptr[ip + 2]; GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count); const StringName *index = &_global_names_ptr[indexname]; - GET_VARIANT_PTR(src, 2); bool valid; #ifndef DEBUG_ENABLED @@ -690,11 +700,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE(OPCODE_GET_MEMBER) { CHECK_SPACE(3); - int indexname = _code_ptr[ip + 1]; + GET_INSTRUCTION_ARG(dst, 0); + int indexname = _code_ptr[ip + 2]; GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count); const StringName *index = &_global_names_ptr[indexname]; - GET_VARIANT_PTR(dst, 2); - #ifndef DEBUG_ENABLED ClassDB::get_property(p_instance->owner, *index, *dst); #else @@ -710,8 +719,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE(OPCODE_ASSIGN) { CHECK_SPACE(3); - GET_VARIANT_PTR(dst, 1); - GET_VARIANT_PTR(src, 2); + GET_INSTRUCTION_ARG(dst, 0); + GET_INSTRUCTION_ARG(src, 1); *dst = *src; @@ -721,7 +730,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE(OPCODE_ASSIGN_TRUE) { CHECK_SPACE(2); - GET_VARIANT_PTR(dst, 1); + GET_INSTRUCTION_ARG(dst, 0); *dst = true; @@ -731,7 +740,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE(OPCODE_ASSIGN_FALSE) { CHECK_SPACE(2); - GET_VARIANT_PTR(dst, 1); + GET_INSTRUCTION_ARG(dst, 0); *dst = false; @@ -741,10 +750,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE(OPCODE_ASSIGN_TYPED_BUILTIN) { CHECK_SPACE(4); - GET_VARIANT_PTR(dst, 2); - GET_VARIANT_PTR(src, 3); + GET_INSTRUCTION_ARG(dst, 0); + GET_INSTRUCTION_ARG(src, 1); - Variant::Type var_type = (Variant::Type)_code_ptr[ip + 1]; + Variant::Type var_type = (Variant::Type)_code_ptr[ip + 3]; GD_ERR_BREAK(var_type < 0 || var_type >= Variant::VARIANT_MAX); if (src->get_type() != var_type) { @@ -770,11 +779,11 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE(OPCODE_ASSIGN_TYPED_NATIVE) { CHECK_SPACE(4); - GET_VARIANT_PTR(dst, 2); - GET_VARIANT_PTR(src, 3); + GET_INSTRUCTION_ARG(dst, 0); + GET_INSTRUCTION_ARG(src, 1); #ifdef DEBUG_ENABLED - GET_VARIANT_PTR(type, 1); + GET_INSTRUCTION_ARG(type, 2); GDScriptNativeClass *nc = Object::cast_to(type->operator Object *()); GD_ERR_BREAK(!nc); if (src->get_type() != Variant::OBJECT && src->get_type() != Variant::NIL) { @@ -798,11 +807,11 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE(OPCODE_ASSIGN_TYPED_SCRIPT) { CHECK_SPACE(4); - GET_VARIANT_PTR(dst, 2); - GET_VARIANT_PTR(src, 3); + GET_INSTRUCTION_ARG(dst, 0); + GET_INSTRUCTION_ARG(src, 1); #ifdef DEBUG_ENABLED - GET_VARIANT_PTR(type, 1); + GET_INSTRUCTION_ARG(type, 2); Script *base_type = Object::cast_to