1/**************************************************************************/
2/* gdscript_disassembler.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#ifdef DEBUG_ENABLED
32
33#include "gdscript.h"
34#include "gdscript_function.h"
35
36#include "core/string/string_builder.h"
37
38static String _get_variant_string(const Variant &p_variant) {
39 String txt;
40 if (p_variant.get_type() == Variant::STRING) {
41 txt = "\"" + String(p_variant) + "\"";
42 } else if (p_variant.get_type() == Variant::STRING_NAME) {
43 txt = "&\"" + String(p_variant) + "\"";
44 } else if (p_variant.get_type() == Variant::NODE_PATH) {
45 txt = "^\"" + String(p_variant) + "\"";
46 } else if (p_variant.get_type() == Variant::OBJECT) {
47 Object *obj = p_variant;
48 if (!obj) {
49 txt = "null";
50 } else {
51 GDScriptNativeClass *cls = Object::cast_to<GDScriptNativeClass>(obj);
52 if (cls) {
53 txt = "class(" + cls->get_name() + ")";
54 } else {
55 Script *script = Object::cast_to<Script>(obj);
56 if (script) {
57 txt = "script(" + GDScript::debug_get_script_name(script) + ")";
58 } else {
59 txt = "object(" + obj->get_class();
60 if (obj->get_script_instance()) {
61 txt += ", " + GDScript::debug_get_script_name(obj->get_script_instance()->get_script());
62 }
63 txt += ")";
64 }
65 }
66 }
67 } else {
68 txt = p_variant;
69 }
70 return txt;
71}
72
73static String _disassemble_address(const GDScript *p_script, const GDScriptFunction &p_function, int p_address) {
74 int addr = p_address & GDScriptFunction::ADDR_MASK;
75
76 switch (p_address >> GDScriptFunction::ADDR_BITS) {
77 case GDScriptFunction::ADDR_TYPE_STACK: {
78 switch (addr) {
79 case GDScriptFunction::ADDR_STACK_SELF:
80 return "self";
81 case GDScriptFunction::ADDR_STACK_CLASS:
82 return "class";
83 case GDScriptFunction::ADDR_STACK_NIL:
84 return "nil";
85 default:
86 return "stack(" + itos(addr) + ")";
87 }
88 } break;
89 case GDScriptFunction::ADDR_TYPE_CONSTANT: {
90 return "const(" + _get_variant_string(p_function.get_constant(addr)) + ")";
91 } break;
92 case GDScriptFunction::ADDR_TYPE_MEMBER: {
93 return "member(" + p_script->debug_get_member_by_index(addr) + ")";
94 } break;
95 }
96
97 return "<err>";
98}
99
100void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
101#define DADDR(m_ip) (_disassemble_address(_script, *this, _code_ptr[ip + m_ip]))
102
103 for (int ip = 0; ip < _code_size;) {
104 StringBuilder text;
105 int incr = 0;
106
107 text += " ";
108 text += itos(ip);
109 text += ": ";
110
111 // This makes the compiler complain if some opcode is unchecked in the switch.
112 Opcode opcode = Opcode(_code_ptr[ip]);
113
114 switch (opcode) {
115 case OPCODE_OPERATOR: {
116 constexpr int _pointer_size = sizeof(Variant::ValidatedOperatorEvaluator) / sizeof(*_code_ptr);
117 int operation = _code_ptr[ip + 4];
118
119 text += "operator ";
120
121 text += DADDR(3);
122 text += " = ";
123 text += DADDR(1);
124 text += " ";
125 text += Variant::get_operator_name(Variant::Operator(operation));
126 text += " ";
127 text += DADDR(2);
128
129 incr += 7 + _pointer_size;
130 } break;
131 case OPCODE_OPERATOR_VALIDATED: {
132 text += "validated operator ";
133
134 text += DADDR(3);
135 text += " = ";
136 text += DADDR(1);
137 text += " ";
138 text += operator_names[_code_ptr[ip + 4]];
139 text += " ";
140 text += DADDR(2);
141
142 incr += 5;
143 } break;
144 case OPCODE_TYPE_TEST_BUILTIN: {
145 text += "type test ";
146 text += DADDR(1);
147 text += " = ";
148 text += DADDR(2);
149 text += " is ";
150 text += Variant::get_type_name(Variant::Type(_code_ptr[ip + 3]));
151
152 incr += 4;
153 } break;
154 case OPCODE_TYPE_TEST_ARRAY: {
155 text += "type test ";
156 text += DADDR(1);
157 text += " = ";
158 text += DADDR(2);
159 text += " is Array[";
160
161 Ref<Script> script_type = get_constant(_code_ptr[ip + 3] & ADDR_MASK);
162 Variant::Type builtin_type = (Variant::Type)_code_ptr[ip + 4];
163 StringName native_type = get_global_name(_code_ptr[ip + 5]);
164
165 if (script_type.is_valid() && script_type->is_valid()) {
166 text += "script(";
167 text += GDScript::debug_get_script_name(script_type);
168 text += ")";
169 } else if (native_type != StringName()) {
170 text += native_type;
171 } else {
172 text += Variant::get_type_name(builtin_type);
173 }
174
175 text += "]";
176
177 incr += 6;
178 } break;
179 case OPCODE_TYPE_TEST_NATIVE: {
180 text += "type test ";
181 text += DADDR(1);
182 text += " = ";
183 text += DADDR(2);
184 text += " is ";
185 text += get_global_name(_code_ptr[ip + 3]);
186
187 incr += 4;
188 } break;
189 case OPCODE_TYPE_TEST_SCRIPT: {
190 text += "type test ";
191 text += DADDR(1);
192 text += " = ";
193 text += DADDR(2);
194 text += " is ";
195 text += DADDR(3);
196
197 incr += 4;
198 } break;
199 case OPCODE_SET_KEYED: {
200 text += "set keyed ";
201 text += DADDR(1);
202 text += "[";
203 text += DADDR(2);
204 text += "] = ";
205 text += DADDR(3);
206
207 incr += 4;
208 } break;
209 case OPCODE_SET_KEYED_VALIDATED: {
210 text += "set keyed validated ";
211 text += DADDR(1);
212 text += "[";
213 text += DADDR(2);
214 text += "] = ";
215 text += DADDR(3);
216
217 incr += 5;
218 } break;
219 case OPCODE_SET_INDEXED_VALIDATED: {
220 text += "set indexed validated ";
221 text += DADDR(1);
222 text += "[";
223 text += DADDR(2);
224 text += "] = ";
225 text += DADDR(3);
226
227 incr += 5;
228 } break;
229 case OPCODE_GET_KEYED: {
230 text += "get keyed ";
231 text += DADDR(3);
232 text += " = ";
233 text += DADDR(1);
234 text += "[";
235 text += DADDR(2);
236 text += "]";
237
238 incr += 4;
239 } break;
240 case OPCODE_GET_KEYED_VALIDATED: {
241 text += "get keyed validated ";
242 text += DADDR(3);
243 text += " = ";
244 text += DADDR(1);
245 text += "[";
246 text += DADDR(2);
247 text += "]";
248
249 incr += 5;
250 } break;
251 case OPCODE_GET_INDEXED_VALIDATED: {
252 text += "get indexed validated ";
253 text += DADDR(3);
254 text += " = ";
255 text += DADDR(1);
256 text += "[";
257 text += DADDR(2);
258 text += "]";
259
260 incr += 5;
261 } break;
262 case OPCODE_SET_NAMED: {
263 text += "set_named ";
264 text += DADDR(1);
265 text += "[\"";
266 text += _global_names_ptr[_code_ptr[ip + 3]];
267 text += "\"] = ";
268 text += DADDR(2);
269
270 incr += 4;
271 } break;
272 case OPCODE_SET_NAMED_VALIDATED: {
273 text += "set_named validated ";
274 text += DADDR(1);
275 text += "[\"";
276 text += setter_names[_code_ptr[ip + 3]];
277 text += "\"] = ";
278 text += DADDR(2);
279
280 incr += 4;
281 } break;
282 case OPCODE_GET_NAMED: {
283 text += "get_named ";
284 text += DADDR(2);
285 text += " = ";
286 text += DADDR(1);
287 text += "[\"";
288 text += _global_names_ptr[_code_ptr[ip + 3]];
289 text += "\"]";
290
291 incr += 4;
292 } break;
293 case OPCODE_GET_NAMED_VALIDATED: {
294 text += "get_named validated ";
295 text += DADDR(2);
296 text += " = ";
297 text += DADDR(1);
298 text += "[\"";
299 text += getter_names[_code_ptr[ip + 3]];
300 text += "\"]";
301
302 incr += 4;
303 } break;
304 case OPCODE_SET_MEMBER: {
305 text += "set_member ";
306 text += "[\"";
307 text += _global_names_ptr[_code_ptr[ip + 2]];
308 text += "\"] = ";
309 text += DADDR(1);
310
311 incr += 3;
312 } break;
313 case OPCODE_GET_MEMBER: {
314 text += "get_member ";
315 text += DADDR(1);
316 text += " = ";
317 text += "[\"";
318 text += _global_names_ptr[_code_ptr[ip + 2]];
319 text += "\"]";
320
321 incr += 3;
322 } break;
323 case OPCODE_SET_STATIC_VARIABLE: {
324 Ref<GDScript> gdscript = get_constant(_code_ptr[ip + 2] & ADDR_MASK);
325
326 text += "set_static_variable script(";
327 text += GDScript::debug_get_script_name(gdscript);
328 text += ")";
329 if (gdscript.is_valid()) {
330 text += "[\"" + gdscript->debug_get_static_var_by_index(_code_ptr[ip + 3]) + "\"]";
331 } else {
332 text += "[<index " + itos(_code_ptr[ip + 3]) + ">]";
333 }
334 text += " = ";
335 text += DADDR(1);
336
337 incr += 4;
338 } break;
339 case OPCODE_GET_STATIC_VARIABLE: {
340 Ref<GDScript> gdscript = get_constant(_code_ptr[ip + 2] & ADDR_MASK);
341
342 text += "get_static_variable ";
343 text += DADDR(1);
344 text += " = script(";
345 text += GDScript::debug_get_script_name(gdscript);
346 text += ")";
347 if (gdscript.is_valid()) {
348 text += "[\"" + gdscript->debug_get_static_var_by_index(_code_ptr[ip + 3]) + "\"]";
349 } else {
350 text += "[<index " + itos(_code_ptr[ip + 3]) + ">]";
351 }
352
353 incr += 4;
354 } break;
355 case OPCODE_ASSIGN: {
356 text += "assign ";
357 text += DADDR(1);
358 text += " = ";
359 text += DADDR(2);
360
361 incr += 3;
362 } break;
363 case OPCODE_ASSIGN_TRUE: {
364 text += "assign ";
365 text += DADDR(1);
366 text += " = true";
367
368 incr += 2;
369 } break;
370 case OPCODE_ASSIGN_FALSE: {
371 text += "assign ";
372 text += DADDR(1);
373 text += " = false";
374
375 incr += 2;
376 } break;
377 case OPCODE_ASSIGN_TYPED_BUILTIN: {
378 text += "assign typed builtin (";
379 text += Variant::get_type_name((Variant::Type)_code_ptr[ip + 3]);
380 text += ") ";
381 text += DADDR(1);
382 text += " = ";
383 text += DADDR(2);
384
385 incr += 4;
386 } break;
387 case OPCODE_ASSIGN_TYPED_ARRAY: {
388 text += "assign typed array ";
389 text += DADDR(1);
390 text += " = ";
391 text += DADDR(2);
392
393 incr += 6;
394 } break;
395 case OPCODE_ASSIGN_TYPED_NATIVE: {
396 text += "assign typed native (";
397 text += DADDR(3);
398 text += ") ";
399 text += DADDR(1);
400 text += " = ";
401 text += DADDR(2);
402
403 incr += 4;
404 } break;
405 case OPCODE_ASSIGN_TYPED_SCRIPT: {
406 Ref<Script> script = get_constant(_code_ptr[ip + 3] & ADDR_MASK);
407
408 text += "assign typed script (";
409 text += GDScript::debug_get_script_name(script);
410 text += ") ";
411 text += DADDR(1);
412 text += " = ";
413 text += DADDR(2);
414
415 incr += 4;
416 } break;
417 case OPCODE_CAST_TO_BUILTIN: {
418 text += "cast builtin ";
419 text += DADDR(2);
420 text += " = ";
421 text += DADDR(1);
422 text += " as ";
423 text += Variant::get_type_name(Variant::Type(_code_ptr[ip + 1]));
424
425 incr += 4;
426 } break;
427 case OPCODE_CAST_TO_NATIVE: {
428 text += "cast native ";
429 text += DADDR(2);
430 text += " = ";
431 text += DADDR(1);
432 text += " as ";
433 text += DADDR(3);
434
435 incr += 4;
436 } break;
437 case OPCODE_CAST_TO_SCRIPT: {
438 text += "cast ";
439 text += DADDR(2);
440 text += " = ";
441 text += DADDR(1);
442 text += " as ";
443 text += DADDR(3);
444
445 incr += 4;
446 } break;
447 case OPCODE_CONSTRUCT: {
448 int instr_var_args = _code_ptr[++ip];
449 Variant::Type t = Variant::Type(_code_ptr[ip + 3 + instr_var_args]);
450 int argc = _code_ptr[ip + 1 + instr_var_args];
451
452 text += "construct ";
453 text += DADDR(1 + argc);
454 text += " = ";
455
456 text += Variant::get_type_name(t) + "(";
457 for (int i = 0; i < argc; i++) {
458 if (i > 0) {
459 text += ", ";
460 }
461 text += DADDR(i + 1);
462 }
463 text += ")";
464
465 incr = 3 + instr_var_args;
466 } break;
467 case OPCODE_CONSTRUCT_VALIDATED: {
468 int instr_var_args = _code_ptr[++ip];
469 int argc = _code_ptr[ip + 1 + instr_var_args];
470
471 text += "construct validated ";
472 text += DADDR(1 + argc);
473 text += " = ";
474
475 text += constructors_names[_code_ptr[ip + 3 + argc]];
476 text += "(";
477 for (int i = 0; i < argc; i++) {
478 if (i > 0) {
479 text += ", ";
480 }
481 text += DADDR(i + 1);
482 }
483 text += ")";
484
485 incr = 3 + instr_var_args;
486 } break;
487 case OPCODE_CONSTRUCT_ARRAY: {
488 int instr_var_args = _code_ptr[++ip];
489 int argc = _code_ptr[ip + 1 + instr_var_args];
490 text += " make_array ";
491 text += DADDR(1 + argc);
492 text += " = [";
493
494 for (int i = 0; i < argc; i++) {
495 if (i > 0) {
496 text += ", ";
497 }
498 text += DADDR(1 + i);
499 }
500
501 text += "]";
502
503 incr += 3 + argc;
504 } break;
505 case OPCODE_CONSTRUCT_TYPED_ARRAY: {
506 int instr_var_args = _code_ptr[++ip];
507 int argc = _code_ptr[ip + 1 + instr_var_args];
508
509 Ref<Script> script_type = get_constant(_code_ptr[ip + argc + 2] & ADDR_MASK);
510 Variant::Type builtin_type = (Variant::Type)_code_ptr[ip + argc + 4];
511 StringName native_type = get_global_name(_code_ptr[ip + argc + 5]);
512
513 String type_name;
514 if (script_type.is_valid() && script_type->is_valid()) {
515 type_name = "script(" + GDScript::debug_get_script_name(script_type) + ")";
516 } else if (native_type != StringName()) {
517 type_name = native_type;
518 } else {
519 type_name = Variant::get_type_name(builtin_type);
520 }
521
522 text += " make_typed_array (";
523 text += type_name;
524 text += ") ";
525
526 text += DADDR(1 + argc);
527 text += " = [";
528
529 for (int i = 0; i < argc; i++) {
530 if (i > 0) {
531 text += ", ";
532 }
533 text += DADDR(1 + i);
534 }
535
536 text += "]";
537
538 incr += 6 + argc;
539 } break;
540 case OPCODE_CONSTRUCT_DICTIONARY: {
541 int instr_var_args = _code_ptr[++ip];
542 int argc = _code_ptr[ip + 1 + instr_var_args];
543 text += "make_dict ";
544 text += DADDR(1 + argc * 2);
545 text += " = {";
546
547 for (int i = 0; i < argc; i++) {
548 if (i > 0) {
549 text += ", ";
550 }
551 text += DADDR(1 + i * 2 + 0);
552 text += ": ";
553 text += DADDR(1 + i * 2 + 1);
554 }
555
556 text += "}";
557
558 incr += 3 + argc * 2;
559 } break;
560 case OPCODE_CALL:
561 case OPCODE_CALL_RETURN:
562 case OPCODE_CALL_ASYNC: {
563 bool ret = (_code_ptr[ip]) == OPCODE_CALL_RETURN;
564 bool async = (_code_ptr[ip]) == OPCODE_CALL_ASYNC;
565
566 int instr_var_args = _code_ptr[++ip];
567
568 if (ret) {
569 text += "call-ret ";
570 } else if (async) {
571 text += "call-async ";
572 } else {
573 text += "call ";
574 }
575
576 int argc = _code_ptr[ip + 1 + instr_var_args];
577 if (ret || async) {
578 text += DADDR(2 + argc) + " = ";
579 }
580
581 text += DADDR(1 + argc) + ".";
582 text += String(_global_names_ptr[_code_ptr[ip + 2 + instr_var_args]]);
583 text += "(";
584
585 for (int i = 0; i < argc; i++) {
586 if (i > 0) {
587 text += ", ";
588 }
589 text += DADDR(1 + i);
590 }
591 text += ")";
592
593 incr = 5 + argc;
594 } break;
595 case OPCODE_CALL_METHOD_BIND:
596 case OPCODE_CALL_METHOD_BIND_RET: {
597 bool ret = (_code_ptr[ip]) == OPCODE_CALL_METHOD_BIND_RET;
598 int instr_var_args = _code_ptr[++ip];
599
600 if (ret) {
601 text += "call-method_bind-ret ";
602 } else {
603 text += "call-method_bind ";
604 }
605
606 MethodBind *method = _methods_ptr[_code_ptr[ip + 2 + instr_var_args]];
607
608 int argc = _code_ptr[ip + 1 + instr_var_args];
609 if (ret) {
610 text += DADDR(2 + argc) + " = ";
611 }
612
613 text += DADDR(1 + argc) + ".";
614 text += method->get_name();
615 text += "(";
616
617 for (int i = 0; i < argc; i++) {
618 if (i > 0) {
619 text += ", ";
620 }
621 text += DADDR(1 + i);
622 }
623 text += ")";
624
625 incr = 5 + argc;
626 } break;
627 case OPCODE_CALL_BUILTIN_STATIC: {
628 int instr_var_args = _code_ptr[++ip];
629 Variant::Type type = (Variant::Type)_code_ptr[ip + 1 + instr_var_args];
630 int argc = _code_ptr[ip + 3 + instr_var_args];
631
632 text += "call built-in method static ";
633 text += DADDR(1 + argc);
634 text += " = ";
635 text += Variant::get_type_name(type);
636 text += ".";
637 text += _global_names_ptr[_code_ptr[ip + 2 + instr_var_args]].operator String();
638 text += "(";
639
640 for (int i = 0; i < argc; i++) {
641 if (i > 0) {
642 text += ", ";
643 }
644 text += DADDR(1 + i);
645 }
646 text += ")";
647
648 incr += 5 + argc;
649 } break;
650 case OPCODE_CALL_NATIVE_STATIC: {
651 int instr_var_args = _code_ptr[++ip];
652 MethodBind *method = _methods_ptr[_code_ptr[ip + 1 + instr_var_args]];
653 int argc = _code_ptr[ip + 2 + instr_var_args];
654
655 text += "call native method static ";
656 text += DADDR(1 + argc);
657 text += " = ";
658 text += method->get_instance_class();
659 text += ".";
660 text += method->get_name();
661 text += "(";
662
663 for (int i = 0; i < argc; i++) {
664 if (i > 0) {
665 text += ", ";
666 }
667 text += DADDR(1 + i);
668 }
669 text += ")";
670
671 incr += 4 + argc;
672 } break;
673 case OPCODE_CALL_PTRCALL_NO_RETURN: {
674 int instr_var_args = _code_ptr[++ip];
675
676 text += "call-ptrcall (no return) ";
677
678 MethodBind *method = _methods_ptr[_code_ptr[ip + 2 + instr_var_args]];
679
680 int argc = _code_ptr[ip + 1 + instr_var_args];
681
682 text += DADDR(1 + argc) + ".";
683 text += method->get_name();
684 text += "(";
685
686 for (int i = 0; i < argc; i++) {
687 if (i > 0) {
688 text += ", ";
689 }
690 text += DADDR(1 + i);
691 }
692 text += ")";
693
694 incr = 5 + argc;
695 } break;
696
697#define DISASSEMBLE_PTRCALL(m_type) \
698 case OPCODE_CALL_PTRCALL_##m_type: { \
699 int instr_var_args = _code_ptr[++ip]; \
700 text += "call-ptrcall (return "; \
701 text += #m_type; \
702 text += ") "; \
703 MethodBind *method = _methods_ptr[_code_ptr[ip + 2 + instr_var_args]]; \
704 int argc = _code_ptr[ip + 1 + instr_var_args]; \
705 text += DADDR(2 + argc) + " = "; \
706 text += DADDR(1 + argc) + "."; \
707 text += method->get_name(); \
708 text += "("; \
709 for (int i = 0; i < argc; i++) { \
710 if (i > 0) \
711 text += ", "; \
712 text += DADDR(1 + i); \
713 } \
714 text += ")"; \
715 incr = 5 + argc; \
716 } break
717
718 DISASSEMBLE_PTRCALL(BOOL);
719 DISASSEMBLE_PTRCALL(INT);
720 DISASSEMBLE_PTRCALL(FLOAT);
721 DISASSEMBLE_PTRCALL(STRING);
722 DISASSEMBLE_PTRCALL(VECTOR2);
723 DISASSEMBLE_PTRCALL(VECTOR2I);
724 DISASSEMBLE_PTRCALL(RECT2);
725 DISASSEMBLE_PTRCALL(RECT2I);
726 DISASSEMBLE_PTRCALL(VECTOR3);
727 DISASSEMBLE_PTRCALL(VECTOR3I);
728 DISASSEMBLE_PTRCALL(TRANSFORM2D);
729 DISASSEMBLE_PTRCALL(VECTOR4);
730 DISASSEMBLE_PTRCALL(VECTOR4I);
731 DISASSEMBLE_PTRCALL(PLANE);
732 DISASSEMBLE_PTRCALL(AABB);
733 DISASSEMBLE_PTRCALL(BASIS);
734 DISASSEMBLE_PTRCALL(TRANSFORM3D);
735 DISASSEMBLE_PTRCALL(PROJECTION);
736 DISASSEMBLE_PTRCALL(COLOR);
737 DISASSEMBLE_PTRCALL(STRING_NAME);
738 DISASSEMBLE_PTRCALL(NODE_PATH);
739 DISASSEMBLE_PTRCALL(RID);
740 DISASSEMBLE_PTRCALL(QUATERNION);
741 DISASSEMBLE_PTRCALL(OBJECT);
742 DISASSEMBLE_PTRCALL(CALLABLE);
743 DISASSEMBLE_PTRCALL(SIGNAL);
744 DISASSEMBLE_PTRCALL(DICTIONARY);
745 DISASSEMBLE_PTRCALL(ARRAY);
746 DISASSEMBLE_PTRCALL(PACKED_BYTE_ARRAY);
747 DISASSEMBLE_PTRCALL(PACKED_INT32_ARRAY);
748 DISASSEMBLE_PTRCALL(PACKED_INT64_ARRAY);
749 DISASSEMBLE_PTRCALL(PACKED_FLOAT32_ARRAY);
750 DISASSEMBLE_PTRCALL(PACKED_FLOAT64_ARRAY);
751 DISASSEMBLE_PTRCALL(PACKED_STRING_ARRAY);
752 DISASSEMBLE_PTRCALL(PACKED_VECTOR2_ARRAY);
753 DISASSEMBLE_PTRCALL(PACKED_VECTOR3_ARRAY);
754 DISASSEMBLE_PTRCALL(PACKED_COLOR_ARRAY);
755
756 case OPCODE_CALL_BUILTIN_TYPE_VALIDATED: {
757 int instr_var_args = _code_ptr[++ip];
758 int argc = _code_ptr[ip + 1 + instr_var_args];
759
760 text += "call-builtin-method validated ";
761
762 text += DADDR(2 + argc) + " = ";
763
764 text += DADDR(1) + ".";
765 text += builtin_methods_names[_code_ptr[ip + 4 + argc]];
766
767 text += "(";
768
769 for (int i = 0; i < argc; i++) {
770 if (i > 0) {
771 text += ", ";
772 }
773 text += DADDR(1 + i);
774 }
775 text += ")";
776
777 incr = 5 + argc;
778 } break;
779 case OPCODE_CALL_UTILITY: {
780 int instr_var_args = _code_ptr[++ip];
781
782 text += "call-utility ";
783
784 int argc = _code_ptr[ip + 1 + instr_var_args];
785 text += DADDR(1 + argc) + " = ";
786
787 text += _global_names_ptr[_code_ptr[ip + 2 + instr_var_args]];
788 text += "(";
789
790 for (int i = 0; i < argc; i++) {
791 if (i > 0) {
792 text += ", ";
793 }
794 text += DADDR(1 + i);
795 }
796 text += ")";
797
798 incr = 4 + argc;
799 } break;
800 case OPCODE_CALL_UTILITY_VALIDATED: {
801 int instr_var_args = _code_ptr[++ip];
802
803 text += "call-utility validated ";
804
805 int argc = _code_ptr[ip + 1 + instr_var_args];
806 text += DADDR(1 + argc) + " = ";
807
808 text += utilities_names[_code_ptr[ip + 3 + argc]];
809 text += "(";
810
811 for (int i = 0; i < argc; i++) {
812 if (i > 0) {
813 text += ", ";
814 }
815 text += DADDR(1 + i);
816 }
817 text += ")";
818
819 incr = 4 + argc;
820 } break;
821 case OPCODE_CALL_GDSCRIPT_UTILITY: {
822 int instr_var_args = _code_ptr[++ip];
823
824 text += "call-gdscript-utility ";
825
826 int argc = _code_ptr[ip + 1 + instr_var_args];
827 text += DADDR(1 + argc) + " = ";
828
829 text += gds_utilities_names[_code_ptr[ip + 3 + argc]];
830 text += "(";
831
832 for (int i = 0; i < argc; i++) {
833 if (i > 0) {
834 text += ", ";
835 }
836 text += DADDR(1 + i);
837 }
838 text += ")";
839
840 incr = 4 + argc;
841 } break;
842 case OPCODE_CALL_SELF_BASE: {
843 int instr_var_args = _code_ptr[++ip];
844
845 text += "call-self-base ";
846
847 int argc = _code_ptr[ip + 1 + instr_var_args];
848 text += DADDR(2 + argc) + " = ";
849
850 text += _global_names_ptr[_code_ptr[ip + 2 + instr_var_args]];
851 text += "(";
852
853 for (int i = 0; i < argc; i++) {
854 if (i > 0) {
855 text += ", ";
856 }
857 text += DADDR(1 + i);
858 }
859 text += ")";
860
861 incr = 4 + argc;
862 } break;
863 case OPCODE_AWAIT: {
864 text += "await ";
865 text += DADDR(1);
866
867 incr = 2;
868 } break;
869 case OPCODE_AWAIT_RESUME: {
870 text += "await resume ";
871 text += DADDR(1);
872
873 incr = 2;
874 } break;
875 case OPCODE_CREATE_LAMBDA: {
876 int instr_var_args = _code_ptr[++ip];
877 int captures_count = _code_ptr[ip + 1 + instr_var_args];
878 GDScriptFunction *lambda = _lambdas_ptr[_code_ptr[ip + 2 + instr_var_args]];
879
880 text += DADDR(1 + captures_count);
881 text += "create lambda from ";
882 text += lambda->name.operator String();
883 text += "function, captures (";
884
885 for (int i = 0; i < captures_count; i++) {
886 if (i > 0) {
887 text += ", ";
888 }
889 text += DADDR(1 + i);
890 }
891 text += ")";
892
893 incr = 4 + captures_count;
894 } break;
895 case OPCODE_CREATE_SELF_LAMBDA: {
896 int instr_var_args = _code_ptr[++ip];
897 int captures_count = _code_ptr[ip + 1 + instr_var_args];
898 GDScriptFunction *lambda = _lambdas_ptr[_code_ptr[ip + 2 + instr_var_args]];
899
900 text += DADDR(1 + captures_count);
901 text += "create self lambda from ";
902 text += lambda->name.operator String();
903 text += "function, captures (";
904
905 for (int i = 0; i < captures_count; i++) {
906 if (i > 0) {
907 text += ", ";
908 }
909 text += DADDR(1 + i);
910 }
911 text += ")";
912
913 incr = 4 + captures_count;
914 } break;
915 case OPCODE_JUMP: {
916 text += "jump ";
917 text += itos(_code_ptr[ip + 1]);
918
919 incr = 2;
920 } break;
921 case OPCODE_JUMP_IF: {
922 text += "jump-if ";
923 text += DADDR(1);
924 text += " to ";
925 text += itos(_code_ptr[ip + 2]);
926
927 incr = 3;
928 } break;
929 case OPCODE_JUMP_IF_NOT: {
930 text += "jump-if-not ";
931 text += DADDR(1);
932 text += " to ";
933 text += itos(_code_ptr[ip + 2]);
934
935 incr = 3;
936 } break;
937 case OPCODE_JUMP_TO_DEF_ARGUMENT: {
938 text += "jump-to-default-argument ";
939
940 incr = 1;
941 } break;
942 case OPCODE_JUMP_IF_SHARED: {
943 text += "jump-if-shared ";
944 text += DADDR(1);
945 text += " to ";
946 text += itos(_code_ptr[ip + 2]);
947
948 incr = 3;
949 } break;
950 case OPCODE_RETURN: {
951 text += "return ";
952 text += DADDR(1);
953
954 incr = 2;
955 } break;
956 case OPCODE_RETURN_TYPED_BUILTIN: {
957 text += "return typed builtin (";
958 text += Variant::get_type_name((Variant::Type)_code_ptr[ip + 2]);
959 text += ") ";
960 text += DADDR(1);
961
962 incr += 3;
963 } break;
964 case OPCODE_RETURN_TYPED_ARRAY: {
965 text += "return typed array ";
966 text += DADDR(1);
967
968 incr += 5;
969 } break;
970 case OPCODE_RETURN_TYPED_NATIVE: {
971 text += "return typed native (";
972 text += DADDR(2);
973 text += ") ";
974 text += DADDR(1);
975
976 incr += 3;
977 } break;
978 case OPCODE_RETURN_TYPED_SCRIPT: {
979 Ref<Script> script = get_constant(_code_ptr[ip + 2] & ADDR_MASK);
980
981 text += "return typed script (";
982 text += GDScript::debug_get_script_name(script);
983 text += ") ";
984 text += DADDR(1);
985
986 incr += 3;
987 } break;
988
989#define DISASSEMBLE_ITERATE(m_type) \
990 case OPCODE_ITERATE_##m_type: { \
991 text += "for-loop (typed "; \
992 text += #m_type; \
993 text += ") "; \
994 text += DADDR(3); \
995 text += " in "; \
996 text += DADDR(2); \
997 text += " counter "; \
998 text += DADDR(1); \
999 text += " end "; \
1000 text += itos(_code_ptr[ip + 4]); \
1001 incr += 5; \
1002 } break
1003
1004#define DISASSEMBLE_ITERATE_BEGIN(m_type) \
1005 case OPCODE_ITERATE_BEGIN_##m_type: { \
1006 text += "for-init (typed "; \
1007 text += #m_type; \
1008 text += ") "; \
1009 text += DADDR(3); \
1010 text += " in "; \
1011 text += DADDR(2); \
1012 text += " counter "; \
1013 text += DADDR(1); \
1014 text += " end "; \
1015 text += itos(_code_ptr[ip + 4]); \
1016 incr += 5; \
1017 } break
1018
1019#define DISASSEMBLE_ITERATE_TYPES(m_macro) \
1020 m_macro(INT); \
1021 m_macro(FLOAT); \
1022 m_macro(VECTOR2); \
1023 m_macro(VECTOR2I); \
1024 m_macro(VECTOR3); \
1025 m_macro(VECTOR3I); \
1026 m_macro(STRING); \
1027 m_macro(DICTIONARY); \
1028 m_macro(ARRAY); \
1029 m_macro(PACKED_BYTE_ARRAY); \
1030 m_macro(PACKED_INT32_ARRAY); \
1031 m_macro(PACKED_INT64_ARRAY); \
1032 m_macro(PACKED_FLOAT32_ARRAY); \
1033 m_macro(PACKED_FLOAT64_ARRAY); \
1034 m_macro(PACKED_STRING_ARRAY); \
1035 m_macro(PACKED_VECTOR2_ARRAY); \
1036 m_macro(PACKED_VECTOR3_ARRAY); \
1037 m_macro(PACKED_COLOR_ARRAY); \
1038 m_macro(OBJECT)
1039
1040 case OPCODE_ITERATE_BEGIN: {
1041 text += "for-init ";
1042 text += DADDR(3);
1043 text += " in ";
1044 text += DADDR(2);
1045 text += " counter ";
1046 text += DADDR(1);
1047 text += " end ";
1048 text += itos(_code_ptr[ip + 4]);
1049
1050 incr += 5;
1051 } break;
1052 DISASSEMBLE_ITERATE_TYPES(DISASSEMBLE_ITERATE_BEGIN);
1053 case OPCODE_ITERATE: {
1054 text += "for-loop ";
1055 text += DADDR(2);
1056 text += " in ";
1057 text += DADDR(2);
1058 text += " counter ";
1059 text += DADDR(1);
1060 text += " end ";
1061 text += itos(_code_ptr[ip + 4]);
1062
1063 incr += 5;
1064 } break;
1065 DISASSEMBLE_ITERATE_TYPES(DISASSEMBLE_ITERATE);
1066 case OPCODE_STORE_GLOBAL: {
1067 text += "store global ";
1068 text += DADDR(1);
1069 text += " = ";
1070 text += String::num_int64(_code_ptr[ip + 2]);
1071
1072 incr += 3;
1073 } break;
1074 case OPCODE_STORE_NAMED_GLOBAL: {
1075 text += "store named global ";
1076 text += DADDR(1);
1077 text += " = ";
1078 text += String(_global_names_ptr[_code_ptr[ip + 2]]);
1079
1080 incr += 3;
1081 } break;
1082 case OPCODE_LINE: {
1083 int line = _code_ptr[ip + 1] - 1;
1084 if (line >= 0 && line < p_code_lines.size()) {
1085 text += "line ";
1086 text += itos(line + 1);
1087 text += ": ";
1088 text += p_code_lines[line];
1089 } else {
1090 text += "";
1091 }
1092
1093 incr += 2;
1094 } break;
1095
1096#define DISASSEMBLE_TYPE_ADJUST(m_v_type) \
1097 case OPCODE_TYPE_ADJUST_##m_v_type: { \
1098 text += "type adjust ("; \
1099 text += #m_v_type; \
1100 text += ") "; \
1101 text += DADDR(1); \
1102 incr += 2; \
1103 } break
1104
1105 DISASSEMBLE_TYPE_ADJUST(BOOL);
1106 DISASSEMBLE_TYPE_ADJUST(INT);
1107 DISASSEMBLE_TYPE_ADJUST(FLOAT);
1108 DISASSEMBLE_TYPE_ADJUST(STRING);
1109 DISASSEMBLE_TYPE_ADJUST(VECTOR2);
1110 DISASSEMBLE_TYPE_ADJUST(VECTOR2I);
1111 DISASSEMBLE_TYPE_ADJUST(RECT2);
1112 DISASSEMBLE_TYPE_ADJUST(RECT2I);
1113 DISASSEMBLE_TYPE_ADJUST(VECTOR3);
1114 DISASSEMBLE_TYPE_ADJUST(VECTOR3I);
1115 DISASSEMBLE_TYPE_ADJUST(TRANSFORM2D);
1116 DISASSEMBLE_TYPE_ADJUST(VECTOR4);
1117 DISASSEMBLE_TYPE_ADJUST(VECTOR4I);
1118 DISASSEMBLE_TYPE_ADJUST(PLANE);
1119 DISASSEMBLE_TYPE_ADJUST(QUATERNION);
1120 DISASSEMBLE_TYPE_ADJUST(AABB);
1121 DISASSEMBLE_TYPE_ADJUST(BASIS);
1122 DISASSEMBLE_TYPE_ADJUST(TRANSFORM3D);
1123 DISASSEMBLE_TYPE_ADJUST(PROJECTION);
1124 DISASSEMBLE_TYPE_ADJUST(COLOR);
1125 DISASSEMBLE_TYPE_ADJUST(STRING_NAME);
1126 DISASSEMBLE_TYPE_ADJUST(NODE_PATH);
1127 DISASSEMBLE_TYPE_ADJUST(RID);
1128 DISASSEMBLE_TYPE_ADJUST(OBJECT);
1129 DISASSEMBLE_TYPE_ADJUST(CALLABLE);
1130 DISASSEMBLE_TYPE_ADJUST(SIGNAL);
1131 DISASSEMBLE_TYPE_ADJUST(DICTIONARY);
1132 DISASSEMBLE_TYPE_ADJUST(ARRAY);
1133 DISASSEMBLE_TYPE_ADJUST(PACKED_BYTE_ARRAY);
1134 DISASSEMBLE_TYPE_ADJUST(PACKED_INT32_ARRAY);
1135 DISASSEMBLE_TYPE_ADJUST(PACKED_INT64_ARRAY);
1136 DISASSEMBLE_TYPE_ADJUST(PACKED_FLOAT32_ARRAY);
1137 DISASSEMBLE_TYPE_ADJUST(PACKED_FLOAT64_ARRAY);
1138 DISASSEMBLE_TYPE_ADJUST(PACKED_STRING_ARRAY);
1139 DISASSEMBLE_TYPE_ADJUST(PACKED_VECTOR2_ARRAY);
1140 DISASSEMBLE_TYPE_ADJUST(PACKED_VECTOR3_ARRAY);
1141 DISASSEMBLE_TYPE_ADJUST(PACKED_COLOR_ARRAY);
1142
1143 case OPCODE_ASSERT: {
1144 text += "assert (";
1145 text += DADDR(1);
1146 text += ", ";
1147 text += DADDR(2);
1148 text += ")";
1149
1150 incr += 3;
1151 } break;
1152 case OPCODE_BREAKPOINT: {
1153 text += "breakpoint";
1154
1155 incr += 1;
1156 } break;
1157 case OPCODE_END: {
1158 text += "== END ==";
1159
1160 incr += 1;
1161 } break;
1162 }
1163
1164 ip += incr;
1165 if (text.get_string_length() > 0) {
1166 print_line(text.as_string());
1167 }
1168 }
1169}
1170
1171#endif // DEBUG_ENABLED
1172