Răsfoiți Sursa

Merge pull request #47727 from vnen/gdscript-less-addressing

Reduce number of addressing modes in GDScript VM
Rémi Verschelde 4 ani în urmă
părinte
comite
3aadbec23a

+ 21 - 23
modules/gdscript/gdscript_byte_codegen.cpp

@@ -59,12 +59,7 @@ uint32_t GDScriptByteCodeGenerator::add_local_constant(const StringName &p_name,
 }
 
 uint32_t GDScriptByteCodeGenerator::add_or_get_constant(const Variant &p_constant) {
-	if (constant_map.has(p_constant)) {
-		return constant_map[p_constant];
-	}
-	int index = constant_map.size();
-	constant_map[p_constant] = index;
-	return index;
+	return get_constant_pos(p_constant);
 }
 
 uint32_t GDScriptByteCodeGenerator::add_or_get_name(const StringName &p_name) {
@@ -612,7 +607,8 @@ void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Addr
 			} break;
 			case GDScriptDataType::NATIVE: {
 				int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_target.type.native_type];
-				class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS);
+				Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];
+				class_idx = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
 				append(GDScriptFunction::OPCODE_ASSIGN_TYPED_NATIVE, 3);
 				append(p_target);
 				append(p_source);
@@ -621,8 +617,7 @@ void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Addr
 			case GDScriptDataType::SCRIPT:
 			case GDScriptDataType::GDSCRIPT: {
 				Variant script = p_target.type.script_type;
-				int idx = get_constant_pos(script);
-				idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
+				int idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
 
 				append(GDScriptFunction::OPCODE_ASSIGN_TYPED_SCRIPT, 3);
 				append(p_target);
@@ -673,6 +668,12 @@ void GDScriptByteCodeGenerator::write_assign_default_parameter(const Address &p_
 	function->default_arguments.push_back(opcodes.size());
 }
 
+void GDScriptByteCodeGenerator::write_store_named_global(const Address &p_dst, const StringName &p_global) {
+	append(GDScriptFunction::OPCODE_STORE_NAMED_GLOBAL, 1);
+	append(p_dst);
+	append(p_global);
+}
+
 void GDScriptByteCodeGenerator::write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) {
 	int index = 0;
 
@@ -683,16 +684,14 @@ void GDScriptByteCodeGenerator::write_cast(const Address &p_target, const Addres
 		} break;
 		case GDScriptDataType::NATIVE: {
 			int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_type.native_type];
-			class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS);
+			Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];
 			append(GDScriptFunction::OPCODE_CAST_TO_NATIVE, 3);
-			index = class_idx;
+			index = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
 		} break;
 		case GDScriptDataType::SCRIPT:
 		case GDScriptDataType::GDSCRIPT: {
 			Variant script = p_type.script_type;
-			int idx = get_constant_pos(script);
-			idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
-
+			int idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
 			append(GDScriptFunction::OPCODE_CAST_TO_SCRIPT, 3);
 			index = idx;
 		} break;
