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 | |
38 | static 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 | |
73 | static 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 | |
100 | void 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 | |