summaryrefslogtreecommitdiffstats
path: root/modules/gdscript/gdscript_compiler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript/gdscript_compiler.cpp')
-rw-r--r--modules/gdscript/gdscript_compiler.cpp28
1 files changed, 22 insertions, 6 deletions
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index b0ac4aa800..d8b44a558f 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -1064,6 +1064,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
// Get at (potential) root stack pos, so it can be returned.
GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, chain.back()->get()->base);
+ const bool base_known_type = base.type.has_type;
+ const bool base_is_shared = Variant::is_type_shared(base.type.builtin_type);
if (r_error) {
return GDScriptCodeGenerator::Address();
@@ -1074,7 +1076,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
// In case the base has a setter, don't use the address directly, as we want to call that setter.
// So use a temp value instead and call the setter at the end.
GDScriptCodeGenerator::Address base_temp;
- if (base.mode == GDScriptCodeGenerator::Address::MEMBER && member_property_has_setter && !member_property_is_in_setter) {
+ if ((!base_known_type || !base_is_shared) && base.mode == GDScriptCodeGenerator::Address::MEMBER && member_property_has_setter && !member_property_is_in_setter) {
base_temp = codegen.add_temporary(base.type);
gen->write_assign(base_temp, base);
prev_base = base_temp;
@@ -1229,8 +1231,14 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
}
}
} else if (base_temp.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ if (!base_known_type) {
+ gen->write_jump_if_shared(base);
+ }
// Save the temp value back to the base by calling its setter.
gen->write_call(GDScriptCodeGenerator::Address(), base, member_property_setter_function, { assigned });
+ if (!base_known_type) {
+ gen->write_end_jump_if_shared();
+ }
}
if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
@@ -1893,7 +1901,7 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
case GDScriptParser::Node::MATCH: {
const GDScriptParser::MatchNode *match = static_cast<const GDScriptParser::MatchNode *>(s);
- codegen.start_block(); // Add an extra block, since the binding pattern and @special variables belong to the branch scope.
+ codegen.start_block(); // Add an extra block, since @special locals belong to the match scope.
// Evaluate the match expression.
GDScriptCodeGenerator::Address value = codegen.add_local("@match_value", _gdtype_from_datatype(match->test->get_datatype(), codegen.script));
@@ -1931,7 +1939,7 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
const GDScriptParser::MatchBranchNode *branch = match->branches[j];
- codegen.start_block(); // Create an extra block around for binds.
+ codegen.start_block(); // Add an extra block, since binds belong to the match branch scope.
// Add locals in block before patterns, so temporaries don't use the stack address for binds.
List<GDScriptCodeGenerator::Address> branch_locals = _add_block_locals(codegen, branch->block);
@@ -1983,13 +1991,15 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
_clear_block_locals(codegen, branch_locals);
- codegen.end_block(); // Get out of extra block.
+ codegen.end_block(); // Get out of extra block for binds.
}
// End all nested `if`s.
for (int j = 0; j < match->branches.size(); j++) {
gen->write_endif();
}
+
+ codegen.end_block(); // Get out of extra block for match's @special locals.
} break;
case GDScriptParser::Node::IF: {
const GDScriptParser::IfNode *if_n = static_cast<const GDScriptParser::IfNode *>(s);
@@ -2023,7 +2033,9 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
case GDScriptParser::Node::FOR: {
const GDScriptParser::ForNode *for_n = static_cast<const GDScriptParser::ForNode *>(s);
- codegen.start_block(); // Add an extra block, since the iterator and @special variables belong to the loop scope.
+ // Add an extra block, since the iterator and @special locals belong to the loop scope.
+ // Also we use custom logic to clear block locals.
+ codegen.start_block();
GDScriptCodeGenerator::Address iterator = codegen.add_local(for_n->variable->name, _gdtype_from_datatype(for_n->variable->get_datatype(), codegen.script));
@@ -2056,11 +2068,13 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
_clear_block_locals(codegen, loop_locals); // Outside loop, after block - for `break` and normal exit.
- codegen.end_block(); // Get out of extra block.
+ codegen.end_block(); // Get out of extra block for loop iterator, @special locals, and custom locals clearing.
} break;
case GDScriptParser::Node::WHILE: {
const GDScriptParser::WhileNode *while_n = static_cast<const GDScriptParser::WhileNode *>(s);
+ codegen.start_block(); // Add an extra block, since we use custom logic to clear block locals.
+
gen->start_while_condition();
GDScriptCodeGenerator::Address condition = _parse_expression(codegen, err, while_n->condition);
@@ -2087,6 +2101,8 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
gen->write_endwhile();
_clear_block_locals(codegen, loop_locals); // Outside loop, after block - for `break` and normal exit.
+
+ codegen.end_block(); // Get out of extra block for custom locals clearing.
} break;
case GDScriptParser::Node::BREAK: {
gen->write_break();