1/**************************************************************************/
2/* gdscript_byte_codegen.h */
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#ifndef GDSCRIPT_BYTE_CODEGEN_H
32#define GDSCRIPT_BYTE_CODEGEN_H
33
34#include "gdscript_codegen.h"
35#include "gdscript_function.h"
36#include "gdscript_utility_functions.h"
37
38class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
39 struct StackSlot {
40 Variant::Type type = Variant::NIL;
41 Vector<int> bytecode_indices;
42
43 StackSlot() = default;
44 StackSlot(Variant::Type p_type) :
45 type(p_type) {}
46 };
47
48 const static int RESERVED_STACK = 3; // For self, class, and nil.
49
50 struct CallTarget {
51 Address target;
52 bool is_new_temporary = false;
53 GDScriptByteCodeGenerator *codegen = nullptr;
54#ifdef DEV_ENABLED
55 bool cleaned = false;
56#endif
57
58 void cleanup() {
59 DEV_ASSERT(!cleaned);
60 if (is_new_temporary) {
61 codegen->pop_temporary();
62 }
63#ifdef DEV_ENABLED
64 cleaned = true;
65#endif
66 }
67
68 CallTarget(Address p_target, bool p_is_new_temporary, GDScriptByteCodeGenerator *p_codegen) :
69 target(p_target),
70 is_new_temporary(p_is_new_temporary),
71 codegen(p_codegen) {}
72 ~CallTarget() { DEV_ASSERT(cleaned); }
73 CallTarget(const CallTarget &) = delete;
74 CallTarget &operator=(CallTarget &) = delete;
75 };
76
77 bool ended = false;
78 GDScriptFunction *function = nullptr;
79 bool debug_stack = false;
80
81 Vector<int> opcodes;
82 List<RBMap<StringName, int>> stack_id_stack;
83 RBMap<StringName, int> stack_identifiers;
84 List<int> stack_identifiers_counts;
85 RBMap<StringName, int> local_constants;
86
87 Vector<StackSlot> locals;
88 Vector<StackSlot> temporaries;
89 List<int> used_temporaries;
90 List<int> temporaries_pending_clear;
91 RBMap<Variant::Type, List<int>> temporaries_pool;
92
93 List<GDScriptFunction::StackDebug> stack_debug;
94 List<RBMap<StringName, int>> block_identifier_stack;
95 RBMap<StringName, int> block_identifiers;
96
97 int max_locals = 0;
98 int current_line = 0;
99 int instr_args_max = 0;
100 int ptrcall_max = 0;
101
102#ifdef DEBUG_ENABLED
103 List<int> temp_stack;
104#endif
105
106 HashMap<Variant, int, VariantHasher, VariantComparator> constant_map;
107 RBMap<StringName, int> name_map;
108#ifdef TOOLS_ENABLED
109 Vector<StringName> named_globals;
110#endif
111 RBMap<Variant::ValidatedOperatorEvaluator, int> operator_func_map;
112 RBMap<Variant::ValidatedSetter, int> setters_map;
113 RBMap<Variant::ValidatedGetter, int> getters_map;
114 RBMap<Variant::ValidatedKeyedSetter, int> keyed_setters_map;
115 RBMap<Variant::ValidatedKeyedGetter, int> keyed_getters_map;
116 RBMap<Variant::ValidatedIndexedSetter, int> indexed_setters_map;
117 RBMap<Variant::ValidatedIndexedGetter, int> indexed_getters_map;
118 RBMap<Variant::ValidatedBuiltInMethod, int> builtin_method_map;
119 RBMap<Variant::ValidatedConstructor, int> constructors_map;
120 RBMap<Variant::ValidatedUtilityFunction, int> utilities_map;
121 RBMap<GDScriptUtilityFunctions::FunctionPtr, int> gds_utilities_map;
122 RBMap<MethodBind *, int> method_bind_map;
123 RBMap<GDScriptFunction *, int> lambdas_map;
124
125#if DEBUG_ENABLED
126 // Keep method and property names for pointer and validated operations.
127 // Used when disassembling the bytecode.
128 Vector<String> operator_names;
129 Vector<String> setter_names;
130 Vector<String> getter_names;
131 Vector<String> builtin_methods_names;
132 Vector<String> constructors_names;
133 Vector<String> utilities_names;
134 Vector<String> gds_utilities_names;
135 void add_debug_name(Vector<String> &vector, int index, const String &name) {
136 if (index >= vector.size()) {
137 vector.resize(index + 1);
138 }
139 vector.write[index] = name;
140 }
141#endif
142
143 // Lists since these can be nested.
144 List<int> if_jmp_addrs;
145 List<int> for_jmp_addrs;
146 List<Address> for_counter_variables;
147 List<Address> for_container_variables;
148 List<int> while_jmp_addrs;
149 List<int> continue_addrs;
150
151 // Used to patch jumps with `and` and `or` operators with short-circuit.
152 List<int> logic_op_jump_pos1;
153 List<int> logic_op_jump_pos2;
154
155 List<Address> ternary_result;
156 List<int> ternary_jump_fail_pos;
157 List<int> ternary_jump_skip_pos;
158
159 List<List<int>> current_breaks_to_patch;
160
161 void add_stack_identifier(const StringName &p_id, int p_stackpos) {
162 if (locals.size() > max_locals) {
163 max_locals = locals.size();
164 }
165 stack_identifiers[p_id] = p_stackpos;
166 if (debug_stack) {
167 block_identifiers[p_id] = p_stackpos;
168 GDScriptFunction::StackDebug sd;
169 sd.added = true;
170 sd.line = current_line;
171 sd.identifier = p_id;
172 sd.pos = p_stackpos;
173 stack_debug.push_back(sd);
174 }
175 }
176
177 void push_stack_identifiers() {
178 stack_identifiers_counts.push_back(locals.size());
179 stack_id_stack.push_back(stack_identifiers);
180 if (debug_stack) {
181 RBMap<StringName, int> block_ids(block_identifiers);
182 block_identifier_stack.push_back(block_ids);
183 block_identifiers.clear();
184 }
185 }
186
187 void pop_stack_identifiers() {
188 int current_locals = stack_identifiers_counts.back()->get();
189 stack_identifiers_counts.pop_back();
190 stack_identifiers = stack_id_stack.back()->get();
191 stack_id_stack.pop_back();
192#ifdef DEBUG_ENABLED
193 if (!used_temporaries.is_empty()) {
194 ERR_PRINT("Leaving block with non-zero temporary variables: " + itos(used_temporaries.size()));
195 }
196#endif
197 locals.resize(current_locals);
198 if (debug_stack) {
199 for (const KeyValue<StringName, int> &E : block_identifiers) {
200 GDScriptFunction::StackDebug sd;
201 sd.added = false;
202 sd.identifier = E.key;
203 sd.line = current_line;
204 sd.pos = E.value;
205 stack_debug.push_back(sd);
206 }
207 block_identifiers = block_identifier_stack.back()->get();
208 block_identifier_stack.pop_back();
209 }
210 }
211
212 int get_name_map_pos(const StringName &p_identifier) {
213 int ret;
214 if (!name_map.has(p_identifier)) {
215 ret = name_map.size();
216 name_map[p_identifier] = ret;
217 } else {
218 ret = name_map[p_identifier];
219 }
220 return ret;
221 }
222
223 int get_constant_pos(const Variant &p_constant) {
224 if (constant_map.has(p_constant)) {
225 return constant_map[p_constant];
226 }
227 int pos = constant_map.size();
228 constant_map[p_constant] = pos;
229 return pos;
230 }
231
232 int get_operation_pos(const Variant::ValidatedOperatorEvaluator p_operation) {
233 if (operator_func_map.has(p_operation)) {
234 return operator_func_map[p_operation];
235 }
236 int pos = operator_func_map.size();
237 operator_func_map[p_operation] = pos;
238 return pos;
239 }
240
241 int get_setter_pos(const Variant::ValidatedSetter p_setter) {
242 if (setters_map.has(p_setter)) {
243 return setters_map[p_setter];
244 }
245 int pos = setters_map.size();
246 setters_map[p_setter] = pos;
247 return pos;
248 }
249
250 int get_getter_pos(const Variant::ValidatedGetter p_getter) {
251 if (getters_map.has(p_getter)) {
252 return getters_map[p_getter];
253 }
254 int pos = getters_map.size();
255 getters_map[p_getter] = pos;
256 return pos;
257 }
258
259 int get_keyed_setter_pos(const Variant::ValidatedKeyedSetter p_keyed_setter) {
260 if (keyed_setters_map.has(p_keyed_setter)) {
261 return keyed_setters_map[p_keyed_setter];
262 }
263 int pos = keyed_setters_map.size();
264 keyed_setters_map[p_keyed_setter] = pos;
265 return pos;
266 }
267
268 int get_keyed_getter_pos(const Variant::ValidatedKeyedGetter p_keyed_getter) {
269 if (keyed_getters_map.has(p_keyed_getter)) {
270 return keyed_getters_map[p_keyed_getter];
271 }
272 int pos = keyed_getters_map.size();
273 keyed_getters_map[p_keyed_getter] = pos;
274 return pos;
275 }
276
277 int get_indexed_setter_pos(const Variant::ValidatedIndexedSetter p_indexed_setter) {
278 if (indexed_setters_map.has(p_indexed_setter)) {
279 return indexed_setters_map[p_indexed_setter];
280 }
281 int pos = indexed_setters_map.size();
282 indexed_setters_map[p_indexed_setter] = pos;
283 return pos;
284 }
285
286 int get_indexed_getter_pos(const Variant::ValidatedIndexedGetter p_indexed_getter) {
287 if (indexed_getters_map.has(p_indexed_getter)) {
288 return indexed_getters_map[p_indexed_getter];
289 }
290 int pos = indexed_getters_map.size();
291 indexed_getters_map[p_indexed_getter] = pos;
292 return pos;
293 }
294
295 int get_builtin_method_pos(const Variant::ValidatedBuiltInMethod p_method) {
296 if (builtin_method_map.has(p_method)) {
297 return builtin_method_map[p_method];
298 }
299 int pos = builtin_method_map.size();
300 builtin_method_map[p_method] = pos;
301 return pos;
302 }
303
304 int get_constructor_pos(const Variant::ValidatedConstructor p_constructor) {
305 if (constructors_map.has(p_constructor)) {
306 return constructors_map[p_constructor];
307 }
308 int pos = constructors_map.size();
309 constructors_map[p_constructor] = pos;
310 return pos;
311 }
312
313 int get_utility_pos(const Variant::ValidatedUtilityFunction p_utility) {
314 if (utilities_map.has(p_utility)) {
315 return utilities_map[p_utility];
316 }
317 int pos = utilities_map.size();
318 utilities_map[p_utility] = pos;
319 return pos;
320 }
321
322 int get_gds_utility_pos(const GDScriptUtilityFunctions::FunctionPtr p_gds_utility) {
323 if (gds_utilities_map.has(p_gds_utility)) {
324 return gds_utilities_map[p_gds_utility];
325 }
326 int pos = gds_utilities_map.size();
327 gds_utilities_map[p_gds_utility] = pos;
328 return pos;
329 }
330
331 int get_method_bind_pos(MethodBind *p_method) {
332 if (method_bind_map.has(p_method)) {
333 return method_bind_map[p_method];
334 }
335 int pos = method_bind_map.size();
336 method_bind_map[p_method] = pos;
337 return pos;
338 }
339
340 int get_lambda_function_pos(GDScriptFunction *p_lambda_function) {
341 if (lambdas_map.has(p_lambda_function)) {
342 return lambdas_map[p_lambda_function];
343 }
344 int pos = lambdas_map.size();
345 lambdas_map[p_lambda_function] = pos;
346 return pos;
347 }
348
349 void alloc_ptrcall(int p_params) {
350 if (p_params >= ptrcall_max) {
351 ptrcall_max = p_params;
352 }
353 }
354
355 CallTarget get_call_target(const Address &p_target, Variant::Type p_type = Variant::NIL);
356
357 int address_of(const Address &p_address) {
358 switch (p_address.mode) {
359 case Address::SELF:
360 return GDScriptFunction::ADDR_SELF;
361 case Address::CLASS:
362 return GDScriptFunction::ADDR_CLASS;
363 case Address::MEMBER:
364 return p_address.address | (GDScriptFunction::ADDR_TYPE_MEMBER << GDScriptFunction::ADDR_BITS);
365 case Address::CONSTANT:
366 return p_address.address | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
367 case Address::LOCAL_VARIABLE:
368 case Address::FUNCTION_PARAMETER:
369 return p_address.address | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
370 case Address::TEMPORARY:
371 temporaries.write[p_address.address].bytecode_indices.push_back(opcodes.size());
372 return -1;
373 case Address::NIL:
374 return GDScriptFunction::ADDR_NIL;
375 }
376 return -1; // Unreachable.
377 }
378
379 void append_opcode(GDScriptFunction::Opcode p_code) {
380 opcodes.push_back(p_code);
381 }
382
383 void append_opcode_and_argcount(GDScriptFunction::Opcode p_code, int p_argument_count) {
384 opcodes.push_back(p_code);
385 opcodes.push_back(p_argument_count);
386 instr_args_max = MAX(instr_args_max, p_argument_count);
387 }
388
389 void append(int p_code) {
390 opcodes.push_back(p_code);
391 }
392
393 void append(const Address &p_address) {
394 opcodes.push_back(address_of(p_address));
395 }
396
397 void append(const StringName &p_name) {
398 opcodes.push_back(get_name_map_pos(p_name));
399 }
400
401 void append(const Variant::ValidatedOperatorEvaluator p_operation) {
402 opcodes.push_back(get_operation_pos(p_operation));
403 }
404
405 void append(const Variant::ValidatedSetter p_setter) {
406 opcodes.push_back(get_setter_pos(p_setter));
407 }
408
409 void append(const Variant::ValidatedGetter p_getter) {
410 opcodes.push_back(get_getter_pos(p_getter));
411 }
412
413 void append(const Variant::ValidatedKeyedSetter p_keyed_setter) {
414 opcodes.push_back(get_keyed_setter_pos(p_keyed_setter));
415 }
416
417 void append(const Variant::ValidatedKeyedGetter p_keyed_getter) {
418 opcodes.push_back(get_keyed_getter_pos(p_keyed_getter));
419 }
420
421 void append(const Variant::ValidatedIndexedSetter p_indexed_setter) {
422 opcodes.push_back(get_indexed_setter_pos(p_indexed_setter));
423 }
424
425 void append(const Variant::ValidatedIndexedGetter p_indexed_getter) {
426 opcodes.push_back(get_indexed_getter_pos(p_indexed_getter));
427 }
428
429 void append(const Variant::ValidatedBuiltInMethod p_method) {
430 opcodes.push_back(get_builtin_method_pos(p_method));
431 }
432
433 void append(const Variant::ValidatedConstructor p_constructor) {
434 opcodes.push_back(get_constructor_pos(p_constructor));
435 }
436
437 void append(const Variant::ValidatedUtilityFunction p_utility) {
438 opcodes.push_back(get_utility_pos(p_utility));
439 }
440
441 void append(const GDScriptUtilityFunctions::FunctionPtr p_gds_utility) {
442 opcodes.push_back(get_gds_utility_pos(p_gds_utility));
443 }
444
445 void append(MethodBind *p_method) {
446 opcodes.push_back(get_method_bind_pos(p_method));
447 }
448
449 void append(GDScriptFunction *p_lambda_function) {
450 opcodes.push_back(get_lambda_function_pos(p_lambda_function));
451 }
452
453 void patch_jump(int p_address) {
454 opcodes.write[p_address] = opcodes.size();
455 }
456
457public:
458 virtual uint32_t add_parameter(const StringName &p_name, bool p_is_optional, const GDScriptDataType &p_type) override;
459 virtual uint32_t add_local(const StringName &p_name, const GDScriptDataType &p_type) override;
460 virtual uint32_t add_local_constant(const StringName &p_name, const Variant &p_constant) override;
461 virtual uint32_t add_or_get_constant(const Variant &p_constant) override;
462 virtual uint32_t add_or_get_name(const StringName &p_name) override;
463 virtual uint32_t add_temporary(const GDScriptDataType &p_type) override;
464 virtual void pop_temporary() override;
465 virtual void clean_temporaries() override;
466
467 virtual void start_parameters() override;
468 virtual void end_parameters() override;
469
470 virtual void start_block() override;
471 virtual void end_block() override;
472
473 virtual void write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, Variant p_rpc_config, const GDScriptDataType &p_return_type) override;
474 virtual GDScriptFunction *write_end() override;
475
476#ifdef DEBUG_ENABLED
477 virtual void set_signature(const String &p_signature) override;
478#endif
479 virtual void set_initial_line(int p_line) override;
480
481 virtual void write_type_adjust(const Address &p_target, Variant::Type p_new_type) override;
482 virtual void write_unary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand) override;
483 virtual void write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) override;
484 virtual void write_type_test(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) override;
485 virtual void write_and_left_operand(const Address &p_left_operand) override;
486 virtual void write_and_right_operand(const Address &p_right_operand) override;
487 virtual void write_end_and(const Address &p_target) override;
488 virtual void write_or_left_operand(const Address &p_left_operand) override;
489 virtual void write_or_right_operand(const Address &p_right_operand) override;
490 virtual void write_end_or(const Address &p_target) override;
491 virtual void write_start_ternary(const Address &p_target) override;
492 virtual void write_ternary_condition(const Address &p_condition) override;
493 virtual void write_ternary_true_expr(const Address &p_expr) override;
494 virtual void write_ternary_false_expr(const Address &p_expr) override;
495 virtual void write_end_ternary() override;
496 virtual void write_set(const Address &p_target, const Address &p_index, const Address &p_source) override;
497 virtual void write_get(const Address &p_target, const Address &p_index, const Address &p_source) override;
498 virtual void write_set_named(const Address &p_target, const StringName &p_name, const Address &p_source) override;
499 virtual void write_get_named(const Address &p_target, const StringName &p_name, const Address &p_source) override;
500 virtual void write_set_member(const Address &p_value, const StringName &p_name) override;
501 virtual void write_get_member(const Address &p_target, const StringName &p_name) override;
502 virtual void write_set_static_variable(const Address &p_value, const Address &p_class, int p_index) override;
503 virtual void write_get_static_variable(const Address &p_target, const Address &p_class, int p_index) override;
504 virtual void write_assign(const Address &p_target, const Address &p_source) override;
505 virtual void write_assign_with_conversion(const Address &p_target, const Address &p_source) override;
506 virtual void write_assign_true(const Address &p_target) override;
507 virtual void write_assign_false(const Address &p_target) override;
508 virtual void write_assign_default_parameter(const Address &p_dst, const Address &p_src, bool p_use_conversion) override;
509 virtual void write_store_global(const Address &p_dst, int p_global_index) override;
510 virtual void write_store_named_global(const Address &p_dst, const StringName &p_global) override;
511 virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) override;
512 virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
513 virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
514 virtual void write_call_async(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
515 virtual void write_call_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) override;
516 void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, bool p_is_static, const Vector<Address> &p_arguments);
517 virtual void write_call_gdscript_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) override;
518 virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override;
519 virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override;
520 virtual void write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) override;
521 virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override;
522 virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override;
523 virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
524 virtual void write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
525 virtual void write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
526 virtual void write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures, bool p_use_self) override;
527 virtual void write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) override;
528 virtual void write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) override;
529 virtual void write_construct_typed_array(const Address &p_target, const GDScriptDataType &p_element_type, const Vector<Address> &p_arguments) override;
530 virtual void write_construct_dictionary(const Address &p_target, const Vector<Address> &p_arguments) override;
531 virtual void write_await(const Address &p_target, const Address &p_operand) override;
532 virtual void write_if(const Address &p_condition) override;
533 virtual void write_else() override;
534 virtual void write_endif() override;
535 virtual void write_jump_if_shared(const Address &p_value) override;
536 virtual void write_end_jump_if_shared() override;
537 virtual void start_for(const GDScriptDataType &p_iterator_type, const GDScriptDataType &p_list_type) override;
538 virtual void write_for_assignment(const Address &p_list) override;
539 virtual void write_for(const Address &p_variable, bool p_use_conversion) override;
540 virtual void write_endfor() override;
541 virtual void start_while_condition() override;
542 virtual void write_while(const Address &p_condition) override;
543 virtual void write_endwhile() override;
544 virtual void write_break() override;
545 virtual void write_continue() override;
546 virtual void write_breakpoint() override;
547 virtual void write_newline(int p_line) override;
548 virtual void write_return(const Address &p_return_value) override;
549 virtual void write_assert(const Address &p_test, const Address &p_message) override;
550
551 virtual ~GDScriptByteCodeGenerator();
552};
553
554#endif // GDSCRIPT_BYTE_CODEGEN_H
555