瀏覽代碼

GDScript: Split Function code into multiple files

To improve organization and reduce the size of compilation units.
George Marques 4 年之前
父節點
當前提交
b6519d0d03
共有 3 個文件被更改,包括 2136 次插入1567 次删除
  1. 540 0
      modules/gdscript/gdscript_disassembler.cpp
  2. 0 1567
      modules/gdscript/gdscript_function.cpp
  3. 1596 0
      modules/gdscript/gdscript_vm.cpp

+ 540 - 0
modules/gdscript/gdscript_disassembler.cpp

@@ -0,0 +1,540 @@
+/*************************************************************************/
+/*  gdscript_disassembler.cpp                                            */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifdef DEBUG_ENABLED
+
+#include "gdscript_function.h"
+
+#include "core/string/string_builder.h"
+#include "gdscript.h"
+#include "gdscript_functions.h"
+
+static String _get_variant_string(const Variant &p_variant) {
+	String txt;
+	if (p_variant.get_type() == Variant::STRING) {
+		txt = "\"" + String(p_variant) + "\"";
+	} else if (p_variant.get_type() == Variant::STRING_NAME) {
+		txt = "&\"" + String(p_variant) + "\"";
+	} else if (p_variant.get_type() == Variant::NODE_PATH) {
+		txt = "^\"" + String(p_variant) + "\"";
+	} else if (p_variant.get_type() == Variant::OBJECT) {
+		Object *obj = p_variant;
+		if (!obj) {
+			txt = "null";
+		} else {
+			GDScriptNativeClass *cls = Object::cast_to<GDScriptNativeClass>(obj);
+			if (cls) {
+				txt += cls->get_name();
+				txt += " (class)";
+			} else {
+				txt = obj->get_class();
+				if (obj->get_script_instance()) {
+					txt += "(" + obj->get_script_instance()->get_script()->get_path() + ")";
+				}
+			}
+		}
+	} else {
+		txt = p_variant;
+	}
+	return txt;
+}
+
+static String _disassemble_address(const GDScript *p_script, const GDScriptFunction &p_function, int p_address) {
+	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: {
+			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";
+		} break;
+	}
+
+	return "<err>";
+}
+
+void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
+#define DADDR(m_ip) (_disassemble_address(_script, *this, _code_ptr[ip + m_ip]))
+
+	for (int ip = 0; ip < _code_size;) {
+		StringBuilder text;
+		int incr = 0;
+
+		text += " ";
+		text += itos(ip);
+		text += ": ";
+
+		// This makes the compiler complain if some opcode is unchecked in the switch.
+		Opcode code = Opcode(_code_ptr[ip]);
+
+		switch (code) {
+			case OPCODE_OPERATOR: {
+				int operation = _code_ptr[ip + 1];
+
+				text += "operator ";
+
+				text += DADDR(4);
+				text += " = ";
+				text += DADDR(2);
+				text += " ";
+				text += Variant::get_operator_name(Variant::Operator(operation));
+				text += " ";
+				text += DADDR(3);
+
+				incr += 5;
+			} break;
+			case OPCODE_EXTENDS_TEST: {
+				text += "is object ";
+				text += DADDR(3);
+				text += " = ";
+				text += DADDR(1);
+				text += " is ";
+				text += DADDR(2);
+
+				incr += 4;
+			} break;
+			case OPCODE_IS_BUILTIN: {
+				text += "is builtin ";
+				text += DADDR(3);
+				text += " = ";
+				text += DADDR(1);
+				text += " is ";
+				text += Variant::get_type_name(Variant::Type(_code_ptr[ip + 2]));
+
+				incr += 4;
+			} break;
+			case OPCODE_SET: {
+				text += "set ";
+				text += DADDR(1);
+				text += "[";
+				text += DADDR(2);
+				text += "] = ";
+				text += DADDR(3);
+
+				incr += 4;
+			} break;
+			case OPCODE_GET: {
+				text += "get ";
+				text += DADDR(3);
+				text += " = ";
+				text += DADDR(1);
+				text += "[";
+				text += DADDR(2);
+				text += "]";
+
+				incr += 4;
+			} break;
+			case OPCODE_SET_NAMED: {
+				text += "set_named ";
+				text += DADDR(1);
+				text += "[\"";
+				text += _global_names_ptr[_code_ptr[ip + 2]];
+				text += "\"] = ";
+				text += DADDR(3);
+
+				incr += 4;
+			} break;
+			case OPCODE_GET_NAMED: {
+				text += "get_named ";
+				text += DADDR(3);
+				text += " = ";
+				text += DADDR(1);
+				text += "[\"";
+				text += _global_names_ptr[_code_ptr[ip + 2]];
+				text += "\"]";
+
+				incr += 4;
+			} break;
+			case OPCODE_SET_MEMBER: {
+				text += "set_member ";
+				text += "[\"";
+				text += _global_names_ptr[_code_ptr[ip + 1]];
+				text += "\"] = ";
+				text += DADDR(2);
+
+				incr += 3;
+			} break;
+			case OPCODE_GET_MEMBER: {
+				text += "get_member ";
+				text += DADDR(2);
+				text += " = ";
+				text += "[\"";
+				text += _global_names_ptr[_code_ptr[ip + 1]];
+				text += "\"]";
+
+				incr += 3;
+			} break;
+			case OPCODE_ASSIGN: {
+				text += "assign ";
+				text += DADDR(1);
+				text += " = ";
+				text += DADDR(2);
+
+				incr += 3;
+			} break;
+			case OPCODE_ASSIGN_TRUE: {
+				text += "assign ";
+				text += DADDR(1);
+				text += " = true";
+
+				incr += 2;
+			} break;
+			case OPCODE_ASSIGN_FALSE: {
+				text += "assign ";
+				text += DADDR(1);
+				text += " = false";
+
+				incr += 2;
+			} break;
+			case OPCODE_ASSIGN_TYPED_BUILTIN: {
+				text += "assign typed builtin (";
+				text += Variant::get_type_name((Variant::Type)_code_ptr[ip + 1]);
+				text += ") ";
+				text += DADDR(2);
+				text += " = ";
+				text += DADDR(3);
+
+				incr += 4;
+			} break;
+			case OPCODE_ASSIGN_TYPED_NATIVE: {
+				Variant class_name = _constants_ptr[_code_ptr[ip + 1]];
+				GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(class_name.operator Object *());
+
+				text += "assign typed native (";
+				text += nc->get_name().operator String();
+				text += ") ";
+				text += DADDR(2);
+				text += " = ";
+				text += DADDR(3);
+
+				incr += 4;
+			} break;
+			case OPCODE_ASSIGN_TYPED_SCRIPT: {
+				Variant script = _constants_ptr[_code_ptr[ip + 1]];
+				Script *sc = Object::cast_to<Script>(script.operator Object *());
+
+				text += "assign typed script (";
+				text += sc->get_path();
+				text += ") ";
+				text += DADDR(2);
+				text += " = ";
+				text += DADDR(3);
+
+				incr += 4;
+			} break;
+			case OPCODE_CAST_TO_BUILTIN: {
+				text += "cast builtin ";
+				text += DADDR(3);
+				text += " = ";
+				text += DADDR(2);
+				text += " as ";
+				text += Variant::get_type_name(Variant::Type(_code_ptr[ip + 1]));
+
+				incr += 4;
+			} break;
+			case OPCODE_CAST_TO_NATIVE: {
+				Variant class_name = _constants_ptr[_code_ptr[ip + 1]];
+				GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(class_name.operator Object *());
+
+				text += "cast native ";
+				text += DADDR(3);
+				text += " = ";
+				text += DADDR(2);
+				text += " as ";
+				text += nc->get_name();
+
+				incr += 4;
+			} break;
+			case OPCODE_CAST_TO_SCRIPT: {
+				text += "cast ";
+				text += DADDR(3);
+				text += " = ";
+				text += DADDR(2);
+				text += " as ";
+				text += DADDR(1);
+
+				incr += 4;
+			} break;
+			case OPCODE_CONSTRUCT: {
+				Variant::Type t = Variant::Type(_code_ptr[ip + 1]);
+				int argc = _code_ptr[ip + 2];
+
+				text += "construct ";
+				text += DADDR(3 + argc);
+				text += " = ";
+
+				text += Variant::get_type_name(t) + "(";
+				for (int i = 0; i < argc; i++) {
+					if (i > 0)
+						text += ", ";
+					text += DADDR(i + 3);
+				}
+				text += ")";
+
+				incr = 4 + argc;
+			} break;
+			case OPCODE_CONSTRUCT_ARRAY: {
+				int argc = _code_ptr[ip + 1];
+				text += " make_array ";
+				text += DADDR(2 + argc);
+				text += " = [";
+
+				for (int i = 0; i < argc; i++) {
+					if (i > 0)
+						text += ", ";
+					text += DADDR(2 + i);
+				}
+
+				text += "]";
+
+				incr += 3 + argc;
+			} break;
+			case OPCODE_CONSTRUCT_DICTIONARY: {
+				int argc = _code_ptr[ip + 1];
+				text += "make_dict ";
+				text += DADDR(2 + argc * 2);
+				text += " = {";
+
+				for (int i = 0; i < argc; i++) {
+					if (i > 0)
+						text += ", ";
+					text += DADDR(2 + i * 2 + 0);
+					text += ": ";
+					text += DADDR(2 + i * 2 + 1);
+				}
+
+				text += "}";
+
+				incr += 3 + argc * 2;
+			} break;
+			case OPCODE_CALL:
+			case OPCODE_CALL_RETURN:
+			case OPCODE_CALL_ASYNC: {
+				bool ret = _code_ptr[ip] == OPCODE_CALL_RETURN;
+				bool async = _code_ptr[ip] == OPCODE_CALL_ASYNC;
+
+				if (ret) {
+					text += "call-ret ";
+				} else if (async) {
+					text += "call-async ";
+				} else {
+					text += "call ";
+				}
+
+				int argc = _code_ptr[ip + 1];
+				if (ret || async) {
+					text += DADDR(4 + argc) + " = ";
+				}
+
+				text += DADDR(2) + ".";
+				text += String(_global_names_ptr[_code_ptr[ip + 3]]);
+				text += "(";
+
+				for (int i = 0; i < argc; i++) {
+					if (i > 0)
+						text += ", ";
+					text += DADDR(4 + i);
+				}
+				text += ")";
+
+				incr = 5 + argc;
+			} break;
+			case OPCODE_CALL_BUILT_IN: {
+				text += "call-built-in ";
+
+				int argc = _code_ptr[ip + 2];
+				text += DADDR(3 + argc) + " = ";
+
+				text += GDScriptFunctions::get_func_name(GDScriptFunctions::Function(_code_ptr[ip + 1]));
+				text += "(";
+
+				for (int i = 0; i < argc; i++) {
+					if (i > 0)
+						text += ", ";
+					text += DADDR(3 + i);
+				}
+				text += ")";
+
+				incr = 4 + argc;
+			} break;
+			case OPCODE_CALL_SELF_BASE: {
+				text += "call-self-base ";
+
+				int argc = _code_ptr[ip + 2];
+				text += DADDR(3 + argc) + " = ";
+
+				text += _global_names_ptr[_code_ptr[ip + 1]];
+				text += "(";
+
+				for (int i = 0; i < argc; i++) {
+					if (i > 0)
+						text += ", ";
+					text += DADDR(3 + i);
+				}
+				text += ")";
+
+				incr = 4 + argc;
+			} break;
+			case OPCODE_AWAIT: {
+				text += "await ";
+				text += DADDR(1);
+
+				incr += 2;
+			} break;
+			case OPCODE_AWAIT_RESUME: {
+				text += "await resume ";
+				text += DADDR(1);
+
+				incr = 2;
+			} break;
+			case OPCODE_JUMP: {
+				text += "jump ";
+				text += itos(_code_ptr[ip + 1]);
+
+				incr = 2;
+			} break;
+			case OPCODE_JUMP_IF: {
+				text += "jump-if ";
+				text += DADDR(1);
+				text += " to ";
+				text += itos(_code_ptr[ip + 2]);
+
+				incr = 3;
+			} break;
+			case OPCODE_JUMP_IF_NOT: {
+				text += "jump-if-not ";
+				text += DADDR(1);
+				text += " to ";
+				text += itos(_code_ptr[ip + 2]);
+
+				incr = 3;
+			} break;
+			case OPCODE_JUMP_TO_DEF_ARGUMENT: {
+				text += "jump-to-default-argument ";
+
+				incr = 1;
+			} break;
+			case OPCODE_RETURN: {
+				text += "return ";
+				text += DADDR(1);
+
+				incr = 2;
+			} break;
+			case OPCODE_ITERATE_BEGIN: {
+				text += "for-init ";
+				text += DADDR(4);
+				text += " in ";
+				text += DADDR(2);
+				text += " counter ";
+				text += DADDR(1);
+				text += " end ";
+				text += itos(_code_ptr[ip + 3]);
+
+				incr += 5;
+			} break;
+			case OPCODE_ITERATE: {
+				text += "for-loop ";
+				text += DADDR(4);
+				text += " in ";
+				text += DADDR(2);
+				text += " counter ";
+				text += DADDR(1);
+				text += " end ";
+				text += itos(_code_ptr[ip + 3]);
+
+				incr += 5;
+			} break;
+			case OPCODE_LINE: {
+				int line = _code_ptr[ip + 1] - 1;
+				if (line >= 0 && line < p_code_lines.size()) {
+					text += "line ";
+					text += itos(line + 1);
+					text += ": ";
+					text += p_code_lines[line];
+				} else {
+					text += "";
+				}
+
+				incr += 2;
+			} break;
+			case OPCODE_ASSERT: {
+				text += "assert (";
+				text += DADDR(1);
+				text += ", ";
+				text += DADDR(2);
+				text += ")";
+
+				incr += 3;
+			} break;
+			case OPCODE_BREAKPOINT: {
+				text += "breakpoint";
+
+				incr += 1;
+			} break;
+			case OPCODE_END: {
+				text += "== END ==";
+
+				incr += 1;
+			} break;
+		}
+
+		ip += incr;
+		if (text.get_string_length() > 0) {
+			print_line(text.as_string());
+		}
+	}
+}
+
+#endif

