| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074 | /*************************************************************************//*  gdscript_disassembler.cpp                                            *//*************************************************************************//*                       This file is part of:                           *//*                           GODOT ENGINE                                *//*                      https://godotengine.org                          *//*************************************************************************//* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 *//* Copyright (c) 2014-2022 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"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_MEMBER: {			return "member(" + p_script->debug_get_member_by_index(addr) + ")";		} break;		case GDScriptFunction::ADDR_TYPE_CONSTANT: {			return "const(" + _get_variant_string(p_function.get_constant(addr)) + ")";		} break;		case GDScriptFunction::ADDR_TYPE_STACK: {			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;	}	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] & INSTR_MASK);		int instr_var_args = (_code_ptr[ip] & INSTR_ARGS_MASK) >> INSTR_BITS;		switch (code) {			case OPCODE_OPERATOR: {				int operation = _code_ptr[ip + 4];				text += "operator ";				text += DADDR(3);				text += " = ";				text += DADDR(1);				text += " ";				text += Variant::get_operator_name(Variant::Operator(operation));				text += " ";				text += DADDR(2);				incr += 5;			} break;			case OPCODE_OPERATOR_VALIDATED: {				text += "validated operator ";				text += DADDR(3);				text += " = ";				text += DADDR(1);				text += " <operator function> ";				text += DADDR(2);				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(2);				text += " = ";				text += DADDR(1);				text += " is ";				text += Variant::get_type_name(Variant::Type(_code_ptr[ip + 3]));				incr += 4;			} break;			case OPCODE_SET_KEYED: {				text += "set keyed ";				text += DADDR(1);				text += "[";				text += DADDR(2);				text += "] = ";				text += DADDR(3);				incr += 4;			} break;			case OPCODE_SET_KEYED_VALIDATED: {				text += "set keyed validated ";				text += DADDR(1);				text += "[";				text += DADDR(2);				text += "] = ";				text += DADDR(3);				incr += 5;			} break;			case OPCODE_SET_INDEXED_VALIDATED: {				text += "set indexed validated ";				text += DADDR(1);				text += "[";				text += DADDR(2);				text += "] = ";				text += DADDR(3);				incr += 5;			} break;			case OPCODE_GET_KEYED: {				text += "get keyed ";				text += DADDR(3);				text += " = ";				text += DADDR(1);				text += "[";				text += DADDR(2);				text += "]";				incr += 4;			} break;			case OPCODE_GET_KEYED_VALIDATED: {				text += "get keyed validated ";				text += DADDR(3);				text += " = ";				text += DADDR(1);				text += "[";				text += DADDR(2);				text += "]";				incr += 5;			} break;			case OPCODE_GET_INDEXED_VALIDATED: {				text += "get indexed validated ";				text += DADDR(3);				text += " = ";				text += DADDR(1);				text += "[";				text += DADDR(2);				text += "]";				incr += 5;			} break;			case OPCODE_SET_NAMED: {				text += "set_named ";				text += DADDR(1);				text += "[\"";				text += _global_names_ptr[_code_ptr[ip + 3]];				text += "\"] = ";				text += DADDR(2);				incr += 4;			} break;			case OPCODE_SET_NAMED_VALIDATED: {				text += "set_named validated ";				text += DADDR(1);				text += "[\"";				text += "<unknown name>";				text += "\"] = ";				text += DADDR(2);				incr += 4;			} break;			case OPCODE_GET_NAMED: {				text += "get_named ";				text += DADDR(2);				text += " = ";				text += DADDR(1);				text += "[\"";				text += _global_names_ptr[_code_ptr[ip + 3]];				text += "\"]";				incr += 4;			} break;			case OPCODE_GET_NAMED_VALIDATED: {				text += "get_named validated ";				text += DADDR(2);				text += " = ";				text += DADDR(1);				text += "[\"";				text += "<unknown name>";				text += "\"]";				incr += 4;			} break;			case OPCODE_SET_MEMBER: {				text += "set_member ";				text += "[\"";				text += _global_names_ptr[_code_ptr[ip + 2]];				text += "\"] = ";				text += DADDR(1);				incr += 3;			} break;			case OPCODE_GET_MEMBER: {				text += "get_member ";				text += DADDR(1);				text += " = ";				text += "[\"";				text += _global_names_ptr[_code_ptr[ip + 2]];				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 + 3]);				text += ") ";				text += DADDR(1);				text += " = ";				text += DADDR(2);				incr += 4;			} break;			case OPCODE_ASSIGN_TYPED_ARRAY: {				text += "assign typed array ";				text += DADDR(1);				text += " = ";				text += DADDR(2);				incr += 3;			} break;			case OPCODE_ASSIGN_TYPED_NATIVE: {				text += "assign typed native (";				text += DADDR(3);				text += ") ";				text += DADDR(1);				text += " = ";				text += DADDR(2);				incr += 4;			} break;			case OPCODE_ASSIGN_TYPED_SCRIPT: {				Variant script = _constants_ptr[_code_ptr[ip + 3]];				Script *sc = Object::cast_to<Script>(script.operator Object *());				text += "assign typed script (";				text += sc->get_path();				text += ") ";				text += DADDR(1);				text += " = ";				text += DADDR(2);				incr += 4;			} break;			case OPCODE_CAST_TO_BUILTIN: {				text += "cast builtin ";				text += DADDR(2);				text += " = ";				text += DADDR(1);				text += " as ";				text += Variant::get_type_name(Variant::Type(_code_ptr[ip + 1]));				incr += 4;			} break;			case OPCODE_CAST_TO_NATIVE: {				text += "cast native ";				text += DADDR(2);				text += " = ";				text += DADDR(1);				text += " as ";				text += DADDR(3);				incr += 4;			} break;			case OPCODE_CAST_TO_SCRIPT: {				text += "cast ";				text += DADDR(2);				text += " = ";				text += DADDR(1);				text += " as ";				text += DADDR(3);				incr += 4;			} break;			case OPCODE_CONSTRUCT: {				Variant::Type t = Variant::Type(_code_ptr[ip + 3 + instr_var_args]);				int argc = _code_ptr[ip + 1 + instr_var_args];				text += "construct ";				text += DADDR(1 + argc);				text += " = ";				text += Variant::get_type_name(t) + "(";				for (int i = 0; i < argc; i++) {					if (i > 0) {						text += ", ";					}					text += DADDR(i + 1);				}				text += ")";				incr = 3 + instr_var_args;			} break;			case OPCODE_CONSTRUCT_VALIDATED: {				int argc = _code_ptr[ip + 1 + instr_var_args];				text += "construct validated ";				text += DADDR(1 + argc);				text += " = ";				text += "<unknown type>(";				for (int i = 0; i < argc; i++) {					if (i > 0) {						text += ", ";					}					text += DADDR(i + 1);				}				text += ")";				incr = 3 + instr_var_args;			} break;			case OPCODE_CONSTRUCT_ARRAY: {				int argc = _code_ptr[ip + 1 + instr_var_args];				text += " make_array ";				text += DADDR(1 + argc);				text += " = [";				for (int i = 0; i < argc; i++) {					if (i > 0) {						text += ", ";					}					text += DADDR(1 + i);				}				text += "]";				incr += 3 + argc;			} break;			case OPCODE_CONSTRUCT_TYPED_ARRAY: {				int argc = _code_ptr[ip + 1 + instr_var_args];				Ref<Script> script_type = get_constant(_code_ptr[ip + argc + 2]);				Variant::Type builtin_type = (Variant::Type)_code_ptr[ip + argc + 4];				StringName native_type = get_global_name(_code_ptr[ip + argc + 5]);				String type_name;				if (script_type.is_valid() && script_type->is_valid()) {					type_name = script_type->get_path();				} else if (native_type != StringName()) {					type_name = native_type;				} else {					type_name = Variant::get_type_name(builtin_type);				}				text += " make_typed_array (";				text += type_name;				text += ") ";				text += DADDR(1 + argc);				text += " = [";				for (int i = 0; i < argc; i++) {					if (i > 0) {						text += ", ";					}					text += DADDR(1 + i);				}				text += "]";				incr += 3 + argc;			} break;			case OPCODE_CONSTRUCT_DICTIONARY: {				int argc = _code_ptr[ip + 1 + instr_var_args];				text += "make_dict ";				text += DADDR(1 + argc * 2);				text += " = {";				for (int i = 0; i < argc; i++) {					if (i > 0) {						text += ", ";					}					text += DADDR(1 + i * 2 + 0);					text += ": ";					text += DADDR(1 + 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] & INSTR_MASK) == OPCODE_CALL_RETURN;				bool async = (_code_ptr[ip] & INSTR_MASK) == OPCODE_CALL_ASYNC;				if (ret) {					text += "call-ret ";				} else if (async) {					text += "call-async ";				} else {					text += "call ";				}				int argc = _code_ptr[ip + 1 + instr_var_args];				if (ret || async) {					text += DADDR(2 + argc) + " = ";				}				text += DADDR(1 + argc) + ".";				text += String(_global_names_ptr[_code_ptr[ip + 2 + instr_var_args]]);				text += "(";				for (int i = 0; i < argc; i++) {					if (i > 0) {						text += ", ";					}					text += DADDR(1 + i);				}				text += ")";				incr = 5 + argc;			} break;			case OPCODE_CALL_METHOD_BIND:			case OPCODE_CALL_METHOD_BIND_RET: {				bool ret = (_code_ptr[ip] & INSTR_MASK) == OPCODE_CALL_METHOD_BIND_RET;				if (ret) {					text += "call-method_bind-ret ";				} else {					text += "call-method_bind ";				}				MethodBind *method = _methods_ptr[_code_ptr[ip + 2 + instr_var_args]];				int argc = _code_ptr[ip + 1 + instr_var_args];				if (ret) {					text += DADDR(2 + argc) + " = ";				}				text += DADDR(1 + argc) + ".";				text += method->get_name();				text += "(";				for (int i = 0; i < argc; i++) {					if (i > 0) {						text += ", ";					}					text += DADDR(1 + i);				}				text += ")";				incr = 5 + argc;			} break;			case OPCODE_CALL_BUILTIN_STATIC: {				Variant::Type type = (Variant::Type)_code_ptr[ip + 1 + instr_var_args];				int argc = _code_ptr[ip + 3 + instr_var_args];				text += "call built-in method static ";				text += DADDR(1 + argc);				text += " = ";				text += Variant::get_type_name(type);				text += ".";				text += _global_names_ptr[_code_ptr[ip + 2 + instr_var_args]].operator String();				text += "(";				for (int i = 0; i < argc; i++) {					if (i > 0) {						text += ", ";					}					text += DADDR(1 + i);				}				text += ")";				incr += 5 + argc;			} break;			case OPCODE_CALL_NATIVE_STATIC: {				MethodBind *method = _methods_ptr[_code_ptr[ip + 1 + instr_var_args]];				int argc = _code_ptr[ip + 2 + instr_var_args];				text += "call native method static ";				text += DADDR(1 + argc);				text += " = ";				text += method->get_instance_class();				text += ".";				text += method->get_name();				text += "(";				for (int i = 0; i < argc; i++) {					if (i > 0) {						text += ", ";					}					text += DADDR(1 + i);				}				text += ")";				incr += 4 + argc;			} break;			case OPCODE_CALL_PTRCALL_NO_RETURN: {				text += "call-ptrcall (no return) ";				MethodBind *method = _methods_ptr[_code_ptr[ip + 2 + instr_var_args]];				int argc = _code_ptr[ip + 1 + instr_var_args];				text += DADDR(1 + argc) + ".";				text += method->get_name();				text += "(";				for (int i = 0; i < argc; i++) {					if (i > 0) {						text += ", ";					}					text += DADDR(1 + i);				}				text += ")";				incr = 5 + argc;			} break;#define DISASSEMBLE_PTRCALL(m_type)                                            \	case OPCODE_CALL_PTRCALL_##m_type: {                                       \		text += "call-ptrcall (return ";                                       \		text += #m_type;                                                       \		text += ") ";                                                          \		MethodBind *method = _methods_ptr[_code_ptr[ip + 2 + instr_var_args]]; \		int argc = _code_ptr[ip + 1 + instr_var_args];                         \		text += DADDR(2 + argc) + " = ";                                       \		text += DADDR(1 + argc) + ".";                                         \		text += method->get_name();                                            \		text += "(";                                                           \		for (int i = 0; i < argc; i++) {                                       \			if (i > 0)                                                         \				text += ", ";                                                  \			text += DADDR(1 + i);                                              \		}                                                                      \		text += ")";                                                           \		incr = 5 + argc;                                                       \	} break				DISASSEMBLE_PTRCALL(BOOL);				DISASSEMBLE_PTRCALL(INT);				DISASSEMBLE_PTRCALL(FLOAT);				DISASSEMBLE_PTRCALL(STRING);				DISASSEMBLE_PTRCALL(VECTOR2);				DISASSEMBLE_PTRCALL(VECTOR2I);				DISASSEMBLE_PTRCALL(RECT2);				DISASSEMBLE_PTRCALL(RECT2I);				DISASSEMBLE_PTRCALL(VECTOR3);				DISASSEMBLE_PTRCALL(VECTOR3I);				DISASSEMBLE_PTRCALL(TRANSFORM2D);				DISASSEMBLE_PTRCALL(VECTOR4);				DISASSEMBLE_PTRCALL(VECTOR4I);				DISASSEMBLE_PTRCALL(PLANE);				DISASSEMBLE_PTRCALL(AABB);				DISASSEMBLE_PTRCALL(BASIS);				DISASSEMBLE_PTRCALL(TRANSFORM3D);				DISASSEMBLE_PTRCALL(PROJECTION);				DISASSEMBLE_PTRCALL(COLOR);				DISASSEMBLE_PTRCALL(STRING_NAME);				DISASSEMBLE_PTRCALL(NODE_PATH);				DISASSEMBLE_PTRCALL(RID);				DISASSEMBLE_PTRCALL(QUATERNION);				DISASSEMBLE_PTRCALL(OBJECT);				DISASSEMBLE_PTRCALL(CALLABLE);				DISASSEMBLE_PTRCALL(SIGNAL);				DISASSEMBLE_PTRCALL(DICTIONARY);				DISASSEMBLE_PTRCALL(ARRAY);				DISASSEMBLE_PTRCALL(PACKED_BYTE_ARRAY);				DISASSEMBLE_PTRCALL(PACKED_INT32_ARRAY);				DISASSEMBLE_PTRCALL(PACKED_INT64_ARRAY);				DISASSEMBLE_PTRCALL(PACKED_FLOAT32_ARRAY);				DISASSEMBLE_PTRCALL(PACKED_FLOAT64_ARRAY);				DISASSEMBLE_PTRCALL(PACKED_STRING_ARRAY);				DISASSEMBLE_PTRCALL(PACKED_VECTOR2_ARRAY);				DISASSEMBLE_PTRCALL(PACKED_VECTOR3_ARRAY);				DISASSEMBLE_PTRCALL(PACKED_COLOR_ARRAY);			case OPCODE_CALL_BUILTIN_TYPE_VALIDATED: {				int argc = _code_ptr[ip + 1 + instr_var_args];				text += "call-builtin-method validated ";				text += DADDR(2 + argc) + " = ";				text += DADDR(1) + ".";				text += "<unknown method>";				text += "(";				for (int i = 0; i < argc; i++) {					if (i > 0) {						text += ", ";					}					text += DADDR(1 + i);				}				text += ")";				incr = 5 + argc;			} break;			case OPCODE_CALL_UTILITY: {				text += "call-utility ";				int argc = _code_ptr[ip + 1 + instr_var_args];				text += DADDR(1 + argc) + " = ";				text += _global_names_ptr[_code_ptr[ip + 2 + instr_var_args]];				text += "(";				for (int i = 0; i < argc; i++) {					if (i > 0) {						text += ", ";					}					text += DADDR(1 + i);				}				text += ")";				incr = 4 + argc;			} break;			case OPCODE_CALL_UTILITY_VALIDATED: {				text += "call-utility ";				int argc = _code_ptr[ip + 1 + instr_var_args];				text += DADDR(1 + argc) + " = ";				text += "<unknown function>";				text += "(";				for (int i = 0; i < argc; i++) {					if (i > 0) {						text += ", ";					}					text += DADDR(1 + i);				}				text += ")";				incr = 4 + argc;			} break;			case OPCODE_CALL_GDSCRIPT_UTILITY: {				text += "call-gscript-utility ";				int argc = _code_ptr[ip + 1 + instr_var_args];				text += DADDR(1 + argc) + " = ";				text += "<unknown function>";				text += "(";				for (int i = 0; i < argc; i++) {					if (i > 0) {						text += ", ";					}					text += DADDR(1 + i);				}				text += ")";				incr = 4 + argc;			} break;			case OPCODE_CALL_SELF_BASE: {				text += "call-self-base ";				int argc = _code_ptr[ip + 1 + instr_var_args];				text += DADDR(2 + argc) + " = ";				text += _global_names_ptr[_code_ptr[ip + 2 + instr_var_args]];				text += "(";				for (int i = 0; i < argc; i++) {					if (i > 0) {						text += ", ";					}					text += DADDR(1 + 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_CREATE_LAMBDA: {				int captures_count = _code_ptr[ip + 1 + instr_var_args];				GDScriptFunction *lambda = _lambdas_ptr[_code_ptr[ip + 2 + instr_var_args]];				text += DADDR(1 + captures_count);				text += "create lambda from ";				text += lambda->name.operator String();				text += "function, captures (";				for (int i = 0; i < captures_count; i++) {					if (i > 0) {						text += ", ";					}					text += DADDR(1 + i);				}				text += ")";				incr = 3 + captures_count;			} break;			case OPCODE_CREATE_SELF_LAMBDA: {				int captures_count = _code_ptr[ip + 1 + instr_var_args];				GDScriptFunction *lambda = _lambdas_ptr[_code_ptr[ip + 2 + instr_var_args]];				text += DADDR(1 + captures_count);				text += "create self lambda from ";				text += lambda->name.operator String();				text += "function, captures (";				for (int i = 0; i < captures_count; i++) {					if (i > 0) {						text += ", ";					}					text += DADDR(1 + i);				}				text += ")";				incr = 3 + captures_count;			} 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_JUMP_IF_SHARED: {				text += "jump-if-shared ";				text += DADDR(1);				text += " to ";				text += itos(_code_ptr[ip + 2]);				incr = 3;			} break;			case OPCODE_RETURN: {				text += "return ";				text += DADDR(1);				incr = 2;			} break;			case OPCODE_RETURN_TYPED_BUILTIN: {				text += "return typed builtin (";				text += Variant::get_type_name((Variant::Type)_code_ptr[ip + 2]);				text += ") ";				text += DADDR(1);				incr += 3;			} break;			case OPCODE_RETURN_TYPED_ARRAY: {				text += "return typed array ";				text += DADDR(1);				incr += 5;			} break;			case OPCODE_RETURN_TYPED_NATIVE: {				text += "return typed native (";				text += DADDR(2);				text += ") ";				text += DADDR(1);				incr += 3;			} break;			case OPCODE_RETURN_TYPED_SCRIPT: {				Variant script = _constants_ptr[_code_ptr[ip + 2]];				Script *sc = Object::cast_to<Script>(script.operator Object *());				text += "return typed script (";				text += sc->get_path();				text += ") ";				text += DADDR(1);				incr += 3;			} break;#define DISASSEMBLE_ITERATE(m_type)      \	case OPCODE_ITERATE_##m_type: {      \		text += "for-loop (typed ";      \		text += #m_type;                 \		text += ") ";                    \		text += DADDR(3);                \		text += " in ";                  \		text += DADDR(2);                \		text += " counter ";             \		text += DADDR(1);                \		text += " end ";                 \		text += itos(_code_ptr[ip + 4]); \		incr += 5;                       \	} break#define DISASSEMBLE_ITERATE_BEGIN(m_type) \	case OPCODE_ITERATE_BEGIN_##m_type: { \		text += "for-init (typed ";       \		text += #m_type;                  \		text += ") ";                     \		text += DADDR(3);                 \		text += " in ";                   \		text += DADDR(2);                 \		text += " counter ";              \		text += DADDR(1);                 \		text += " end ";                  \		text += itos(_code_ptr[ip + 4]);  \		incr += 5;                        \	} break#define DISASSEMBLE_ITERATE_TYPES(m_macro) \	m_macro(INT);                          \	m_macro(FLOAT);                        \	m_macro(VECTOR2);                      \	m_macro(VECTOR2I);                     \	m_macro(VECTOR3);                      \	m_macro(VECTOR3I);                     \	m_macro(STRING);                       \	m_macro(DICTIONARY);                   \	m_macro(ARRAY);                        \	m_macro(PACKED_BYTE_ARRAY);            \	m_macro(PACKED_INT32_ARRAY);           \	m_macro(PACKED_INT64_ARRAY);           \	m_macro(PACKED_FLOAT32_ARRAY);         \	m_macro(PACKED_FLOAT64_ARRAY);         \	m_macro(PACKED_STRING_ARRAY);          \	m_macro(PACKED_VECTOR2_ARRAY);         \	m_macro(PACKED_VECTOR3_ARRAY);         \	m_macro(PACKED_COLOR_ARRAY);           \	m_macro(OBJECT)			case OPCODE_ITERATE_BEGIN: {				text += "for-init ";				text += DADDR(3);				text += " in ";				text += DADDR(2);				text += " counter ";				text += DADDR(1);				text += " end ";				text += itos(_code_ptr[ip + 4]);				incr += 5;			} break;				DISASSEMBLE_ITERATE_TYPES(DISASSEMBLE_ITERATE_BEGIN);			case OPCODE_ITERATE: {				text += "for-loop ";				text += DADDR(2);				text += " in ";				text += DADDR(2);				text += " counter ";				text += DADDR(1);				text += " end ";				text += itos(_code_ptr[ip + 4]);				incr += 5;			} break;				DISASSEMBLE_ITERATE_TYPES(DISASSEMBLE_ITERATE);			case OPCODE_STORE_GLOBAL: {				text += "store global ";				text += DADDR(1);				text += " = ";				text += String::num_int64(_code_ptr[ip + 2]);				incr += 3;			} break;			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()) {					text += "line ";					text += itos(line + 1);					text += ": ";					text += p_code_lines[line];				} else {					text += "";				}				incr += 2;			} break;#define DISASSEMBLE_TYPE_ADJUST(m_v_type) \	case OPCODE_TYPE_ADJUST_##m_v_type: { \		text += "type adjust (";          \		text += #m_v_type;                \		text += ") ";                     \		text += DADDR(1);                 \		incr += 2;                        \	} break				DISASSEMBLE_TYPE_ADJUST(BOOL);				DISASSEMBLE_TYPE_ADJUST(INT);				DISASSEMBLE_TYPE_ADJUST(FLOAT);				DISASSEMBLE_TYPE_ADJUST(STRING);				DISASSEMBLE_TYPE_ADJUST(VECTOR2);				DISASSEMBLE_TYPE_ADJUST(VECTOR2I);				DISASSEMBLE_TYPE_ADJUST(RECT2);				DISASSEMBLE_TYPE_ADJUST(RECT2I);				DISASSEMBLE_TYPE_ADJUST(VECTOR3);				DISASSEMBLE_TYPE_ADJUST(VECTOR3I);				DISASSEMBLE_TYPE_ADJUST(TRANSFORM2D);				DISASSEMBLE_TYPE_ADJUST(VECTOR4);				DISASSEMBLE_TYPE_ADJUST(VECTOR4I);				DISASSEMBLE_TYPE_ADJUST(PLANE);				DISASSEMBLE_TYPE_ADJUST(QUATERNION);				DISASSEMBLE_TYPE_ADJUST(AABB);				DISASSEMBLE_TYPE_ADJUST(BASIS);				DISASSEMBLE_TYPE_ADJUST(TRANSFORM3D);				DISASSEMBLE_TYPE_ADJUST(PROJECTION);				DISASSEMBLE_TYPE_ADJUST(COLOR);				DISASSEMBLE_TYPE_ADJUST(STRING_NAME);				DISASSEMBLE_TYPE_ADJUST(NODE_PATH);				DISASSEMBLE_TYPE_ADJUST(RID);				DISASSEMBLE_TYPE_ADJUST(OBJECT);				DISASSEMBLE_TYPE_ADJUST(CALLABLE);				DISASSEMBLE_TYPE_ADJUST(SIGNAL);				DISASSEMBLE_TYPE_ADJUST(DICTIONARY);				DISASSEMBLE_TYPE_ADJUST(ARRAY);				DISASSEMBLE_TYPE_ADJUST(PACKED_BYTE_ARRAY);				DISASSEMBLE_TYPE_ADJUST(PACKED_INT32_ARRAY);				DISASSEMBLE_TYPE_ADJUST(PACKED_INT64_ARRAY);				DISASSEMBLE_TYPE_ADJUST(PACKED_FLOAT32_ARRAY);				DISASSEMBLE_TYPE_ADJUST(PACKED_FLOAT64_ARRAY);				DISASSEMBLE_TYPE_ADJUST(PACKED_STRING_ARRAY);				DISASSEMBLE_TYPE_ADJUST(PACKED_VECTOR2_ARRAY);				DISASSEMBLE_TYPE_ADJUST(PACKED_VECTOR3_ARRAY);				DISASSEMBLE_TYPE_ADJUST(PACKED_COLOR_ARRAY);			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
 |