@@ -903,7 +902,7 @@ void GDScriptByteCodeGenerator::write_call_self(const Address &p_target, const S
 	for (int i = 0; i < p_arguments.size(); i++) {
 		append(p_arguments[i]);
 	}
-	append(GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS);
+	append(GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
 	append(p_target);
 	append(p_arguments.size());
 	append(p_function_name);
@@ -914,7 +913,7 @@ void GDScriptByteCodeGenerator::write_call_self_async(const Address &p_target, c
 	for (int i = 0; i < p_arguments.size(); i++) {
 		append(p_arguments[i]);
 	}
-	append(GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS);
+	append(GDScriptFunction::ADDR_SELF);
 	append(p_target);
 	append(p_arguments.size());
 	append(p_function_name);
@@ -999,7 +998,7 @@ void GDScriptByteCodeGenerator::write_construct_typed_array(const Address &p_tar
 	if (p_element_type.script_type) {
 		Variant script_type = Ref<Script>(p_element_type.script_type);
 		int addr = get_constant_pos(script_type);
-		addr |= GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS;
+		addr |= GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS;
 		append(addr);
 	} else {
 		append(Address()); // null.
@@ -1296,8 +1295,7 @@ void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) {
 				const GDScriptDataType &element_type = function->return_type.get_container_element_type();
 
 				Variant script = function->return_type.script_type;
-				int script_idx = get_constant_pos(script);
-				script_idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
+				int script_idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
 
 				append(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY, 2);
 				append(p_return_value);
@@ -1326,7 +1324,7 @@ void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) {
 
 					Variant script = function->return_type.script_type;
 					int script_idx = get_constant_pos(script);
-					script_idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
+					script_idx |= (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
 
 					append(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY, 2);
 					append(p_return_value);
@@ -1343,14 +1341,14 @@ void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) {
 				append(GDScriptFunction::OPCODE_RETURN_TYPED_NATIVE, 2);
 				append(p_return_value);
 				int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[function->return_type.native_type];
-				class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS);
+				Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];
+				class_idx = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
 				append(class_idx);
 			} break;
 			case GDScriptDataType::GDSCRIPT:
 			case GDScriptDataType::SCRIPT: {
 				Variant script = function->return_type.script_type;
-				int script_idx = get_constant_pos(script);
-				script_idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
+				int script_idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
 
 				append(GDScriptFunction::OPCODE_RETURN_TYPED_SCRIPT, 2);
 				append(p_return_value);

+ 8 - 14
modules/gdscript/gdscript_byte_codegen.h

@@ -51,11 +51,11 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
 	List<Map<StringName, int>> block_identifier_stack;
 	Map<StringName, int> block_identifiers;
 
-	int current_stack_size = 0;
+	int current_stack_size = 3; // First 3 spots are reserved for self, class, and nil.
 	int current_temporaries = 0;
 	int current_locals = 0;
 	int current_line = 0;
-	int stack_max = 0;
+	int stack_max = 3;
 	int instr_args_max = 0;
 	int ptrcall_max = 0;
 
@@ -135,7 +135,7 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
 			ERR_PRINT("Leaving block with non-zero temporary variables: " + itos(current_temporaries));
 		}
 #endif
-		current_stack_size = current_locals;
+		current_stack_size = current_locals + 3; // Keep the 3 reserved slots for self, class, and nil.
 
 		if (debug_stack) {
 			for (Map<StringName, int>::Element *E = block_identifiers.front(); E; E = E->next()) {
@@ -300,26 +300,19 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
 	int address_of(const Address &p_address) {
 		switch (p_address.mode) {
 			case Address::SELF:
-				return GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS;
+				return GDScriptFunction::ADDR_SELF;
 			case Address::CLASS:
-				return GDScriptFunction::ADDR_TYPE_CLASS << GDScriptFunction::ADDR_BITS;
+				return GDScriptFunction::ADDR_CLASS;
 			case Address::MEMBER:
 				return p_address.address | (GDScriptFunction::ADDR_TYPE_MEMBER << GDScriptFunction::ADDR_BITS);
-			case Address::CLASS_CONSTANT:
-				return p_address.address | (GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT << GDScriptFunction::ADDR_BITS);
-			case Address::LOCAL_CONSTANT:
 			case Address::CONSTANT:
-				return p_address.address | (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
+				return p_address.address | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
 			case Address::LOCAL_VARIABLE:
 			case Address::TEMPORARY:
 			case Address::FUNCTION_PARAMETER:
 				return p_address.address | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
-			case Address::GLOBAL:
-				return p_address.address | (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS);
-			case Address::NAMED_GLOBAL:
-				return p_address.address | (GDScriptFunction::ADDR_TYPE_NAMED_GLOBAL << GDScriptFunction::ADDR_BITS);
 			case Address::NIL:
-				return GDScriptFunction::ADDR_TYPE_NIL << GDScriptFunction::ADDR_BITS;
+				return GDScriptFunction::ADDR_NIL;
 		}
 		return -1; // Unreachable.
 	}
@@ -441,6 +434,7 @@ public:
 	virtual void write_assign_true(const Address &p_target) override;
 	virtual void write_assign_false(const Address &p_target) override;
 	virtual void write_assign_default_parameter(const Address &p_dst, const Address &p_src) override;
+	virtual void write_store_named_global(const Address &p_dst, const StringName &p_global) override;
 	virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) override;
 	virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
 	virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;

+ 1 - 4
modules/gdscript/gdscript_codegen.h

@@ -45,13 +45,9 @@ public:
 			CLASS,
 			MEMBER,
 			CONSTANT,
-			CLASS_CONSTANT,
-			LOCAL_CONSTANT,
 			LOCAL_VARIABLE,
 			FUNCTION_PARAMETER,
 			TEMPORARY,
-			GLOBAL,
-			NAMED_GLOBAL,
 			NIL,
 		};
 		AddressMode mode = NIL;
@@ -123,6 +119,7 @@ public:
 	virtual void write_assign_true(const Address &p_target) = 0;
 	virtual void write_assign_false(const Address &p_target) = 0;
 	virtual void write_assign_default_parameter(const Address &dst, const Address &src) = 0;
+	virtual void write_store_named_global(const Address &p_dst, const StringName &p_global) = 0;
 	virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) = 0;
 	virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
 	virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;

+ 6 - 3
modules/gdscript/gdscript_compiler.cpp

@@ -262,7 +262,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
 					GDScriptNativeClass *nc = nullptr;
 					while (scr) {
 						if (scr->constants.has(identifier)) {
-							return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CLASS_CONSTANT, gen->add_or_get_name(identifier)); // TODO: Get type here.
+							return codegen.add_constant(scr->constants[identifier]); // TODO: Get type here.
 						}
 						if (scr->native.is_valid()) {
 							nc = scr->native.ptr();
@@ -319,7 +319,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
 
 			if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) {
 				int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier];
-				return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::GLOBAL, idx); // TODO: Get type.
+				Variant global = GDScriptLanguage::get_singleton()->get_global_array()[idx];
+				return codegen.add_constant(global); // TODO: Get type.
 			}
 
 			// Try global classes.
@@ -347,7 +348,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
 
 #ifdef TOOLS_ENABLED
 			if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(identifier)) {
-				return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::NAMED_GLOBAL, gen->add_or_get_name(identifier)); // TODO: Get type.
+				GDScriptCodeGenerator::Address global = codegen.add_temporary(); // TODO: Get type.
+				gen->write_store_named_global(global, identifier);
+				return global;
 			}
 #endif
 