文件差異過大導致無法顯示
+ 0 - 1567
modules/gdscript/gdscript_function.cpp


+ 1596 - 0
modules/gdscript/gdscript_vm.cpp

@@ -0,0 +1,1596 @@
+/*************************************************************************/
+/*  gdscript_vm.cpp                                                      */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#include "gdscript_function.h"
+
+#include "core/os/os.h"
+#include "gdscript.h"
+#include "gdscript_functions.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 {
+	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: {
+#ifdef DEBUG_ENABLED
+			if (unlikely(!p_instance)) {
+				r_error = "Cannot access self without instance.";
+				return nullptr;
+			}
+#endif
+			return &self;
+		} break;
+		case ADDR_TYPE_CLASS: {
+			return &static_ref;
+		} break;
+		case ADDR_TYPE_MEMBER: {
+#ifdef DEBUG_ENABLED
+			if (unlikely(!p_instance)) {
+				r_error = "Cannot access member without instance.";
+				return nullptr;
+			}
+#endif
+			//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).");
+	return nullptr;
+}
+
+#ifdef DEBUG_ENABLED
+static String _get_var_type(const Variant *p_var) {
+	String basestr;
+
+	if (p_var->get_type() == Variant::OBJECT) {
+		bool was_freed;
+		Object *bobj = p_var->get_validated_object_with_check(was_freed);
+		if (!bobj) {
+			if (was_freed) {
+				basestr = "null instance";
+			} else {
+				basestr = "previously freed";
+			}
+		} else {
+			if (bobj->get_script_instance()) {
+				basestr = bobj->get_class() + " (" + bobj->get_script_instance()->get_script()->get_path().get_file() + ")";
+			} else {
+				basestr = bobj->get_class();
+			}
+		}
+
+	} else {
+		basestr = Variant::get_type_name(p_var->get_type());
+	}
+
+	return basestr;
+}
+#endif // DEBUG_ENABLED
+
+String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const String &p_where, const Variant **argptrs) const {
+	String err_text;
+
+	if (p_err.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
+		int errorarg = p_err.argument;
+		// Handle the Object to Object case separately as we don't have further class details.
+#ifdef DEBUG_ENABLED
+		if (p_err.expected == Variant::OBJECT && argptrs[errorarg]->get_type() == p_err.expected) {
+			err_text = "Invalid type in " + p_where + ". The Object-derived class of argument " + itos(errorarg + 1) + " (" + _get_var_type(argptrs[errorarg]) + ") is not a subclass of the expected argument class.";
+		} else
+#endif // DEBUG_ENABLED
+		{
+			err_text = "Invalid type in " + p_where + ". Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(Variant::Type(p_err.expected)) + ".";
+		}
+	} else if (p_err.error == Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) {
+		err_text = "Invalid call to " + p_where + ". Expected " + itos(p_err.argument) + " arguments.";
+	} else if (p_err.error == Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
+		err_text = "Invalid call to " + p_where + ". Expected " + itos(p_err.argument) + " arguments.";
+	} else if (p_err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
+		err_text = "Invalid call. Nonexistent " + p_where + ".";
+	} else if (p_err.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
+		err_text = "Attempt to call " + p_where + " on a null instance.";
+	} else {
+		err_text = "Bug, call error: #" + itos(p_err.error);
+	}
+
+	return err_text;
+}
+
+#if defined(__GNUC__)
+#define OPCODES_TABLE                         \
+	static const void *switch_table_ops[] = { \
+		&&OPCODE_OPERATOR,                    \
+		&&OPCODE_EXTENDS_TEST,                \
+		&&OPCODE_IS_BUILTIN,                  \
+		&&OPCODE_SET,                         \
+		&&OPCODE_GET,                         \
+		&&OPCODE_SET_NAMED,                   \
+		&&OPCODE_GET_NAMED,                   \
+		&&OPCODE_SET_MEMBER,                  \
+		&&OPCODE_GET_MEMBER,                  \
+		&&OPCODE_ASSIGN,                      \
+		&&OPCODE_ASSIGN_TRUE,                 \
+		&&OPCODE_ASSIGN_FALSE,                \
+		&&OPCODE_ASSIGN_TYPED_BUILTIN,        \
+		&&OPCODE_ASSIGN_TYPED_NATIVE,         \
+		&&OPCODE_ASSIGN_TYPED_SCRIPT,         \
+		&&OPCODE_CAST_TO_BUILTIN,             \
+		&&OPCODE_CAST_TO_NATIVE,              \
+		&&OPCODE_CAST_TO_SCRIPT,              \
+		&&OPCODE_CONSTRUCT,                   \
+		&&OPCODE_CONSTRUCT_ARRAY,             \
+		&&OPCODE_CONSTRUCT_DICTIONARY,        \
+		&&OPCODE_CALL,                        \
+		&&OPCODE_CALL_RETURN,                 \
+		&&OPCODE_CALL_ASYNC,                  \
+		&&OPCODE_CALL_BUILT_IN,               \
+		&&OPCODE_CALL_SELF_BASE,              \
+		&&OPCODE_AWAIT,                       \
+		&&OPCODE_AWAIT_RESUME,                \
+		&&OPCODE_JUMP,                        \
+		&&OPCODE_JUMP_IF,                     \
+		&&OPCODE_JUMP_IF_NOT,                 \
+		&&OPCODE_JUMP_TO_DEF_ARGUMENT,        \
+		&&OPCODE_RETURN,                      \
+		&&OPCODE_ITERATE_BEGIN,               \
+		&&OPCODE_ITERATE,                     \
+		&&OPCODE_ASSERT,                      \
+		&&OPCODE_BREAKPOINT,                  \
+		&&OPCODE_LINE,                        \
+		&&OPCODE_END                          \
+	};                                        \
+	static_assert((sizeof(switch_table_ops) / sizeof(switch_table_ops[0]) == (OPCODE_END + 1)), "Opcodes in jump table aren't the same as opcodes in enum.");
+
+#define OPCODE(m_op) \
+	m_op:
+#define OPCODE_WHILE(m_test)
+#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 OPCODE_BREAK goto OPSEXIT
+#define OPCODE_OUT goto OPSOUT
+#else
+#define OPCODES_TABLE
+#define OPCODE(m_op) case m_op:
+#define OPCODE_WHILE(m_test) while (m_test)
+#define OPCODES_END
+#define OPCODES_OUT
+#define DISPATCH_OPCODE continue
+#define OPCODE_SWITCH(m_test) switch (m_test)
+#define OPCODE_BREAK break
+#define OPCODE_OUT break
+#endif
+
+Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_args, int p_argcount, Callable::CallError &r_err, CallState *p_state) {
+	OPCODES_TABLE;
+
+	if (!_code_ptr) {
+		return Variant();
+	}
+
+	r_err.error = Callable::CallError::CALL_OK;
+
+	Variant self;
+	Variant static_ref;
+	Variant retvalue;
+	Variant *stack = nullptr;
+	Variant **call_args;
+	int defarg = 0;
+
+#ifdef DEBUG_ENABLED
+
+	//GDScriptLanguage::get_singleton()->calls++;
+
+#endif
+
+	uint32_t alloca_size = 0;
+	GDScript *script;
+	int ip = 0;
+	int line = _initial_line;
+
+	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
+		line = p_state->line;
+		ip = p_state->ip;
+		alloca_size = p_state->stack.size();
+		script = p_state->script;
+		p_instance = p_state->instance;
+		defarg = p_state->defarg;
+		self = p_state->self;
+
+	} else {
+		if (p_argcount != _argument_count) {
+			if (p_argcount > _argument_count) {
+				r_err.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+				r_err.argument = _argument_count;
+
+				return Variant();
+			} else if (p_argcount < _argument_count - _default_arg_count) {
+				r_err.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+				r_err.argument = _argument_count - _default_arg_count;
+				return Variant();
+			} else {
+				defarg = _argument_count - p_argcount;
+			}
+		}
+
+		alloca_size = sizeof(Variant *) * _call_size + sizeof(Variant) * _stack_size;
+
+		if (alloca_size) {
+			uint8_t *aptr = (uint8_t *)alloca(alloca_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;
+					}
+
+					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;
+			}
+
+			if (_call_size) {
+				call_args = (Variant **)&aptr[sizeof(Variant) * _stack_size];
+			} else {
+				call_args = nullptr;
+			}
+
+		} else {
+			stack = nullptr;
+			call_args = nullptr;
+		}
+
+		if (p_instance) {
+			if (p_instance->base_ref && static_cast<Reference *>(p_instance->owner)->is_referenced()) {
+				self = REF(static_cast<Reference *>(p_instance->owner));
+			} else {
+				self = p_instance->owner;
+			}
+			script = p_instance->script.ptr();
+		} else {
+			script = _script;
+		}
+	}
+
+	static_ref = script;
+
+	String err_text;
+
+#ifdef DEBUG_ENABLED
+
+	if (EngineDebugger::is_active()) {
+		GDScriptLanguage::get_singleton()->enter_function(p_instance, this, stack, &ip, &line);
+	}
+
+#define GD_ERR_BREAK(m_cond)                                                                                           \
+	{                                                                                                                  \
+		if (unlikely(m_cond)) {                                                                                        \
+			_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. Breaking..:"); \
+			OPCODE_BREAK;                                                                                              \
+		}                                                                                                              \
+	}
+
+#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))                                                                                    \
+		OPCODE_BREAK;
+
+#else
+#define GD_ERR_BREAK(m_cond)
+#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);
+
+#endif
+
+#ifdef DEBUG_ENABLED
+
+	uint64_t function_start_time = 0;
+	uint64_t function_call_time = 0;
+
+	if (GDScriptLanguage::get_singleton()->profiling) {
+		function_start_time = OS::get_singleton()->get_ticks_usec();
+		function_call_time = 0;
+		profile.call_count++;
+		profile.frame_call_count++;
+	}
+	bool exit_ok = false;
+	bool awaited = false;
+#endif
+
+#ifdef DEBUG_ENABLED
+	OPCODE_WHILE(ip < _code_size) {
+		int last_opcode = _code_ptr[ip];
+#else
+	OPCODE_WHILE(true) {
+#endif
+
+		OPCODE_SWITCH(_code_ptr[ip]) {
+			OPCODE(OPCODE_OPERATOR) {
+				CHECK_SPACE(5);
+
+				bool valid;
+				Variant::Operator op = (Variant::Operator)_code_ptr[ip + 1];
+				GD_ERR_BREAK(op >= Variant::OP_MAX);
+
+				GET_VARIANT_PTR(a, 2);
+				GET_VARIANT_PTR(b, 3);
+				GET_VARIANT_PTR(dst, 4);
+
+#ifdef DEBUG_ENABLED
+
+				Variant ret;
+				Variant::evaluate(op, *a, *b, ret, valid);
+#else
+				Variant::evaluate(op, *a, *b, *dst, valid);
+#endif
+#ifdef DEBUG_ENABLED
+				if (!valid) {
+					if (ret.get_type() == Variant::STRING) {
+						//return a string when invalid with the error
+						err_text = ret;
+						err_text += " in operator '" + Variant::get_operator_name(op) + "'.";
+					} else {
+						err_text = "Invalid operands '" + Variant::get_type_name(a->get_type()) + "' and '" + Variant::get_type_name(b->get_type()) + "' in operator '" + Variant::get_operator_name(op) + "'.";
+					}
+					OPCODE_BREAK;
+				}
+				*dst = ret;
+#endif
+				ip += 5;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_EXTENDS_TEST) {
+				CHECK_SPACE(4);
+
+				GET_VARIANT_PTR(a, 1);
+				GET_VARIANT_PTR(b, 2);
+				GET_VARIANT_PTR(dst, 3);
+
+#ifdef DEBUG_ENABLED
+				if (b->get_type() != Variant::OBJECT || b->operator Object *() == nullptr) {
+					err_text = "Right operand of 'is' is not a class.";
+					OPCODE_BREAK;
+				}
+#endif
+
+				bool extends_ok = false;
+				if (a->get_type() == Variant::OBJECT && a->operator Object *() != nullptr) {
+#ifdef DEBUG_ENABLED
+					bool was_freed;
+					Object *obj_A = a->get_validated_object_with_check(was_freed);
+
+					if (was_freed) {
+						err_text = "Left operand of 'is' is a previously freed instance.";
+						OPCODE_BREAK;
+					}
+
+					Object *obj_B = b->get_validated_object_with_check(was_freed);
+
+					if (was_freed) {
+						err_text = "Right operand of 'is' is a previously freed instance.";
+						OPCODE_BREAK;
+					}
+#else
+
+					Object *obj_A = *a;
+					Object *obj_B = *b;
+#endif // DEBUG_ENABLED
+
+					GDScript *scr_B = Object::cast_to<GDScript>(obj_B);
+
+					if (scr_B) {
+						//if B is a script, the only valid condition is that A has an instance which inherits from the script
+						//in other situation, this shoul return false.
+
+						if (obj_A->get_script_instance() && obj_A->get_script_instance()->get_language() == GDScriptLanguage::get_singleton()) {
+							GDScript *cmp = static_cast<GDScript *>(obj_A->get_script_instance()->get_script().ptr());
+							//bool found=false;
+							while (cmp) {
+								if (cmp == scr_B) {
+									//inherits from script, all ok
+									extends_ok = true;
+									break;
+								}
+
+								cmp = cmp->_base;
+							}
+						}
+
+					} else {
+						GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(obj_B);
+
+#ifdef DEBUG_ENABLED
+						if (!nc) {
+							err_text = "Right operand of 'is' is not a class (type: '" + obj_B->get_class() + "').";
+							OPCODE_BREAK;
+						}
+#endif
+						extends_ok = ClassDB::is_parent_class(obj_A->get_class_name(), nc->get_name());
+					}
+				}
+
+				*dst = extends_ok;
+				ip += 4;
+			}
+			DISPATCH_OPCODE;
+
+			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);
+
+				GD_ERR_BREAK(var_type < 0 || var_type >= Variant::VARIANT_MAX);
+
+				*dst = value->get_type() == var_type;
+				ip += 4;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_SET) {
+				CHECK_SPACE(3);
+
+				GET_VARIANT_PTR(dst, 1);
+				GET_VARIANT_PTR(index, 2);
+				GET_VARIANT_PTR(value, 3);
+
+				bool valid;
+				dst->set(*index, *value, &valid);
+
+#ifdef DEBUG_ENABLED
+				if (!valid) {
+					String v = index->operator String();
+					if (v != "") {
+						v = "'" + v + "'";
+					} else {
+						v = "of type '" + _get_var_type(index) + "'";
+					}
+					err_text = "Invalid set index " + v + " (on base: '" + _get_var_type(dst) + "') with value of type '" + _get_var_type(value) + "'";
+					OPCODE_BREAK;
+				}
+#endif
+				ip += 4;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_GET) {
+				CHECK_SPACE(3);
+
+				GET_VARIANT_PTR(src, 1);
+				GET_VARIANT_PTR(index, 2);
+				GET_VARIANT_PTR(dst, 3);
+
+				bool valid;
+#ifdef DEBUG_ENABLED
+				//allow better error message in cases where src and dst are the same stack position
+				Variant ret = src->get(*index, &valid);
+#else
+				*dst = src->get(*index, &valid);
+
+#endif
+#ifdef DEBUG_ENABLED
+				if (!valid) {
+					String v = index->operator String();
+					if (v != "") {
+						v = "'" + v + "'";
+					} else {
+						v = "of type '" + _get_var_type(index) + "'";
+					}
+					err_text = "Invalid get index " + v + " (on base: '" + _get_var_type(src) + "').";
+					OPCODE_BREAK;
+				}
+				*dst = ret;
+#endif
+				ip += 4;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_SET_NAMED) {
+				CHECK_SPACE(3);
+
+				GET_VARIANT_PTR(dst, 1);
+				GET_VARIANT_PTR(value, 3);
+
+				int indexname = _code_ptr[ip + 2];
+
+				GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count);
+				const StringName *index = &_global_names_ptr[indexname];
+
+				bool valid;
+				dst->set_named(*index, *value, valid);
+
+#ifdef DEBUG_ENABLED
+				if (!valid) {
+					String err_type;
+					err_text = "Invalid set index '" + String(*index) + "' (on base: '" + _get_var_type(dst) + "') with value of type '" + _get_var_type(value) + "'.";
+					OPCODE_BREAK;
+				}
+#endif
+				ip += 4;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_GET_NAMED) {
+				CHECK_SPACE(4);
+
+				GET_VARIANT_PTR(src, 1);
+				GET_VARIANT_PTR(dst, 3);
+
+				int indexname = _code_ptr[ip + 2];
+
+				GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count);
+				const StringName *index = &_global_names_ptr[indexname];
+
+				bool valid;
+#ifdef DEBUG_ENABLED
+				//allow better error message in cases where src and dst are the same stack position
+				Variant ret = src->get_named(*index, valid);
+
+#else
+				*dst = src->get_named(*index, valid);
+#endif
+#ifdef DEBUG_ENABLED
+				if (!valid) {
+					if (src->has_method(*index)) {
+						err_text = "Invalid get index '" + index->operator String() + "' (on base: '" + _get_var_type(src) + "'). Did you mean '." + index->operator String() + "()' or funcref(obj, \"" + index->operator String() + "\") ?";
+					} else {
+						err_text = "Invalid get index '" + index->operator String() + "' (on base: '" + _get_var_type(src) + "').";
+					}
+					OPCODE_BREAK;
+				}
+				*dst = ret;
+#endif
+				ip += 4;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_SET_MEMBER) {
+				CHECK_SPACE(3);
+				int indexname = _code_ptr[ip + 1];
+				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
+				ClassDB::set_property(p_instance->owner, *index, *src, &valid);
+#else
+				bool ok = ClassDB::set_property(p_instance->owner, *index, *src, &valid);
+				if (!ok) {
+					err_text = "Internal error setting property: " + String(*index);
+					OPCODE_BREAK;
+				} else if (!valid) {
+					err_text = "Error setting property '" + String(*index) + "' with value of type " + Variant::get_type_name(src->get_type()) + ".";
+					OPCODE_BREAK;
+				}
+#endif
+				ip += 3;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_GET_MEMBER) {
+				CHECK_SPACE(3);
+				int indexname = _code_ptr[ip + 1];
+				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
+				bool ok = ClassDB::get_property(p_instance->owner, *index, *dst);
+				if (!ok) {
+					err_text = "Internal error getting property: " + String(*index);
+					OPCODE_BREAK;
+				}
+#endif
+				ip += 3;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_ASSIGN) {
+				CHECK_SPACE(3);
+				GET_VARIANT_PTR(dst, 1);
+				GET_VARIANT_PTR(src, 2);
+
+				*dst = *src;
+
+				ip += 3;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_ASSIGN_TRUE) {
+				CHECK_SPACE(2);
+				GET_VARIANT_PTR(dst, 1);
+
+				*dst = true;
+
+				ip += 2;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_ASSIGN_FALSE) {
+				CHECK_SPACE(2);
+				GET_VARIANT_PTR(dst, 1);
+
+				*dst = false;
+
+				ip += 2;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_ASSIGN_TYPED_BUILTIN) {
+				CHECK_SPACE(4);
+				GET_VARIANT_PTR(dst, 2);
+				GET_VARIANT_PTR(src, 3);
+
+				Variant::Type var_type = (Variant::Type)_code_ptr[ip + 1];
+				GD_ERR_BREAK(var_type < 0 || var_type >= Variant::VARIANT_MAX);
+
+				if (src->get_type() != var_type) {
+#ifdef DEBUG_ENABLED
+					if (Variant::can_convert_strict(src->get_type(), var_type)) {
+#endif // DEBUG_ENABLED
+						Callable::CallError ce;
+						Variant::construct(var_type, *dst, const_cast<const Variant **>(&src), 1, ce);
+					} else {
+#ifdef DEBUG_ENABLED
+						err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) +
+								   "' to a variable of type '" + Variant::get_type_name(var_type) + "'.";
+						OPCODE_BREAK;
+					}
+				} else {
+#endif // DEBUG_ENABLED
+					*dst = *src;
+				}
+
+				ip += 4;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_ASSIGN_TYPED_NATIVE) {
+				CHECK_SPACE(4);
+				GET_VARIANT_PTR(dst, 2);
+				GET_VARIANT_PTR(src, 3);
+
+#ifdef DEBUG_ENABLED
+				GET_VARIANT_PTR(type, 1);
+				GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(type->operator Object *());
+				GD_ERR_BREAK(!nc);
+				if (src->get_type() != Variant::OBJECT && src->get_type() != Variant::NIL) {
+					err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) +
+							   "' to a variable of type '" + nc->get_name() + "'.";
+					OPCODE_BREAK;
+				}
+				Object *src_obj = src->operator Object *();
+
+				if (src_obj && !ClassDB::is_parent_class(src_obj->get_class_name(), nc->get_name())) {
+					err_text = "Trying to assign value of type '" + src_obj->get_class_name() +
+							   "' to a variable of type '" + nc->get_name() + "'.";
+					OPCODE_BREAK;
+				}
+#endif // DEBUG_ENABLED
+				*dst = *src;
+
+				ip += 4;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_ASSIGN_TYPED_SCRIPT) {
+				CHECK_SPACE(4);
+				GET_VARIANT_PTR(dst, 2);
+				GET_VARIANT_PTR(src, 3);
+
+#ifdef DEBUG_ENABLED
+				GET_VARIANT_PTR(type, 1);
+				Script *base_type = Object::cast_to<Script>(type->operator Object *());
+
+				GD_ERR_BREAK(!base_type);
+
+				if (src->get_type() != Variant::OBJECT && src->get_type() != Variant::NIL) {
+					err_text = "Trying to assign a non-object value to a variable of type '" + base_type->get_path().get_file() + "'.";
+					OPCODE_BREAK;
+				}
+
+				if (src->get_type() != Variant::NIL && src->operator Object *() != nullptr) {
+					ScriptInstance *scr_inst = src->operator Object *()->get_script_instance();
+					if (!scr_inst) {
+						err_text = "Trying to assign value of type '" + src->operator Object *()->get_class_name() +
+								   "' to a variable of type '" + base_type->get_path().get_file() + "'.";
+						OPCODE_BREAK;
+					}
+
+					Script *src_type = src->operator Object *()->get_script_instance()->get_script().ptr();
+					bool valid = false;
+
+					while (src_type) {
+						if (src_type == base_type) {
+							valid = true;
+							break;
+						}
+						src_type = src_type->get_base_script().ptr();
+					}
+
+					if (!valid) {
+						err_text = "Trying to assign value of type '" + src->operator Object *()->get_script_instance()->get_script()->get_path().get_file() +
+								   "' to a variable of type '" + base_type->get_path().get_file() + "'.";
+						OPCODE_BREAK;
+					}
+				}
+#endif // DEBUG_ENABLED
+
+				*dst = *src;
+
+				ip += 4;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_CAST_TO_BUILTIN) {
+				CHECK_SPACE(4);
+				Variant::Type to_type = (Variant::Type)_code_ptr[ip + 1];
+				GET_VARIANT_PTR(src, 2);
+				GET_VARIANT_PTR(dst, 3);
+
+				GD_ERR_BREAK(to_type < 0 || to_type >= Variant::VARIANT_MAX);
+
+				Callable::CallError err;
+				Variant::construct(to_type, *dst, (const Variant **)&src, 1, err);
+
+#ifdef DEBUG_ENABLED
+				if (err.error != Callable::CallError::CALL_OK) {
+					err_text = "Invalid cast: could not convert value to '" + Variant::get_type_name(to_type) + "'.";
+					OPCODE_BREAK;
+				}
+#endif
+
+				ip += 4;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_CAST_TO_NATIVE) {
+				CHECK_SPACE(4);
+				GET_VARIANT_PTR(to_type, 1);
+				GET_VARIANT_PTR(src, 2);
+				GET_VARIANT_PTR(dst, 3);
+
+				GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(to_type->operator Object *());
+				GD_ERR_BREAK(!nc);
+
+#ifdef DEBUG_ENABLED
+				if (src->get_type() != Variant::OBJECT && src->get_type() != Variant::NIL) {
+					err_text = "Invalid cast: can't convert a non-object value to an object type.";
+					OPCODE_BREAK;
+				}
+#endif
+				Object *src_obj = src->operator Object *();
+
+				if (src_obj && !ClassDB::is_parent_class(src_obj->get_class_name(), nc->get_name())) {
+					*dst = Variant(); // invalid cast, assign NULL
+				} else {
+					*dst = *src;
+				}
+
+				ip += 4;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_CAST_TO_SCRIPT) {
+				CHECK_SPACE(4);
+				GET_VARIANT_PTR(to_type, 1);
+				GET_VARIANT_PTR(src, 2);
+				GET_VARIANT_PTR(dst, 3);
+
+				Script *base_type = Object::cast_to<Script>(to_type->operator Object *());
+
+				GD_ERR_BREAK(!base_type);
+
+#ifdef DEBUG_ENABLED
+				if (src->get_type() != Variant::OBJECT && src->get_type() != Variant::NIL) {
+					err_text = "Trying to assign a non-object value to a variable of type '" + base_type->get_path().get_file() + "'.";
+					OPCODE_BREAK;
+				}
+#endif
+
+				bool valid = false;
+
+				if (src->get_type() != Variant::NIL && src->operator Object *() != nullptr) {
+					ScriptInstance *scr_inst = src->operator Object *()->get_script_instance();
+
+					if (scr_inst) {
+						Script *src_type = src->operator Object *()->get_script_instance()->get_script().ptr();
+
+						while (src_type) {
+							if (src_type == base_type) {
+								valid = true;
+								break;
+							}
+							src_type = src_type->get_base_script().ptr();
+						}
+					}
+				}
+
+				if (valid) {
+					*dst = *src; // Valid cast, copy the source object
+				} else {
+					*dst = Variant(); // invalid cast, assign NULL
+				}
+
+				ip += 4;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_CONSTRUCT) {
+				CHECK_SPACE(2);
+				Variant::Type t = Variant::Type(_code_ptr[ip + 1]);
+				int argc = _code_ptr[ip + 2];
+				CHECK_SPACE(argc + 2);
+				Variant **argptrs = call_args;
+				for (int i = 0; i < argc; i++) {
+					GET_VARIANT_PTR(v, 3 + i);
+					argptrs[i] = v;
+				}
+
+				GET_VARIANT_PTR(dst, 3 + argc);
+				Callable::CallError err;
+				Variant::construct(t, *dst, (const Variant **)argptrs, argc, err);
+
+#ifdef DEBUG_ENABLED
+				if (err.error != Callable::CallError::CALL_OK) {
+					err_text = _get_call_error(err, "'" + Variant::get_type_name(t) + "' constructor", (const Variant **)argptrs);
+					OPCODE_BREAK;
+				}
+#endif
+
+				ip += 4 + argc;
+				//construct a basic type
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_CONSTRUCT_ARRAY) {
+				CHECK_SPACE(1);
+				int argc = _code_ptr[ip + 1];
+				Array array; //arrays are always shared
+				array.resize(argc);
+				CHECK_SPACE(argc + 2);
+
+				for (int i = 0; i < argc; i++) {
+					GET_VARIANT_PTR(v, 2 + i);
+					array[i] = *v;
+				}
+
+				GET_VARIANT_PTR(dst, 2 + argc);
+
+				*dst = array;
+
+				ip += 3 + argc;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_CONSTRUCT_DICTIONARY) {
+				CHECK_SPACE(1);
+				int argc = _code_ptr[ip + 1];
+				Dictionary dict; //arrays are always shared
+
+				CHECK_SPACE(argc * 2 + 2);
+
+				for (int i = 0; i < argc; i++) {
+					GET_VARIANT_PTR(k, 2 + i * 2 + 0);
+					GET_VARIANT_PTR(v, 2 + i * 2 + 1);
+					dict[*k] = *v;
+				}
+
+				GET_VARIANT_PTR(dst, 2 + argc * 2);
+
+				*dst = dict;
+
+				ip += 3 + argc * 2;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_CALL_ASYNC)
+			OPCODE(OPCODE_CALL_RETURN)
+			OPCODE(OPCODE_CALL) {
+				CHECK_SPACE(4);
+				bool call_ret = _code_ptr[ip] != OPCODE_CALL;
+#ifdef DEBUG_ENABLED
+				bool call_async = _code_ptr[ip] == OPCODE_CALL_ASYNC;
+#endif
+
+				int argc = _code_ptr[ip + 1];
+				GET_VARIANT_PTR(base, 2);
+				int nameg = _code_ptr[ip + 3];
+
+				GD_ERR_BREAK(nameg < 0 || nameg >= _global_names_count);
+				const StringName *methodname = &_global_names_ptr[nameg];
+
+				GD_ERR_BREAK(argc < 0);
+				ip += 4;
+				CHECK_SPACE(argc + 1);
+				Variant **argptrs = call_args;
+
+				for (int i = 0; i < argc; i++) {
+					GET_VARIANT_PTR(v, i);
+					argptrs[i] = v;
+				}
+
+#ifdef DEBUG_ENABLED
+				uint64_t call_time = 0;
+
+				if (GDScriptLanguage::get_singleton()->profiling) {
+					call_time = OS::get_singleton()->get_ticks_usec();
+				}
+
+#endif
+				Callable::CallError err;
+				if (call_ret) {
+					GET_VARIANT_PTR(ret, argc);
+					base->call(*methodname, (const Variant **)argptrs, argc, *ret, err);
+#ifdef DEBUG_ENABLED
+					if (!call_async && ret->get_type() == Variant::OBJECT) {
+						// Check if getting a function state without await.
+						bool was_freed = false;
+						Object *obj = ret->get_validated_object_with_check(was_freed);
+
+						if (was_freed) {
+							err_text = "Got a freed object as a result of the call.";
+							OPCODE_BREAK;
+						}
+						if (obj && obj->is_class_ptr(GDScriptFunctionState::get_class_ptr_static())) {
+							err_text = R"(Trying to call an async function without "await".)";
+							OPCODE_BREAK;
+						}
+					}
+#endif
+				} else {
+					Variant ret;
+					base->call(*methodname, (const Variant **)argptrs, argc, ret, err);
+				}
+#ifdef DEBUG_ENABLED
+				if (GDScriptLanguage::get_singleton()->profiling) {
+					function_call_time += OS::get_singleton()->get_ticks_usec() - call_time;
+				}
+
+				if (err.error != Callable::CallError::CALL_OK) {
+					String methodstr = *methodname;
+					String basestr = _get_var_type(base);
+
+					if (methodstr == "call") {
+						if (argc >= 1) {
+							methodstr = String(*argptrs[0]) + " (via call)";
+							if (err.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
+								err.argument += 1;
+							}
+						}
+					} else if (methodstr == "free") {
+						if (err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
+							if (base->is_ref()) {
+								err_text = "Attempted to free a reference.";
+								OPCODE_BREAK;
+							} else if (base->get_type() == Variant::OBJECT) {
+								err_text = "Attempted to free a locked object (calling or emitting).";
+								OPCODE_BREAK;
+							}
+						}
+					} else if (methodstr == "call_recursive" && basestr == "TreeItem") {
+						if (argc >= 1) {
+							methodstr = String(*argptrs[0]) + " (via TreeItem.call_recursive)";
+							if (err.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
+								err.argument += 1;
+							}
+						}
+					}
+					err_text = _get_call_error(err, "function '" + methodstr + "' in base '" + basestr + "'", (const Variant **)argptrs);
+					OPCODE_BREAK;
+				}
+#endif
+
+				//_call_func(nullptr,base,*methodname,ip,argc,p_instance,stack);
+				ip += argc + 1;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_CALL_BUILT_IN) {
+				CHECK_SPACE(4);
+
+				GDScriptFunctions::Function func = GDScriptFunctions::Function(_code_ptr[ip + 1]);
+				int argc = _code_ptr[ip + 2];
+				GD_ERR_BREAK(argc < 0);
+
+				ip += 3;
+				CHECK_SPACE(argc + 1);
+				Variant **argptrs = call_args;
+
+				for (int i = 0; i < argc; i++) {
+					GET_VARIANT_PTR(v, i);
+					argptrs[i] = v;
+				}
+
+				GET_VARIANT_PTR(dst, argc);
+
+				Callable::CallError err;
+
+				GDScriptFunctions::call(func, (const Variant **)argptrs, argc, *dst, err);
+
+#ifdef DEBUG_ENABLED
+				if (err.error != Callable::CallError::CALL_OK) {
+					String methodstr = GDScriptFunctions::get_func_name(func);
+					if (dst->get_type() == Variant::STRING) {
+						//call provided error string
+						err_text = "Error calling built-in function '" + methodstr + "': " + String(*dst);
+					} else {
+						err_text = _get_call_error(err, "built-in function '" + methodstr + "'", (const Variant **)argptrs);
+					}
+					OPCODE_BREAK;
+				}
+#endif
+				ip += argc + 1;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_CALL_SELF_BASE) {
+				CHECK_SPACE(2);
+				int self_fun = _code_ptr[ip + 1];
+
+#ifdef DEBUG_ENABLED
+				if (self_fun < 0 || self_fun >= _global_names_count) {
+					err_text = "compiler bug, function name not found";
+					OPCODE_BREAK;
+				}
+#endif
+				const StringName *methodname = &_global_names_ptr[self_fun];
+
+				int argc = _code_ptr[ip + 2];
+
+				CHECK_SPACE(2 + argc + 1);
+
+				Variant **argptrs = call_args;
+
+				for (int i = 0; i < argc; i++) {
+					GET_VARIANT_PTR(v, i + 3);
+					argptrs[i] = v;
+				}
+
+				GET_VARIANT_PTR(dst, argc + 3);
+
+				const GDScript *gds = _script;
+
+				const Map<StringName, GDScriptFunction *>::Element *E = nullptr;
+				while (gds->base.ptr()) {
+					gds = gds->base.ptr();
+					E = gds->member_functions.find(*methodname);
+					if (E) {
+						break;
+					}
+				}
+
+				Callable::CallError err;
+
+				if (E) {
+					*dst = E->get()->call(p_instance, (const Variant **)argptrs, argc, err);
+				} else if (gds->native.ptr()) {
+					if (*methodname != GDScriptLanguage::get_singleton()->strings._init) {
+						MethodBind *mb = ClassDB::get_method(gds->native->get_name(), *methodname);
+						if (!mb) {
+							err.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+						} else {
+							*dst = mb->call(p_instance->owner, (const Variant **)argptrs, argc, err);
+						}
+					} else {
+						err.error = Callable::CallError::CALL_OK;
+					}
+				} else {
+					if (*methodname != GDScriptLanguage::get_singleton()->strings._init) {
+						err.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+					} else {
+						err.error = Callable::CallError::CALL_OK;
+					}
+				}
+
+				if (err.error != Callable::CallError::CALL_OK) {
+					String methodstr = *methodname;
+					err_text = _get_call_error(err, "function '" + methodstr + "'", (const Variant **)argptrs);
+
+					OPCODE_BREAK;
+				}
+
+				ip += 4 + argc;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_AWAIT) {
+				CHECK_SPACE(2);
+
+				//do the oneshot connect
+				GET_VARIANT_PTR(argobj, 1);
+
+				Signal sig;
+				bool is_signal = true;
+
+				{
+					Variant result = *argobj;
+
+					if (argobj->get_type() == Variant::OBJECT) {
+						bool was_freed = false;
+						Object *obj = argobj->get_validated_object_with_check(was_freed);
+
+						if (was_freed) {
+							err_text = "Trying to await on a freed object.";
+							OPCODE_BREAK;
+						}
+
+						// Is this even possible to be null at this point?
+						if (obj) {
+							if (obj->is_class_ptr(GDScriptFunctionState::get_class_ptr_static())) {
+								static StringName completed = _scs_create("completed");
+								result = Signal(obj, completed);
+							}
+						}
+					}
+
+					if (result.get_type() != Variant::SIGNAL) {
+						ip += 4; // Skip OPCODE_AWAIT_RESUME and its data.
+						// The stack pointer should be the same, so we don't need to set a return value.
+						is_signal = false;
+					} else {
+						sig = result;
+					}
+				}
+
+				if (is_signal) {
+					Ref<GDScriptFunctionState> gdfs = memnew(GDScriptFunctionState);
+					gdfs->function = this;
+
+					gdfs->state.stack.resize(alloca_size);
+					//copy variant stack
+					for (int i = 0; i < _stack_size; i++) {
+						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;
+					gdfs->state.script = _script;
+					{
+						MutexLock lock(GDScriptLanguage::get_singleton()->lock);
+						_script->pending_func_states.add(&gdfs->scripts_list);
+						if (p_instance) {
+							gdfs->state.instance = p_instance;
+							p_instance->pending_func_states.add(&gdfs->instances_list);
+						} else {
+							gdfs->state.instance = nullptr;
+						}
+					}
+#ifdef DEBUG_ENABLED
+					gdfs->state.function_name = name;
+					gdfs->state.script_path = _script->get_path();
+#endif
+					gdfs->state.defarg = defarg;
+					gdfs->function = this;
+
+					retvalue = gdfs;
+
+					Error err = sig.connect(Callable(gdfs.ptr(), "_signal_callback"), varray(gdfs), Object::CONNECT_ONESHOT);
+					if (err != OK) {
+						err_text = "Error connecting to signal: " + sig.get_name() + " during await.";
+						OPCODE_BREAK;
+					}
+
+#ifdef DEBUG_ENABLED
+					exit_ok = true;
+					awaited = true;
+#endif
+					OPCODE_BREAK;
+				}
+			}
+			DISPATCH_OPCODE; // Needed for synchronous calls (when result is immediately available).
+
+			OPCODE(OPCODE_AWAIT_RESUME) {
+				CHECK_SPACE(2);
+#ifdef DEBUG_ENABLED
+				if (!p_state) {
+					err_text = ("Invalid Resume (bug?)");
+					OPCODE_BREAK;
+				}
+#endif
+				GET_VARIANT_PTR(result, 1);
+				*result = p_state->result;
+				ip += 2;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_JUMP) {
+				CHECK_SPACE(2);
+				int to = _code_ptr[ip + 1];
+
+				GD_ERR_BREAK(to < 0 || to > _code_size);
+				ip = to;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_JUMP_IF) {
+				CHECK_SPACE(3);
+
+				GET_VARIANT_PTR(test, 1);
+
+				bool result = test->booleanize();
+
+				if (result) {
+					int to = _code_ptr[ip + 2];
+					GD_ERR_BREAK(to < 0 || to > _code_size);
+					ip = to;
+				} else {
+					ip += 3;
+				}
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_JUMP_IF_NOT) {
+				CHECK_SPACE(3);
+
+				GET_VARIANT_PTR(test, 1);
+
+				bool result = test->booleanize();
+
+				if (!result) {
+					int to = _code_ptr[ip + 2];
+					GD_ERR_BREAK(to < 0 || to > _code_size);
+					ip = to;
+				} else {
+					ip += 3;
+				}
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_JUMP_TO_DEF_ARGUMENT) {
+				CHECK_SPACE(2);
+				ip = _default_arg_ptr[defarg];
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_RETURN) {
+				CHECK_SPACE(2);
+				GET_VARIANT_PTR(r, 1);
+				retvalue = *r;
+#ifdef DEBUG_ENABLED
+				exit_ok = true;
+#endif
+				OPCODE_BREAK;
+			}
+
+			OPCODE(OPCODE_ITERATE_BEGIN) {
+				CHECK_SPACE(8); //space for this a regular iterate
+
+				GET_VARIANT_PTR(counter, 1);
+				GET_VARIANT_PTR(container, 2);
+
+				bool valid;
+				if (!container->iter_init(*counter, valid)) {
+#ifdef DEBUG_ENABLED
+					if (!valid) {
+						err_text = "Unable to iterate on object of type '" + Variant::get_type_name(container->get_type()) + "'.";
+						OPCODE_BREAK;
+					}
+#endif
+					int jumpto = _code_ptr[ip + 3];
+					GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+					ip = jumpto;
+				} else {
+					GET_VARIANT_PTR(iterator, 4);
+
+					*iterator = container->iter_get(*counter, valid);
+#ifdef DEBUG_ENABLED
+					if (!valid) {
+						err_text = "Unable to obtain iterator object of type '" + Variant::get_type_name(container->get_type()) + "'.";
+						OPCODE_BREAK;
+					}
+#endif
+					ip += 5; //skip regular iterate which is always next
+				}
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_ITERATE) {
+				CHECK_SPACE(4);
+
+				GET_VARIANT_PTR(counter, 1);
+				GET_VARIANT_PTR(container, 2);
+
+				bool valid;
+				if (!container->iter_next(*counter, valid)) {
+#ifdef DEBUG_ENABLED
+					if (!valid) {
+						err_text = "Unable to iterate on object of type '" + Variant::get_type_name(container->get_type()) + "' (type changed since first iteration?).";
+						OPCODE_BREAK;
+					}
+#endif
+					int jumpto = _code_ptr[ip + 3];
+					GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+					ip = jumpto;
+				} else {
+					GET_VARIANT_PTR(iterator, 4);
+
+					*iterator = container->iter_get(*counter, valid);
+#ifdef DEBUG_ENABLED
+					if (!valid) {
+						err_text = "Unable to obtain iterator object of type '" + Variant::get_type_name(container->get_type()) + "' (but was obtained on first iteration?).";
+						OPCODE_BREAK;
+					}
+#endif
+					ip += 5; //loop again
+				}
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_ASSERT) {
+				CHECK_SPACE(3);
+
+#ifdef DEBUG_ENABLED
+				GET_VARIANT_PTR(test, 1);
+				bool result = test->booleanize();
+
+				if (!result) {
+					String message_str;
+					if (_code_ptr[ip + 2] != 0) {
+						GET_VARIANT_PTR(message, 2);
+						message_str = *message;
+					}
+					if (message_str.empty()) {
+						err_text = "Assertion failed.";
+					} else {
+						err_text = "Assertion failed: " + message_str;
+					}
+					OPCODE_BREAK;
+				}
+
+#endif
+				ip += 3;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_BREAKPOINT) {
+#ifdef DEBUG_ENABLED
+				if (EngineDebugger::is_active()) {
+					GDScriptLanguage::get_singleton()->debug_break("Breakpoint Statement", true);
+				}
+#endif
+				ip += 1;
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_LINE) {
+				CHECK_SPACE(2);
+
+				line = _code_ptr[ip + 1];
+				ip += 2;
+
+				if (EngineDebugger::is_active()) {
+					// line
+					bool do_break = false;
+
+					if (EngineDebugger::get_script_debugger()->get_lines_left() > 0) {
+						if (EngineDebugger::get_script_debugger()->get_depth() <= 0) {
+							EngineDebugger::get_script_debugger()->set_lines_left(EngineDebugger::get_script_debugger()->get_lines_left() - 1);
+						}
+						if (EngineDebugger::get_script_debugger()->get_lines_left() <= 0) {
+							do_break = true;
+						}
+					}
+
+					if (EngineDebugger::get_script_debugger()->is_breakpoint(line, source)) {
+						do_break = true;
+					}
+
+					if (do_break) {
+						GDScriptLanguage::get_singleton()->debug_break("Breakpoint", true);
+					}
+
+					EngineDebugger::get_singleton()->line_poll();
+				}
+			}
+			DISPATCH_OPCODE;
+
+			OPCODE(OPCODE_END) {
+#ifdef DEBUG_ENABLED
+				exit_ok = true;
+#endif
+				OPCODE_BREAK;
+			}
+
+#if 0 // Enable for debugging.
+			default: {
+				err_text = "Illegal opcode " + itos(_code_ptr[ip]) + " at address " + itos(ip);
+				OPCODE_BREAK;
+			}
+#endif
+		}
+
+		OPCODES_END
+#ifdef DEBUG_ENABLED
+		if (exit_ok) {
+			OPCODE_OUT;
+		}
+		//error
+		// function, file, line, error, explanation
+		String err_file;
+		if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && p_instance->script->path != "") {
+			err_file = p_instance->script->path;
+		} else if (script) {
+			err_file = script->path;
+		}
+		if (err_file == "") {
+			err_file = "<built-in>";
+		}
+		String err_func = name;
+		if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && p_instance->script->name != "") {
+			err_func = p_instance->script->name + "." + err_func;
+		}
+		int err_line = line;
+		if (err_text == "") {
+			err_text = "Internal Script Error! - opcode #" + itos(last_opcode) + " (report please).";
+		}
+
+		if (!GDScriptLanguage::get_singleton()->debug_break(err_text, false)) {
+			// debugger break did not happen
+
+			_err_print_error(err_func.utf8().get_data(), err_file.utf8().get_data(), err_line, err_text.utf8().get_data(), ERR_HANDLER_SCRIPT);
+		}
+
+#endif
+		OPCODE_OUT;
+	}
+
+	OPCODES_OUT
+#ifdef DEBUG_ENABLED
+	if (GDScriptLanguage::get_singleton()->profiling) {
+		uint64_t time_taken = OS::get_singleton()->get_ticks_usec() - function_start_time;
+		profile.total_time += time_taken;
+		profile.self_time += time_taken - function_call_time;
+		profile.frame_total_time += time_taken;
+		profile.frame_self_time += time_taken - function_call_time;
+		GDScriptLanguage::get_singleton()->script_frame_time += time_taken - function_call_time;
+	}
+
+	// Check if this is the last time the function is resuming from await
+	// Will be true if never awaited as well
+	// When it's the last resume it will postpone the exit from stack,
+	// so the debugger knows which function triggered the resume of the next function (if any)
+	if (!p_state || awaited) {
+		if (EngineDebugger::is_active()) {
+			GDScriptLanguage::get_singleton()->exit_function();
+		}
+#endif
+
+		if (_stack_size) {
+			//free stack
+			for (int i = 0; i < _stack_size; i++) {
+				stack[i].~Variant();
+			}
+		}
+
+#ifdef DEBUG_ENABLED
+	}
+#endif
+
+	return retvalue;
+}

部分文件因文件數量過多而無法顯示