diff options
author | RĂ©mi Verschelde <remi@verschelde.fr> | 2022-06-27 23:25:53 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-27 23:25:53 +0200 |
commit | c4a426d6ec71865b971ad419bf925ce8b8f9c37b (patch) | |
tree | 4bcece6ac87faea0c66d76d647d8b151a54d4ecd /modules/gdscript | |
parent | 25baa32db068af49cda1d79ea211c9df6c47a547 (diff) | |
parent | 511a4b761c3b5bf565f6e580fc9774a99e72a53e (diff) |
Merge pull request #62462 from vnen/gdscript-setter-chaining
GDScript: Fix setter being called in chains for shared types
Diffstat (limited to 'modules/gdscript')
-rw-r--r-- | modules/gdscript/gdscript_byte_codegen.cpp | 12 | ||||
-rw-r--r-- | modules/gdscript/gdscript_byte_codegen.h | 2 | ||||
-rw-r--r-- | modules/gdscript/gdscript_codegen.h | 2 | ||||
-rw-r--r-- | modules/gdscript/gdscript_compiler.cpp | 66 | ||||
-rw-r--r-- | modules/gdscript/gdscript_disassembler.cpp | 8 | ||||
-rw-r--r-- | modules/gdscript/gdscript_function.h | 1 | ||||
-rw-r--r-- | modules/gdscript/gdscript_vm.cpp | 16 |
7 files changed, 88 insertions, 19 deletions
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index 3d5a39bf38..6a1effd680 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -1336,6 +1336,18 @@ void GDScriptByteCodeGenerator::write_endif() { if_jmp_addrs.pop_back(); } +void GDScriptByteCodeGenerator::write_jump_if_shared(const Address &p_value) { + append(GDScriptFunction::OPCODE_JUMP_IF_SHARED, 1); + append(p_value); + if_jmp_addrs.push_back(opcodes.size()); + append(0); // Jump destination, will be patched. +} + +void GDScriptByteCodeGenerator::write_end_jump_if_shared() { + patch_jump(if_jmp_addrs.back()->get()); + if_jmp_addrs.pop_back(); +} + void GDScriptByteCodeGenerator::start_for(const GDScriptDataType &p_iterator_type, const GDScriptDataType &p_list_type) { Address counter(Address::LOCAL_VARIABLE, add_local("@counter_pos", p_iterator_type), p_iterator_type); Address container(Address::LOCAL_VARIABLE, add_local("@container_pos", p_list_type), p_list_type); diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h index 6ee8fda533..f4b402fc96 100644 --- a/modules/gdscript/gdscript_byte_codegen.h +++ b/modules/gdscript/gdscript_byte_codegen.h @@ -479,6 +479,8 @@ public: virtual void write_if(const Address &p_condition) override; virtual void write_else() override; virtual void write_endif() override; + virtual void write_jump_if_shared(const Address &p_value) override; + virtual void write_end_jump_if_shared() override; virtual void start_for(const GDScriptDataType &p_iterator_type, const GDScriptDataType &p_list_type) override; virtual void write_for_assignment(const Address &p_variable, const Address &p_list) override; virtual void write_for() override; diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h index 326b66a295..81fa265aca 100644 --- a/modules/gdscript/gdscript_codegen.h +++ b/modules/gdscript/gdscript_codegen.h @@ -140,6 +140,8 @@ public: virtual void write_if(const Address &p_condition) = 0; virtual void write_else() = 0; virtual void write_endif() = 0; + virtual void write_jump_if_shared(const Address &p_value) = 0; + virtual void write_end_jump_if_shared() = 0; virtual void start_for(const GDScriptDataType &p_iterator_type, const GDScriptDataType &p_list_type) = 0; virtual void write_for_assignment(const Address &p_variable, const Address &p_list) = 0; virtual void write_for() = 0; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 16a0b17d61..1daf8ff7a9 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -1056,13 +1056,25 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code // Set back the values into their bases. for (const ChainInfo &info : set_chain) { - if (!info.is_named) { - gen->write_set(info.base, info.key, assigned); - if (info.key.mode == GDScriptCodeGenerator::Address::TEMPORARY) { - gen->pop_temporary(); + bool known_type = assigned.type.has_type; + bool is_shared = Variant::is_type_shared(assigned.type.builtin_type); + + if (!known_type) { + // Jump shared values since they are already updated in-place. + gen->write_jump_if_shared(assigned); + } + if (known_type && !is_shared) { + if (!info.is_named) { + gen->write_set(info.base, info.key, assigned); + if (info.key.mode == GDScriptCodeGenerator::Address::TEMPORARY) { + gen->pop_temporary(); + } + } else { + gen->write_set_named(info.base, info.name, assigned); } - } else { - gen->write_set_named(info.base, info.name, assigned); + } + if (!known_type) { + gen->write_end_jump_if_shared(); } if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) { gen->pop_temporary(); @@ -1070,19 +1082,35 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code assigned = info.base; } - // If this is a class member property, also assign to it. - // This allow things like: position.x += 2.0 - if (assign_class_member_property != StringName()) { - gen->write_set_member(assigned, assign_class_member_property); - } - // Same as above but for members - if (is_member_property) { - if (member_property_has_setter && !member_property_is_in_setter) { - Vector<GDScriptCodeGenerator::Address> args; - args.push_back(assigned); - gen->write_call(GDScriptCodeGenerator::Address(), GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF), member_property_setter_function, args); - } else { - gen->write_assign(target_member_property, assigned); + bool known_type = assigned.type.has_type; + bool is_shared = Variant::is_type_shared(assigned.type.builtin_type); + + if (!known_type || !is_shared) { + // If this is a class member property, also assign to it. + // This allow things like: position.x += 2.0 + if (assign_class_member_property != StringName()) { + if (!known_type) { + gen->write_jump_if_shared(assigned); + } + gen->write_set_member(assigned, assign_class_member_property); + if (!known_type) { + gen->write_end_jump_if_shared(); + } + } else if (is_member_property) { + // Same as above but for script members. + if (!known_type) { + gen->write_jump_if_shared(assigned); + } + if (member_property_has_setter && !member_property_is_in_setter) { + Vector<GDScriptCodeGenerator::Address> args; + args.push_back(assigned); + gen->write_call(GDScriptCodeGenerator::Address(), GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF), member_property_setter_function, args); + } else { + gen->write_assign(target_member_property, assigned); + } + if (!known_type) { + gen->write_end_jump_if_shared(); + } } } diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp index dc114f2eff..726f0efe2b 100644 --- a/modules/gdscript/gdscript_disassembler.cpp +++ b/modules/gdscript/gdscript_disassembler.cpp @@ -838,6 +838,14 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { incr = 1; } break; + case OPCODE_JUMP_IF_SHARED: { + text += "jump-if-shared "; + text += DADDR(1); + text += " to "; + text += itos(_code_ptr[ip + 2]); + + incr = 3; + } break; case OPCODE_RETURN: { text += "return "; text += DADDR(1); diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index d2ca795977..3f1265679b 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -304,6 +304,7 @@ public: OPCODE_JUMP_IF, OPCODE_JUMP_IF_NOT, OPCODE_JUMP_TO_DEF_ARGUMENT, + OPCODE_JUMP_IF_SHARED, OPCODE_RETURN, OPCODE_RETURN_TYPED_BUILTIN, OPCODE_RETURN_TYPED_ARRAY, diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index 20b8d29ec3..988a98a591 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -311,6 +311,7 @@ void (*type_init_function_table[])(Variant *) = { &&OPCODE_JUMP_IF, \ &&OPCODE_JUMP_IF_NOT, \ &&OPCODE_JUMP_TO_DEF_ARGUMENT, \ + &&OPCODE_JUMP_IF_SHARED, \ &&OPCODE_RETURN, \ &&OPCODE_RETURN_TYPED_BUILTIN, \ &&OPCODE_RETURN_TYPED_ARRAY, \ @@ -2361,6 +2362,21 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } DISPATCH_OPCODE; + OPCODE(OPCODE_JUMP_IF_SHARED) { + CHECK_SPACE(3); + + GET_INSTRUCTION_ARG(val, 0); + + if (val->is_shared()) { + int to = _code_ptr[ip + 2]; + GD_ERR_BREAK(to < 0 || to > _code_size); + ip = to; + } else { + ip += 3; + } + } + DISPATCH_OPCODE; + OPCODE(OPCODE_RETURN) { CHECK_SPACE(2); GET_INSTRUCTION_ARG(r, 0); |