+ 1 - 1
modules/gdscript/gdscript_compiler.h

@@ -61,7 +61,7 @@ class GDScriptCompiler {
 
 		GDScriptCodeGenerator::Address add_local_constant(const StringName &p_name, const Variant &p_value) {
 			uint32_t addr = generator->add_local_constant(p_name, p_value);
-			locals[p_name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::LOCAL_CONSTANT, addr);
+			locals[p_name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CONSTANT, addr);
 			return locals[p_name];
 		}
 

+ 19 - 23
modules/gdscript/gdscript_disassembler.cpp

@@ -69,35 +69,23 @@ static String _disassemble_address(const GDScript *p_script, const GDScriptFunct
 	int addr = p_address & GDScriptFunction::ADDR_MASK;
 
 	switch (p_address >> GDScriptFunction::ADDR_BITS) {
-		case GDScriptFunction::ADDR_TYPE_SELF: {
-			return "self";
-		} break;
-		case GDScriptFunction::ADDR_TYPE_CLASS: {
-			return "class";
-		} break;
 		case GDScriptFunction::ADDR_TYPE_MEMBER: {
 			return "member(" + p_script->debug_get_member_by_index(addr) + ")";
 		} break;
-		case GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT: {
-			return "class_const(" + p_function.get_global_name(addr) + ")";
-		} break;
-		case GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT: {
+		case GDScriptFunction::ADDR_TYPE_CONSTANT: {
 			return "const(" + _get_variant_string(p_function.get_constant(addr)) + ")";
 		} break;
 		case GDScriptFunction::ADDR_TYPE_STACK: {
-			return "stack(" + itos(addr) + ")";
-		} break;
-		case GDScriptFunction::ADDR_TYPE_STACK_VARIABLE: {
-			return "var_stack(" + itos(addr) + ")";
-		} break;
-		case GDScriptFunction::ADDR_TYPE_GLOBAL: {
-			return "global(" + _get_variant_string(GDScriptLanguage::get_singleton()->get_global_array()[addr]) + ")";
-		} break;
-		case GDScriptFunction::ADDR_TYPE_NAMED_GLOBAL: {
-			return "named_global(" + p_function.get_global_name(addr) + ")";
-		} break;
-		case GDScriptFunction::ADDR_TYPE_NIL: {
-			return "nil";
+			switch (addr) {
+				case GDScriptFunction::ADDR_STACK_SELF:
+					return "self";
+				case GDScriptFunction::ADDR_STACK_CLASS:
+					return "class";
+				case GDScriptFunction::ADDR_STACK_NIL:
+					return "nil";
+				default:
+					return "stack(" + itos(addr) + ")";
+			}
 		} break;
 	}
 
@@ -885,6 +873,14 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
 				incr += 5;
 			} break;
 				DISASSEMBLE_ITERATE_TYPES(DISASSEMBLE_ITERATE);
+			case OPCODE_STORE_NAMED_GLOBAL: {
+				text += "store named global ";
+				text += DADDR(1);
+				text += " = ";
+				text += String(_global_names_ptr[_code_ptr[ip + 2]]);
+
+				incr += 3;
+			} break;
 			case OPCODE_LINE: {
 				int line = _code_ptr[ip + 1] - 1;
 				if (line >= 0 && line < p_code_lines.size()) {

+ 13 - 11
modules/gdscript/gdscript_function.h

@@ -350,6 +350,7 @@ public:
 		OPCODE_ITERATE_PACKED_VECTOR3_ARRAY,
 		OPCODE_ITERATE_PACKED_COLOR_ARRAY,
 		OPCODE_ITERATE_OBJECT,
+		OPCODE_STORE_NAMED_GLOBAL,
 		OPCODE_ASSERT,
 		OPCODE_BREAKPOINT,
 		OPCODE_LINE,
@@ -360,16 +361,18 @@ public:
 		ADDR_BITS = 24,
 		ADDR_MASK = ((1 << ADDR_BITS) - 1),
 		ADDR_TYPE_MASK = ~ADDR_MASK,
-		ADDR_TYPE_SELF = 0,
-		ADDR_TYPE_CLASS = 1,
+		ADDR_TYPE_STACK = 0,
+		ADDR_TYPE_CONSTANT = 1,
 		ADDR_TYPE_MEMBER = 2,
-		ADDR_TYPE_CLASS_CONSTANT = 3,
-		ADDR_TYPE_LOCAL_CONSTANT = 4,
-		ADDR_TYPE_STACK = 5,
-		ADDR_TYPE_STACK_VARIABLE = 6,
-		ADDR_TYPE_GLOBAL = 7,
-		ADDR_TYPE_NAMED_GLOBAL = 8,
-		ADDR_TYPE_NIL = 9
+	};
+
+	enum FixedAddresses {
+		ADDR_STACK_SELF = 0,
+		ADDR_STACK_CLASS = 1,
+		ADDR_STACK_NIL = 2,
+		ADDR_SELF = ADDR_STACK_SELF | (ADDR_TYPE_STACK << ADDR_BITS),
+		ADDR_CLASS = ADDR_STACK_CLASS | (ADDR_TYPE_STACK << ADDR_BITS),
+		ADDR_NIL = ADDR_STACK_NIL | (ADDR_TYPE_STACK << ADDR_BITS),
 	};
 
 	enum Instruction {
@@ -462,7 +465,7 @@ private:
 
 	List<StackDebug> stack_debug;
 
-	_FORCE_INLINE_ Variant *_get_variant(int p_address, GDScriptInstance *p_instance, GDScript *p_script, Variant &self, Variant &static_ref, Variant *p_stack, String &r_error) const;
+	_FORCE_INLINE_ Variant *_get_variant(int p_address, GDScriptInstance *p_instance, Variant *p_stack, String &r_error) const;
 	_FORCE_INLINE_ String _get_call_error(const Callable::CallError &p_err, const String &p_where, const Variant **argptrs) const;
 
 	friend class GDScriptLanguage;
@@ -497,7 +500,6 @@ public:
 #endif
 		Vector<uint8_t> stack;
 		int stack_size = 0;
-		Variant self;
 		uint32_t alloca_size = 0;
 		int ip = 0;
 		int line = 0;

+ 59 - 114
modules/gdscript/gdscript_vm.cpp

@@ -34,22 +34,22 @@
 #include "core/os/os.h"
 #include "gdscript.h"
 
-Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_instance, GDScript *p_script, Variant &self, Variant &static_ref, Variant *p_stack, String &r_error) const {
+Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_instance, Variant *p_stack, String &r_error) const {
 	int address = p_address & ADDR_MASK;
 
 	//sequential table (jump table generated by compiler)
 	switch ((p_address & ADDR_TYPE_MASK) >> ADDR_BITS) {
-		case ADDR_TYPE_SELF: {
+		case ADDR_TYPE_STACK: {
 #ifdef DEBUG_ENABLED
-			if (unlikely(!p_instance)) {
-				r_error = "Cannot access self without instance.";
-				return nullptr;
-			}
+			ERR_FAIL_INDEX_V(address, _stack_size, nullptr);
 #endif
-			return &self;
+			return &p_stack[address];
 		} break;
-		case ADDR_TYPE_CLASS: {
-			return &static_ref;
+		case ADDR_TYPE_CONSTANT: {
+#ifdef DEBUG_ENABLED
+			ERR_FAIL_INDEX_V(address, _constant_count, nullptr);
+#endif
+			return &_constants_ptr[address];
 		} break;
 		case ADDR_TYPE_MEMBER: {
 #ifdef DEBUG_ENABLED
@@ -61,65 +61,6 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta
 			//member indexing is O(1)
 			return &p_instance->members.write[address];
 		} break;
-		case ADDR_TYPE_CLASS_CONSTANT: {
-			//todo change to index!
-			GDScript *s = p_script;
-#ifdef DEBUG_ENABLED
-			ERR_FAIL_INDEX_V(address, _global_names_count, nullptr);
-#endif
-			const StringName *sn = &_global_names_ptr[address];
-
-			while (s) {
-				GDScript *o = s;
-				while (o) {
-					Map<StringName, Variant>::Element *E = o->constants.find(*sn);
-					if (E) {
-						return &E->get();
-					}
-					o = o->_owner;
-				}
-				s = s->_base;
-			}
-
-			ERR_FAIL_V_MSG(nullptr, "GDScriptCompiler bug.");
-		} break;
-		case ADDR_TYPE_LOCAL_CONSTANT: {
-#ifdef DEBUG_ENABLED
-			ERR_FAIL_INDEX_V(address, _constant_count, nullptr);
-#endif
-			return &_constants_ptr[address];
-		} break;
-		case ADDR_TYPE_STACK:
-		case ADDR_TYPE_STACK_VARIABLE: {
-#ifdef DEBUG_ENABLED
-			ERR_FAIL_INDEX_V(address, _stack_size, nullptr);
-#endif
-			return &p_stack[address];
-		} break;
-		case ADDR_TYPE_GLOBAL: {
-#ifdef DEBUG_ENABLED
-			ERR_FAIL_INDEX_V(address, GDScriptLanguage::get_singleton()->get_global_array_size(), nullptr);
-#endif
-			return &GDScriptLanguage::get_singleton()->get_global_array()[address];
-		} break;
-#ifdef TOOLS_ENABLED
-		case ADDR_TYPE_NAMED_GLOBAL: {
-#ifdef DEBUG_ENABLED
-			ERR_FAIL_INDEX_V(address, _global_names_count, nullptr);
-#endif
-			StringName id = _global_names_ptr[address];
-
-			if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(id)) {
-				return (Variant *)&GDScriptLanguage::get_singleton()->get_named_globals_map()[id];
-			} else {
-				r_error = "Autoload singleton '" + String(id) + "' has been removed.";
-				return nullptr;
-			}
-		} break;
-#endif
-		case ADDR_TYPE_NIL: {
-			return &nil;
-		} break;
 	}
 
 	ERR_FAIL_V_MSG(nullptr, "Bad code! (unknown addressing mode).");
@@ -340,6 +281,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
 		&&OPCODE_ITERATE_PACKED_VECTOR3_ARRAY,       \
 		&&OPCODE_ITERATE_PACKED_COLOR_ARRAY,         \
 		&&OPCODE_ITERATE_OBJECT,                     \
+		&&OPCODE_STORE_NAMED_GLOBAL,                 \
 		&&OPCODE_ASSERT,                             \
 		&&OPCODE_BREAKPOINT,                         \
 		&&OPCODE_LINE,                               \
@@ -415,11 +357,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
 
 	r_err.error = Callable::CallError::CALL_OK;
 
-	Variant self;
-	Variant static_ref;
 	Variant retvalue;
 	Variant *stack = nullptr;
-	Variant **instruction_args;
+	Variant **instruction_args = nullptr;
 	const void **call_args_ptr = nullptr;
 	int defarg = 0;
 
@@ -444,7 +384,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
 		script = p_state->script;
 		p_instance = p_state->instance;
 		defarg = p_state->defarg;
-		self = p_state->self;
 
 	} else {
 		if (p_argcount != _argument_count) {
@@ -462,55 +401,49 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
 			}
 		}
 
-		alloca_size = sizeof(Variant *) * _instruction_args_size + sizeof(Variant) * _stack_size;
-
-		if (alloca_size) {
-			uint8_t *aptr = (uint8_t *)alloca(alloca_size);
+		// Add 3 here for self, class, and nil.
+		alloca_size = sizeof(Variant *) * 3 + sizeof(Variant *) * _instruction_args_size + sizeof(Variant) * _stack_size;
 
-			if (_stack_size) {
-				stack = (Variant *)aptr;
-				for (int i = 0; i < p_argcount; i++) {
-					if (!argument_types[i].has_type) {
-						memnew_placement(&stack[i], Variant(*p_args[i]));
-						continue;
-					}
+		uint8_t *aptr = (uint8_t *)alloca(alloca_size);
+		stack = (Variant *)aptr;
 
-					if (!argument_types[i].is_type(*p_args[i], true)) {
-						r_err.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
-						r_err.argument = i;
-						r_err.expected = argument_types[i].kind == GDScriptDataType::BUILTIN ? argument_types[i].builtin_type : Variant::OBJECT;
-						return Variant();
-					}
-					if (argument_types[i].kind == GDScriptDataType::BUILTIN) {
-						Variant arg;
-						Variant::construct(argument_types[i].builtin_type, arg, &p_args[i], 1, r_err);
-						memnew_placement(&stack[i], Variant(arg));
-					} else {
-						memnew_placement(&stack[i], Variant(*p_args[i]));
-					}
-				}
-				for (int i = p_argcount; i < _stack_size; i++) {
-					memnew_placement(&stack[i], Variant);
-				}
-			} else {
-				stack = nullptr;
+		for (int i = 0; i < p_argcount; i++) {
+			if (!argument_types[i].has_type) {
+				memnew_placement(&stack[i + 3], Variant(*p_args[i]));
+				continue;
 			}
 
-			if (_instruction_args_size) {
-				instruction_args = (Variant **)&aptr[sizeof(Variant) * _stack_size];
+			if (!argument_types[i].is_type(*p_args[i], true)) {
+				r_err.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+				r_err.argument = i;
+				r_err.expected = argument_types[i].kind == GDScriptDataType::BUILTIN ? argument_types[i].builtin_type : Variant::OBJECT;
+				return Variant();
+			}
+			if (argument_types[i].kind == GDScriptDataType::BUILTIN) {
+				Variant arg;
+				Variant::construct(argument_types[i].builtin_type, arg, &p_args[i], 1, r_err);
+				memnew_placement(&stack[i + 3], Variant(arg));
 			} else {
-				instruction_args = nullptr;
+				memnew_placement(&stack[i + 3], Variant(*p_args[i]));
 			}
+		}
+		for (int i = p_argcount + 3; i < _stack_size; i++) {
+			memnew_placement(&stack[i], Variant);
+		}
 
+		memnew_placement(&stack[ADDR_STACK_NIL], Variant);
+
+		if (_instruction_args_size) {
+			instruction_args = (Variant **)&aptr[sizeof(Variant) * _stack_size];
 		} else {
-			stack = nullptr;
 			instruction_args = nullptr;
 		}
 
 		if (p_instance) {
-			self = p_instance->owner;
+			memnew_placement(&stack[ADDR_STACK_SELF], Variant(p_instance->owner));
 			script = p_instance->script.ptr();
 		} else {
+			memnew_placement(&stack[ADDR_STACK_SELF], Variant);
 			script = _script;
 		}
 	}
@@ -520,7 +453,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
 		call_args_ptr = nullptr;
 	}
 
-	static_ref = script;
+	memnew_placement(&stack[ADDR_STACK_CLASS], Variant(script));
 
 	String err_text;
 
@@ -541,10 +474,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
 #define CHECK_SPACE(m_space) \
 	GD_ERR_BREAK((ip + m_space) > _code_size)
 
-#define GET_VARIANT_PTR(m_v, m_code_ofs)                                                                   \
-	Variant *m_v;                                                                                          \
-	m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, script, self, static_ref, stack, err_text); \
-	if (unlikely(!m_v))                                                                                    \
+#define GET_VARIANT_PTR(m_v, m_code_ofs)                                         \
+	Variant *m_v;                                                                \
+	m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, stack, err_text); \
+	if (unlikely(!m_v))                                                          \
 		OPCODE_BREAK;
 
 #else
@@ -552,7 +485,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
 #define CHECK_SPACE(m_space)
 #define GET_VARIANT_PTR(m_v, m_code_ofs) \
 	Variant *m_v;                        \
-	m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, script, self, static_ref, stack, err_text);
+	m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, stack, err_text);
 
 #endif
 
@@ -2038,7 +1971,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
 						memnew_placement(&gdfs->state.stack.write[sizeof(Variant) * i], Variant(stack[i]));
 					}
 					gdfs->state.stack_size = _stack_size;
-					gdfs->state.self = self;
 					gdfs->state.alloca_size = alloca_size;
 					gdfs->state.ip = ip + 2;
 					gdfs->state.line = line;
@@ -3028,6 +2960,19 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
 			}
 			DISPATCH_OPCODE;
 
+			OPCODE(OPCODE_STORE_NAMED_GLOBAL) {
+				CHECK_SPACE(3);
+				int globalname_idx = _code_ptr[ip + 2];
+				GD_ERR_BREAK(globalname_idx < 0 || globalname_idx >= _global_names_count);
+				const StringName *globalname = &_global_names_ptr[globalname_idx];
+
+				GET_INSTRUCTION_ARG(dst, 0);
+				*dst = GDScriptLanguage::get_singleton()->get_named_globals_map()[*globalname];
+
+				ip += 3;
+			}
+			DISPATCH_OPCODE;
+
 			OPCODE(OPCODE_ASSERT) {
 				CHECK_SPACE(3);