/[eiffelstudio]/branches/CAT_mono/Src/Eiffel/eiffel/byte_code/byte_context.e
ViewVC logotype

Contents of /branches/CAT_mono/Src/Eiffel/eiffel/byte_code/byte_context.e

Parent Directory Parent Directory | Revision Log Revision Log


Revision 69868 - (show annotations)
Fri Aug 3 22:28:26 2007 UTC (12 years, 4 months ago) by martins
File size: 64329 byte(s)
enabled more types to store monomorph information
1 indexing
2 legal: "See notice at end of class."
3 status: "See notice at end of class."
4 -- Context variables for code generation and utilities.
5
6 class BYTE_CONTEXT
7
8 inherit
9
10 SHARED_C_LEVEL
11 export
12 {NONE} all
13 {REGISTER}
14 c_nb_types
15 end
16
17 SHARED_TYPE_I
18 export
19 {NONE} all
20 end
21
22 ASSERT_TYPE
23 SHARED_ARRAY_BYTE
24 SHARED_SERVER
25 SHARED_GENERATION
26 COMPILER_EXPORTER
27 REFACTORING_HELPER
28
29 create
30 make, make_from_context
31
32 feature -- Initialization
33
34 make is
35 -- Initialization
36 do
37 create register_server.make (c_nb_types * 2)
38 create local_vars.make (1, 50)
39 create local_index_table.make (10)
40 create associated_register_table.make (10)
41 create local_list.make
42 create inherited_assertion.make
43 create global_onces.make (5)
44 create onces.make (5)
45 create once_manifest_string_count_table.make (100)
46 create once_manifest_string_table.make (100)
47 create {LINKED_STACK [PAIR [CLASS_TYPE, CLASS_TYPE]]} class_type_stack.make
48 create generated_inlines.make (5)
49 create generic_wrappers.make (0)
50 end
51
52 feature -- Access
53
54 workbench_mode: BOOLEAN
55 -- Mode of generation: if set to True, generation of C code
56 -- for the workbench otherwise generation of C code in final
57 -- mode
58
59 final_mode: BOOLEAN is
60 -- Is generation of C code for finalized mode?
61 do
62 Result := not workbench_mode
63 end
64
65 has_cpp_externals_calls: BOOLEAN
66 -- Does the current generated class have a C++ call?
67
68 current_feature: FEATURE_I
69 -- Current feature being processed.
70
71 original_body_index: INTEGER
72 -- Original body index of the current feature or class invariant
73
74 current_type: CL_TYPE_I
75 -- Current class type in which byte code is processed
76
77 class_type: CLASS_TYPE
78 -- Context class type with the code which we are generating
79 --| will be changed for assertion chaining, inlining, etc.
80
81 context_class_type: CLASS_TYPE
82 -- Class type for which the code is being generated;
83 -- it is changed for inlining
84
85 original_class_type: CLASS_TYPE
86 -- Class type we are generating
87
88 is_class_type_changed: BOOLEAN is
89 -- Is `class_type' changed to the type, unrelated to `original_class_type'?
90 -- (See also: `change_class_type_contrext'.)
91 do
92 Result := not class_type_stack.is_empty
93 ensure
94 definition: Result = not class_type_stack.is_empty
95 end
96
97 buffer: GENERATION_BUFFER
98 -- Buffer used for code generation
99
100 ext_inline_buffer: GENERATION_BUFFER
101 -- Buffer used for the generation of inlined externals
102
103 header_buffer: GENERATION_BUFFER
104 -- Buffer used for extern declaration generation
105
106 generated_inlines: SEARCH_TABLE [STRING]
107
108 inherited_assertion: INHERITED_ASSERTION
109 -- Used to record inherited assertions
110
111 byte_code: BYTE_CODE
112 -- Current root of processed byte code
113
114 local_vars: ARRAY [BOOLEAN]
115 -- Local variables used have their flag set to True.
116
117 local_index_table: HASH_TABLE [INTEGER, STRING]
118 -- Index in local variable array (C code) for a given register
119
120 associated_register_table: HASH_TABLE [REGISTRABLE, STRING]
121 -- Indexed by the same keys as `local_index_table', this associative
122 -- array maps a name into a registrable instance.
123
124 propagated: BOOLEAN
125 -- Was the propagated value caught ?
126
127 current_used: BOOLEAN
128 -- Is Current used (apart from dtype computation) ?
129
130 current_used_count: INTEGER
131 -- How many times current is used?
132
133 result_used: BOOLEAN
134 -- Is Result used (apart from very last assignment) ?
135
136 label: INTEGER
137 -- For label generation
138
139 dt_current: INTEGER
140 -- Number of time we need to compute Current's type
141
142 inlined_dt_current: INTEGER
143 -- Number of time we need to compute Current's type
144
145 dftype_current: INTEGER
146 -- Number of time we need to compute Current's full dynamic type
147
148 inlined_dftype_current: INTEGER
149 -- Number of time we need to compute Current's full dynamic type
150
151 local_index_counter: INTEGER
152 -- Index for local reference variables
153
154 assertion_type: INTEGER
155 -- Type of assertion being generated
156
157 saved_supplier_precondition: INTEGER
158 -- Number of the saved_supplier_precondition local.
159
160 origin_has_precondition: BOOLEAN
161 -- Is Current feature have origin feature with precondition?
162 -- (This is used for cases where the origin of the
163 -- routine does not have a precondition and thus
164 -- the precondition will always be True)
165
166 is_first_precondition_block_generated: BOOLEAN
167 -- Is generation of first precondition block generated?
168
169 is_new_precondition_block: BOOLEAN
170 -- Is this the start of a new precondition block?
171
172 is_argument_protected: BOOLEAN
173 -- Does current call need to protect some of its arguments?
174
175 copy_body_index: INTEGER
176 -- Body index of `copy' from ANY
177
178 twin_body_index: INTEGER
179 -- Body index of `twin' from ANY
180
181 feature -- Setting
182
183 set_first_precondition_block_generated (v: BOOLEAN) is
184 -- Set `il_external_creation' with `v'.
185 do
186 is_first_precondition_block_generated := v
187 ensure
188 is_first_precondition_block_generated_set: is_first_precondition_block_generated = v
189 end
190
191 set_new_precondition_block (v: BOOLEAN) is
192 -- Set `il_external_creation' with `v'.
193 do
194 is_new_precondition_block := v
195 ensure
196 is_new_precondition_block_set: is_new_precondition_block = v
197 end
198
199 set_is_argument_protected (v: BOOLEAN) is
200 -- Set `is_argument_protected' with `v'.
201 do
202 is_argument_protected := v
203 ensure
204 is_argument_protected_set: is_argument_protected = v
205 end
206
207 set_workbench_mode is
208 -- Set `workbench_mode' to True.
209 do
210 workbench_mode := True
211 ensure
212 workbench_mode_set: workbench_mode
213 end
214
215 set_final_mode is
216 -- Set `final_mode' to True.
217 do
218 workbench_mode := False
219 ensure
220 final_mode_set: final_mode
221 end
222
223 set_has_cpp_externals_calls (v: BOOLEAN) is
224 -- Set `has_cpp_externals_calls' with `v'.
225 do
226 has_cpp_externals_calls := v
227 ensure
228 has_cpp_externals_calls_set: has_cpp_externals_calls = v
229 end
230
231 set_buffer (b: like buffer) is
232 -- Assign `b' to `buffer'.
233 require
234 b_not_void: b /= Void
235 do
236 buffer := b
237 ensure
238 buffer_set: buffer = b
239 end
240
241 set_header_buffer (b: like header_buffer) is
242 -- Assign `b' to `header_buffer'.
243 require
244 b_not_void: b /= Void
245 do
246 header_buffer := b
247 ensure
248 header_buffer_set: header_buffer = b
249 end
250
251 set_assertion_type (a: INTEGER) is
252 -- Assign `a' to `assertion_type'
253 do
254 assertion_type := a
255 end
256
257 set_saved_supplier_precondition (s: INTEGER) is
258 -- Assign `s' to `saved_supplier_precondition'
259 do
260 saved_supplier_precondition := s
261 end
262
263 feature -- Code generation
264
265 generate_gen_type_conversion (gtype : GEN_TYPE_I) is
266 -- Generate code for converting type id arrays
267 -- into single id's.
268 require
269 valid_type : gtype /= Void
270 local
271 use_init : BOOLEAN
272 idx_cnt : COUNTER
273 l_buffer: like buffer
274 do
275 l_buffer := buffer
276 use_init := not gtype.is_explicit
277
278 -- Optimize: Use static array only when `typarr' is
279 -- not modified by generated code in multithreaded mode only.
280 -- It is safe in monothreaded code as we are guaranteed that
281 -- only one thread of execution will use the modified `typarr'.
282 if not System.has_multithreaded or else not use_init then
283 l_buffer.put_string ("static ")
284 end
285 l_buffer.put_string ("int16 typarr [] = {")
286
287 l_buffer.put_integer (current_type.generated_id (final_mode))
288 l_buffer.put_character (',')
289
290 if use_init then
291 create idx_cnt
292 idx_cnt.set_value (1)
293 gtype.generate_cid_array (l_buffer, final_mode, True, idx_cnt)
294 else
295 gtype.generate_cid (l_buffer, final_mode, True)
296 end
297 l_buffer.put_string ("-1};")
298 l_buffer.put_new_line
299 l_buffer.put_string ("int16 typres;")
300 l_buffer.put_new_line
301 if not use_init then
302 l_buffer.put_string ("static int16 typcache = -1;")
303 l_buffer.put_new_line
304 end
305 l_buffer.put_new_line
306
307 if use_init then
308 -- Reset counter
309 idx_cnt.set_value (1)
310 gtype.generate_cid_init (l_buffer, final_mode, True, idx_cnt)
311 end
312
313 if not use_init then
314 l_buffer.put_string ("typres = RTCID2(&typcache, ")
315 else
316 l_buffer.put_string ("typres = RTCID2(NULL, ")
317 end
318 generate_current_dftype
319 l_buffer.put_string (", ")
320 l_buffer.put_integer (gtype.generated_id (final_mode))
321 l_buffer.put_string (", typarr);")
322 l_buffer.put_new_line
323 l_buffer.put_new_line
324 end
325
326 feature {NONE} -- Once features: implementation
327
328 onces: HASH_TABLE [PAIR [TYPE_C, like thread_relative_once_index], INTEGER]
329 -- List result types and once indexes indexed by body indexes which represent all non-global onces
330 -- for current generated type or for the whole system in finalized mode
331
332 global_onces: like onces
333 -- List result types and once indexes indexed by body indexes which represent all global onces for current
334 -- generated type or for the whole system in finalized mode
335
336 add_once (storage: like onces; type: TYPE_C; code_index: INTEGER) is
337 -- Register once routine identified by its `code_index' with result type `type' in `storage'.
338 require
339 storage_not_void: storage /= Void
340 type_not_void: type /= Void
341 do
342 if not storage.has (code_index) then
343 -- Register new once
344 storage.put (create {PAIR [TYPE_C, INTEGER]}.make (type, storage.count), code_index)
345 end
346 end
347
348 feature -- C code generation: once features
349
350 is_once_call_optimized: BOOLEAN
351 -- Can call to a once routine be optimized by direct loading of its result from memory?
352
353 add_thread_relative_once (type: TYPE_C; code_index: INTEGER) is
354 -- Register thread-relative once routine identified by its `code_index' with result type `type'.
355 require
356 type_not_void: type /= Void
357 do
358 add_once (onces, type, code_index)
359 ensure
360 added: has_thread_relative_once (code_index)
361 end
362
363 add_process_relative_once (type: TYPE_C; code_index: INTEGER) is
364 -- Register process-relative once routine identified by its `code_index' with result type `type'.
365 require
366 type_not_void: type /= Void
367 do
368 add_once (global_onces, type, code_index)
369 end
370
371 has_thread_relative_once (code_index: INTEGER): BOOLEAN is
372 -- Is once feature with `code_index' registered?
373 do
374 Result := onces.has (code_index)
375 end
376
377 thread_relative_once_index (code_index: INTEGER): INTEGER is
378 -- Index of a once routine with `code_index' counted from 0
379 require
380 final_mode: final_mode
381 has: has_thread_relative_once (code_index)
382 do
383 Result := onces.item (code_index).second
384 end
385
386 generate_once_optimized_call_start (type_c: TYPE_C; code_index: INTEGER; is_process_relative: BOOLEAN; buf: like buffer) is
387 -- Generate beginning of optimized direct call to once routine of type `type_c' with given `code_index'
388 require
389 is_once_call_optimized: is_once_call_optimized
390 type_not_void: type_c /= Void
391 buffer_not_void: buf /= Void
392 do
393 if not System.has_multithreaded then
394 if type_c.is_void then
395 -- It is a once procedure
396 buf.put_string ("RTOSCP(")
397 else
398 -- It is a once function
399 buf.put_string ("RTOSCF(")
400 end
401 buf.put_integer (code_index)
402 elseif is_process_relative then
403 if type_c.is_void then
404 -- It is a once procedure
405 buf.put_string ("RTOPCP(")
406 else
407 -- It is a once function
408 buf.put_string ("RTOPCF(")
409 end
410 buf.put_integer (code_index)
411 else
412 if type_c.is_void then
413 -- It is a once procedure
414 buf.put_string ("RTOUCP(")
415 elseif type_c.is_pointer then
416 -- It is a once function returning reference
417 buf.put_string ("RTOUCR(")
418 else
419 -- It is a once function returning basic type
420 buf.put_string ("RTOUCB(")
421 buf.put_string (type_c.c_string)
422 buf.put_character (',')
423 end
424 -- Once routine might be not registered yet
425 -- Let's do it now
426 add_thread_relative_once (type_c, code_index)
427 buf.put_integer (thread_relative_once_index (code_index))
428 end
429 buf.put_character (',')
430 end
431
432 generate_once_data_definition (buf: like buffer) is
433 -- Generate definition of once data fields
434 require
435 buffer_not_void: buf /= Void
436 local
437 once_indexes: like onces
438 definition_macro_prefix: STRING
439 result_type: TYPE_C
440 do
441 if final_mode then
442 if system.has_multithreaded then
443 once_indexes := global_onces
444 definition_macro_prefix := "RTOPD"
445 else
446 once_indexes := onces
447 definition_macro_prefix := "RTOSD"
448 end
449 from
450 once_indexes.start
451 until
452 once_indexes.after
453 loop
454 buf.put_string (definition_macro_prefix)
455 result_type := once_indexes.item_for_iteration.first
456 if result_type.is_void then
457 buf.put_string ("P (")
458 else
459 buf.put_string ("F (")
460 buf.put_string (result_type.c_string)
461 buf.put_character (',')
462 end
463 buf.put_integer (once_indexes.key_for_iteration)
464 buf.put_character (')')
465 buf.put_new_line
466 once_indexes.forth
467 end
468 end
469 end
470
471 generate_module_once_data_initialization (static_type_id: INTEGER) is
472 -- Generate initialization of once data fields for type identified by `static_type_id'
473 require
474 buffer_not_void: buffer /= Void
475 local
476 buf: like buffer
477 once_indexes: like onces
478 do
479 if workbench_mode then
480 buf := buffer
481 -- Initialize indexes for single-threaded or thread-relative once routines
482 once_indexes := onces
483 from
484 once_indexes.start
485 until
486 once_indexes.after
487 loop
488 buf.put_string ("RTOTS (")
489 buf.put_integer (once_indexes.key_for_iteration)
490 buf.put_character (',')
491 buf.put_string (encoder.feature_name (static_type_id, once_indexes.key_for_iteration))
492 buf.put_character (')')
493 buf.put_new_line
494 once_indexes.forth
495 end
496 -- Initialize indexes for process-relative once routines
497 once_indexes := global_onces
498 from
499 once_indexes.start
500 until
501 once_indexes.after
502 loop
503 buf.put_string ("RTOQS (")
504 buf.put_integer (once_indexes.key_for_iteration)
505 buf.put_character (',')
506 buf.put_string (encoder.feature_name (static_type_id, once_indexes.key_for_iteration))
507 buf.put_character (')')
508 buf.put_new_line
509 once_indexes.forth
510 end
511 end
512 end
513
514 generate_system_once_data_initialization (buf: like buffer) is
515 -- Generate initialization of system-wide once data fields
516 require
517 buffer_not_void: buf /= Void
518 local
519 once_indexes: like onces
520 initialization_macro: STRING
521 do
522 if final_mode and then system.has_multithreaded then
523 -- Set number of thread-relative once routines
524 buf.put_string ("EIF_once_count = ")
525 buf.put_integer (onces.count)
526 buf.put_character (';')
527 buf.put_new_line
528 -- Initialize process-relative once routine fields
529 -- FIXME: Manu: 02/11/2003: Mutex are created but they are never freed,
530 -- thus a memory leak if upon program termination the system does not
531 -- get back the resources allocated for the mutex.
532 once_indexes := global_onces
533 initialization_macro := "RTOPI("
534 from
535 once_indexes.start
536 until
537 once_indexes.after
538 loop
539 buf.put_string (initialization_macro)
540 buf.put_integer (once_indexes.key_for_iteration)
541 buf.put_character (')')
542 buf.put_new_line
543 once_indexes.forth
544 end
545 end
546 end
547
548 feature {NONE} -- Access: once manifest strings
549
550 once_manifest_string_count_table: HASH_TABLE [INTEGER, INTEGER]
551 -- Number of once manifest strings to be allocated for the given routine body index;
552 -- actual for the whole system
553
554 once_manifest_string_table: HASH_TABLE [ARRAY [STRING], INTEGER]
555 -- Once manifest strings to be created for the given routine body index;
556 -- actual for the current class
557
558 feature -- Access: once manifest strings
559
560 is_static_system_data_safe: BOOLEAN is
561 -- Is it safe to use system data stored in system-wide static memory?
562 do
563 Result := final_mode and then not system.has_multithreaded
564 end
565
566 once_manifest_string_count: INTEGER is
567 -- Number of once manifest strings in current routine body
568 require
569 is_static_system_data_safe: is_static_system_data_safe
570 do
571 Result := once_manifest_string_count_table.item (original_body_index)
572 ensure
573 non_negative_result: Result >= 0
574 end
575
576 once_manifest_string_value (number: INTEGER): STRING is
577 -- Value of once manifest string `number' in current routine body
578 require
579 is_static_system_data_safe: is_static_system_data_safe
580 valid_number: number > 0 and then number <= once_manifest_string_count
581 local
582 routine_once_manifest_strings: ARRAY [STRING]
583 do
584 routine_once_manifest_strings := once_manifest_string_table.item (original_body_index)
585 if routine_once_manifest_strings /= Void then
586 Result := routine_once_manifest_strings.item (number)
587 end
588 end
589
590 generate_once_manifest_string_declaration (buf: like buffer) is
591 -- Generate declarations for once manifest strings.
592 require
593 buffer_not_void: buf /= Void
594 local
595 string_counts: like once_manifest_string_count_table
596 i: INTEGER
597 do
598 string_counts := once_manifest_string_count_table
599 from
600 string_counts.start
601 until
602 string_counts.off
603 loop
604 -- Declare one field for one routine body.
605 buf.put_string ("RTDOMS(")
606 buf.put_integer (string_counts.key_for_iteration - 1)
607 buf.put_character (',')
608 i := string_counts.item_for_iteration
609 buf.put_integer (i)
610 buf.put_character (')')
611 -- Set associated string values to NULL.
612 -- Objects will be created and assigned during module initialization.
613 buf.put_character ('=')
614 buf.put_character ('{')
615 from
616 until
617 i <= 0
618 loop
619 buf.put_string ("NULL")
620 i := i - 1
621 if i > 0 then
622 buffer.put_character (',')
623 end
624 end
625 buf.put_character ('}')
626 buf.put_character (';')
627 buf.put_new_line
628 string_counts.forth
629 end
630 end
631
632 generate_once_manifest_string_import (number: INTEGER) is
633 -- Generate extern declaration for `number' once manifest strings from current routine body.
634 require
635 non_negative_number: number >= 0
636 consistent_number:
637 is_static_system_data_safe and then once_manifest_string_count > 0 implies
638 once_manifest_string_count = number
639 local
640 buf: like buffer
641 do
642 if number > 0 and then is_static_system_data_safe then
643 -- Remember number of strings in current routine.
644 set_once_manifest_string_count (number)
645 -- Generate reference to once manifest string field
646 buf := buffer
647 buf.put_string ("RTEOMS(")
648 buf.put_integer (original_body_index - 1)
649 buf.put_character (',')
650 buf.put_integer (number)
651 buf.put_character (')')
652 buf.put_character (';')
653 buf.put_new_line
654 buf.put_new_line
655 end
656 ensure
657 once_manifest_string_count_set:
658 is_static_system_data_safe implies once_manifest_string_count = number
659 end
660
661 generate_once_manifest_string_allocation (number: INTEGER) is
662 -- Generate C code to allocate memory for once manifest strings in current routine body.
663 require
664 non_negative_number: number >= 0
665 consistent_number: is_static_system_data_safe implies once_manifest_string_count = number
666 local
667 buf: like buffer
668 do
669 if number > 0 and then not is_static_system_data_safe then
670 buf := buffer
671 buf.put_string ("RTAOMS(")
672 buf.put_integer (original_body_index - 1)
673 buf.put_character (',')
674 buf.put_integer (number)
675 buf.put_character (')')
676 buf.put_character (';')
677 buf.put_new_line
678 end
679 end
680
681 make_once_string_allocation_byte_code (ba: BYTE_ARRAY; number: INTEGER) is
682 -- Generate byte code to allocate memory for once manifest strings in current routine body.
683 require
684 byte_array_not_void: ba /= Void
685 non_negative_number: number >= 0
686 do
687 if number > 0 then
688 ba.append ({BYTE_CONST}.Bc_allocate_once_strings)
689 ba.append_integer (original_body_index - 1)
690 ba.append_integer (number)
691 end
692 end
693
694 generate_once_manifest_string_initialization is
695 -- Generate code to initialize once manifest strings.
696 local
697 buf: like buffer
698 class_once_manifest_strings: like once_manifest_string_table
699 routine_once_manifest_strings: ARRAY [STRING]
700 body_index: like original_body_index
701 i: INTEGER
702 value: STRING
703 do
704 buf := buffer
705 class_once_manifest_strings := once_manifest_string_table
706 from
707 class_once_manifest_strings.start
708 until
709 class_once_manifest_strings.off
710 loop
711 body_index := class_once_manifest_strings.key_for_iteration
712 routine_once_manifest_strings := class_once_manifest_strings.item_for_iteration
713 from
714 i := routine_once_manifest_strings.count
715 until
716 i <= 0
717 loop
718 value := routine_once_manifest_strings.item (i)
719 -- `value' is void when string appears in assertion that is not generated
720 if value /= Void then
721 -- RTPOMS is the macro used to create and store once manifest string
722 -- provided that it is not created and stored before
723 buf.put_string ("RTPOMS(")
724 buf.put_integer (body_index - 1)
725 buf.put_character (',')
726 buf.put_integer (i - 1)
727 buf.put_character (',')
728 buf.put_string_literal (value)
729 buf.put_character (',')
730 buf.put_integer (value.count)
731 buf.put_character(',')
732 buf.put_integer (value.hash_code)
733 buf.put_character (')')
734 buf.put_character (';')
735 buf.put_new_line
736 end
737 i := i - 1
738 end
739 class_once_manifest_strings.forth
740 end
741 end
742
743 register_once_manifest_string (value: STRING; number: INTEGER) is
744 -- Register that current routine body has once manifest string
745 -- with the given `number' of the given `value'.
746 require
747 is_static_system_data_safe: is_static_system_data_safe
748 non_void_value: value /= Void
749 valid_number: number > 0 and number <= once_manifest_string_count
750 same_if_registered:
751 once_manifest_string_value (number) /= Void implies
752 once_manifest_string_value (number) = value
753 local
754 index: like original_body_index
755 routine_once_manifest_strings: ARRAY [STRING]
756 do
757 index := original_body_index
758 routine_once_manifest_strings := once_manifest_string_table.item (index)
759 if routine_once_manifest_strings = Void then
760 create routine_once_manifest_strings.make (1, once_manifest_string_count)
761 once_manifest_string_table.force (routine_once_manifest_strings, index)
762 end
763 routine_once_manifest_strings.put (value, number)
764 ensure
765 registered: once_manifest_string_value (number) = value
766 end
767
768 feature {NONE} -- Setting: once manifest strings
769
770 set_once_manifest_string_count (number: INTEGER) is
771 -- Set number of once manifest strings in current routine body to `number'.
772 require
773 positive_number: number > 0
774 same_if_set: once_manifest_string_count > 0 implies once_manifest_string_count = number
775 do
776 once_manifest_string_count_table.force (number, original_body_index)
777 ensure
778 once_manifest_string_count_set: once_manifest_string_count = number
779 end
780
781 feature -- Registers
782
783 Current_register: REGISTRABLE is
784 -- An instance of Current register for local var index computation
785 do
786 Result := inlined_current_register
787 if Result = Void then
788 Result := Current_b
789 end
790 end
791
792 Current_b: CURRENT_BL is
793 once
794 create Result
795 end
796
797 Result_register: RESULT_B is
798 -- An instace of Result register for local var index computation
799 local
800 dummy: NONE_I
801 once
802 -- This hack is needed because of the special treatment of
803 -- the Result register in once functions. The Result is always
804 -- recorded in the GC by RTOC, so there is no need to get an
805 -- l[] variable from the GC hooks. Here we are going to call
806 -- the print_register function on Result_register,
807 -- and this has been carefully patched in RESULT_BL to handle
808 -- the once cases.
809 create dummy
810 create {RESULT_BL} Result.make (dummy)
811 end
812
813 get_argument_register (t: TYPE_C): REGISTER is
814 -- Get a new temporary register of type `t' to hold an argument
815 -- to passed to during a feature call
816 require
817 t_attached: t /= Void
818 valid_t: not t.is_void
819 do
820 create Result.make_with_level (t.level + (c_nb_types - 1))
821 ensure
822 Result_attached: Result /= Void
823 end
824
825 print_argument_register (r: REGISTER; buf: like buffer) is
826 -- Print a name of a register `r' to `buf'
827 require
828 r_attached: r /= Void
829 buf_attached: buf /= Void
830 do
831 put_register_name (r.level, r.regnum, buf)
832 buf.put_character ('x')
833 end
834
835 feature {BYTE_CONTEXT, REGISTER} -- Registers
836
837 register_server: REGISTER_SERVER
838 -- Register number server
839
840 feature {REGISTER} -- Registers
841
842 register_name (t: INTEGER; n: INTEGER): STRING is
843 -- Name of a temporary register number `n' of type `t'.
844 require
845 valid_t: 0 < t and t <= (c_nb_types - 1) * 2
846 positive_n: n > 0
847 do
848 Result := register_names [t].twin
849 Result.append_integer (n)
850 end
851
852 register_type (t: INTEGER): TYPE_C is
853 -- Type of register identified by `t'.
854 require
855 valid_t: 0 < t and t <= (c_nb_types - 1) * 2
856 local
857 i: INTEGER
858 do
859 i := t
860 if i >= c_nb_types then
861 i := i - (c_nb_types - 1)
862 end
863 inspect i
864 when c_uint8 then
865 Result := uint8_c_type
866 when c_uint16 then
867 Result := uint16_c_type
868 when c_uint32 then
869 Result := uint32_c_type
870 when c_uint64 then
871 Result := uint64_c_type
872 when c_int8 then
873 Result := int8_c_type
874 when c_int16 then
875 Result := int16_c_type
876 when c_int32 then
877 Result := int32_c_type
878 when c_int64 then
879 Result := int64_c_type
880 when c_ref then
881 Result := reference_c_type
882 when c_real32 then
883 Result := real32_c_type
884 when c_real64 then
885 Result := real64_c_type
886 when c_char then
887 Result := char_c_type
888 when c_wide_char then
889 Result := wide_char_c_type
890 when c_pointer then
891 Result := pointer_c_type
892 end
893 end
894
895 feature {NONE} -- Registers: implementation
896
897 put_register_name (t: INTEGER; n: INTEGER; buf: like buffer) is
898 -- Put name of a temporary register number `n' of type `t' into `buf'.
899 require
900 valid_t: 0 < t and t <= (c_nb_types - 1) * 2
901 positive_n: n > 0
902 buf_attached: buf /= Void
903 do
904 buf.put_string (register_names [t])
905 buf.put_integer (n)
906 end
907
908 register_names: ARRAY [STRING] is
909 -- Names of registers indexed by their level
910 once
911 -- `c_void' is not used.
912 create Result.make (1, (c_nb_types - 1) * 2)
913 -- Simple registers.
914 Result.put ("ti1_", c_int8)
915 Result.put ("ti2_", c_int16)
916 Result.put ("ti4_", c_int32)
917 Result.put ("ti8_", c_int64)
918 Result.put ("tu1_", c_uint8)
919 Result.put ("tu2_", c_uint16)
920 Result.put ("tu4_", c_uint32)
921 Result.put ("tu8_", c_uint64)
922 Result.put ("tr4_", c_real32)
923 Result.put ("tr8_", c_real64)
924 Result.put ("tc", c_char)
925 Result.put ("tw", c_wide_char)
926 Result.put ("tp", c_pointer)
927 Result.put ("tr", c_ref)
928 -- Registers for passing typed arguments.
929 Result.put ("ui1_", c_nb_types - 1 + c_int8)
930 Result.put ("ui2_", c_nb_types - 1 + c_int16)
931 Result.put ("ui4_", c_nb_types - 1 + c_int32)
932 Result.put ("ui8_", c_nb_types - 1 + c_int64)
933 Result.put ("uu1_", c_nb_types - 1 + c_uint8)
934 Result.put ("uu2_", c_nb_types - 1 + c_uint16)
935 Result.put ("uu4_", c_nb_types - 1 + c_uint32)
936 Result.put ("uu8_", c_nb_types - 1 + c_uint64)
937 Result.put ("ur4_", c_nb_types - 1 + c_real32)
938 Result.put ("ur8_", c_nb_types - 1 + c_real64)
939 Result.put ("uc", c_nb_types - 1 + c_char)
940 Result.put ("uw", c_nb_types - 1 + c_wide_char)
941 Result.put ("up", c_nb_types - 1 + c_pointer)
942 Result.put ("ur", c_nb_types - 1 + c_ref)
943 end
944
945 register_sk_value (t: INTEGER): STRING is
946 -- SK value associated with a register type `t'
947 require
948 valid_t: 0 < t and t <= (c_nb_types - 1) * 2
949 do
950 Result := register_sk_values [t]
951 end
952
953 register_sk_values: ARRAY [STRING] is
954 -- SK values of registers indexed by their level
955 once
956 create Result.make (1, (c_nb_types - 1) * 2)
957 Result.put ("SK_INT8", c_int8)
958 Result.put ("SK_INT16", c_int16)
959 Result.put ("SK_INT32", c_int32)
960 Result.put ("SK_INT64", c_int64)
961 Result.put ("SK_UINT8", c_uint8)
962 Result.put ("SK_UINT16", c_uint16)
963 Result.put ("SK_UINT32", c_uint32)
964 Result.put ("SK_UINT64", c_uint64)
965 Result.put ("SK_REAL32", c_real32)
966 Result.put ("SK_REAL64", c_real64)
967 Result.put ("SK_CHAR", c_char)
968 Result.put ("SK_WCHAR", c_wide_char)
969 Result.put ("SK_POINTER", c_pointer)
970 Result.put ("SK_REF", c_ref)
971 -- Registers for passing typed arguments.
972 Result.put ("SK_INT8", c_nb_types - 1 + c_int8)
973 Result.put ("SK_INT16", c_nb_types - 1 + c_int16)
974 Result.put ("SK_INT32", c_nb_types - 1 + c_int32)
975 Result.put ("SK_INT64", c_nb_types - 1 + c_int64)
976 Result.put ("SK_UINT8", c_nb_types - 1 + c_uint8)
977 Result.put ("SK_UINT16", c_nb_types - 1 + c_uint16)
978 Result.put ("SK_UINT32", c_nb_types - 1 + c_uint32)
979 Result.put ("SK_UINT64", c_nb_types - 1 + c_uint64)
980 Result.put ("SK_REAL32", c_nb_types - 1 + c_real32)
981 Result.put ("SK_REAL64", c_nb_types - 1 + c_real64)
982 Result.put ("SK_CHAR", c_nb_types - 1 + c_char)
983 Result.put ("SK_WCHAR", c_nb_types - 1 + c_wide_char)
984 Result.put ("SK_POINTER", c_nb_types - 1 + c_pointer)
985 Result.put ("SK_REF", c_nb_types - 1 + c_ref)
986 end
987
988 feature -- Access
989
990 has_chained_prec: BOOLEAN is
991 -- Feature has chained preconditions?
992 do
993 Result := (byte_code.precondition /= Void
994 or else inherited_assertion.has_precondition)
995 and then
996 ( workbench_mode
997 or else
998 system.keep_assertions)
999 end
1000
1001 has_rescue: BOOLEAN is
1002 -- Feature has a rescue clause ?
1003 do
1004 Result := byte_code.rescue_clause /= Void
1005 end
1006
1007 set_origin_has_precondition (b: BOOLEAN) is
1008 do
1009 origin_has_precondition := b
1010 end
1011
1012 has_postcondition: BOOLEAN is
1013 -- Do we have to generate any postcondition ?
1014 do
1015 Result := workbench_mode or else System.keep_assertions
1016 end
1017
1018 has_precondition: BOOLEAN is
1019 -- Do we have to generate any precondition ?
1020 do
1021 Result := workbench_mode or else System.keep_assertions
1022 end
1023
1024 has_invariant: BOOLEAN is
1025 -- Do we have to generate invariant checks ?
1026 do
1027 Result := workbench_mode or else System.keep_assertions
1028 end
1029
1030 assertion_level: ASSERTION_I is
1031 -- Assertion level description
1032 do
1033 Result := associated_class.assertion_level
1034 end
1035
1036 associated_class: CLASS_C is
1037 -- Class associated with current type
1038 do
1039 Result := current_type.base_class
1040 end
1041
1042 constrained_type_in (type: TYPE_I; context_type: CLASS_TYPE): TYPE_I is
1043 -- Constrained type `type' in the context of `context_class_type'
1044 require
1045 type_not_void: type /= Void
1046 context_type_not_void: context_type /= Void
1047 local
1048 context_type_i: CL_TYPE_I
1049 formal: FORMAL_I
1050 formal_position: INTEGER
1051 reference_i: REFERENCE_I
1052 do
1053 debug ("to_implement")
1054 to_implement ("Move this feature to TYPE_I with a redefinition in FORMAL_I.")
1055 end
1056 from
1057 Result := type
1058 until
1059 not Result.is_formal or Result.is_multi_constrained
1060 loop
1061 context_type_i := context_type.type
1062 formal ?= Result
1063 check
1064 context_type_i.meta_generic /= Void
1065 end
1066 formal_position := formal.position
1067 Result := context_type_i.meta_generic.item (formal_position)
1068 reference_i ?= Result
1069 if reference_i /= Void then
1070 if formal.type_a.is_multi_constrained (context_type.type.base_class) then
1071 create {MULTI_FORMAL_I} Result.make (formal.is_reference, formal.is_expanded, formal.is_monomorph, formal.position, -1)
1072 else
1073 Result := context_type_i.base_class.constrained_type (formal_position).type_i
1074 end
1075 end
1076 end
1077 ensure
1078 result_not_void: Result /= Void
1079 result_not_formal: not Result.is_formal or Result.is_multi_constrained
1080 end
1081
1082 real_type_in (type: TYPE_I; context_type: CLASS_TYPE): TYPE_I is
1083 -- Type `type' as seen in `context_type'
1084 require
1085 type_not_void: type /= Void
1086 context_type_not_void: context_type /= Void
1087 do
1088 debug ("to_implement")
1089 to_implement ("Move this feature to TYPE_I and descendants.")
1090 end
1091 Result := constrained_type_in (type, context_type).instantiation_in (context_type)
1092 ensure
1093 result_not_void: Result /= Void
1094 result_not_formal: not Result.is_formal or Result.is_multi_constrained
1095 end
1096
1097 real_type_in_fixed (type: TYPE_I; context_type: CLASS_TYPE): TYPE_I is
1098 -- Type `type' as seen in `context_type'
1099 require
1100 type_not_void: type /= Void
1101 context_type_not_void: context_type /= Void
1102 local
1103 l_formal: FORMAL_A
1104 l_type_set: TYPE_SET_A
1105 do
1106 Result := real_type_in (type, context_type)
1107 -- Avoid instantiating types if possible
1108 if false then
1109
1110 debug ("to_implement")
1111 to_implement ("Move this feature to TYPE_I and descendants.")
1112 end
1113 l_formal ?= type.type_a
1114 if l_formal /= Void and then l_formal.is_multi_constrained (context_type.associated_class) then
1115 l_type_set := l_formal.constraints (class_type.associated_class)
1116 if l_type_set.has_expanded then
1117 Result := l_type_set.expanded_representative.type_i
1118 else
1119 create {MULTI_FORMAL_I} Result.make (type.is_reference, l_type_set.has_expanded, l_formal.is_monomorph, l_formal.position, -1)
1120 end
1121 else
1122 Result := constrained_type_in (type, context_type).instantiation_in (context_type)
1123 end
1124 end
1125 ensure
1126 result_not_void: Result /= Void
1127 result_not_formal: not Result.is_formal or Result.is_multi_constrained
1128 end
1129
1130 real_type (type: TYPE_I): TYPE_I is
1131 -- Type `type' written in `class_type' as seen in `context_class_type'
1132 require
1133 type_not_void: type /= Void
1134 class_type_not_void: class_type /= Void
1135 context_class_type_not_void: context_class_type /= Void
1136 local
1137 cl_type_i: CL_TYPE_I
1138 do
1139 fixme ("Check that all callers are aware that they can get back a MULTI_FORMAL_I.")
1140 -- Avoid instantiating types if possible
1141 cl_type_i ?= type
1142 if cl_type_i /= Void and then cl_type_i.is_standalone then
1143 -- Standalone class type
1144 Result := cl_type_i
1145 elseif cl_type_i = Void and then type.is_anchored then
1146 -- "like Current"
1147 Result := context_class_type.type
1148 elseif context_class_type = class_type then
1149 Result := real_type_in (type, class_type)
1150 else
1151 debug ("to_implement")
1152 to_implement ("Implement context-aware TYPE_I.instantiation_in so that there is no need to create TYPE_A.")
1153 end
1154 Result := constrained_type_in (type, class_type).type_a.instantiation_in
1155 (context_class_type.type.type_a, class_type.type.class_id).type_i
1156 end
1157 ensure
1158 result_not_void: Result /= Void
1159 result_not_formal: not Result.is_formal or Result.is_multi_constrained
1160 end
1161
1162 real_type_fixed (type: TYPE_I): TYPE_I is
1163 -- Type `type' written in `class_type' as seen in `context_class_type'
1164 -- Fixed means that the possible return of a MULTI_FORMAL_I is checked and valid.
1165 require
1166 type_not_void: type /= Void
1167 class_type_not_void: class_type /= Void
1168 context_class_type_not_void: context_class_type /= Void
1169 do
1170 Result := real_type (type)
1171 ensure
1172 result_not_void: Result /= Void
1173 result_not_formal: not Result.is_formal or Result.is_multi_constrained
1174 end
1175
1176 creation_type (type: TYPE_I): TYPE_I is
1177 -- Convenience
1178 require
1179 type_not_void: type /= Void
1180 class_type_not_void: class_type /= Void
1181 do
1182 Result := type.complete_instantiation_in (class_type)
1183 end
1184
1185 set_byte_code (bc: BYTE_CODE) is
1186 -- Assign `bc' to byte_code.
1187 require
1188 good_argument: bc /= Void
1189 do
1190 byte_code := bc
1191 end
1192
1193 init (t: CLASS_TYPE) is
1194 -- Initialize byte context with `t'.
1195 require
1196 t_not_void: t /= Void
1197 local
1198 f: FEATURE_I
1199 feature_table: FEATURE_TABLE
1200 do
1201 class_type_stack.wipe_out
1202 original_class_type := t
1203 context_class_type := t
1204 set_class_type (t)
1205 feature_table := System.any_class.compiled_class.feature_table
1206 f := feature_table.item_id ({PREDEFINED_NAMES}.copy_name_id)
1207 if f = Void then
1208 -- "copy" is not found in ANY
1209 copy_body_index := -1
1210 else
1211 copy_body_index := f.body_index
1212 end
1213 f := feature_table.item_id ({PREDEFINED_NAMES}.twin_name_id)
1214 if f = Void then
1215 -- "twin" is not found in ANY
1216 twin_body_index := -1
1217 else
1218 twin_body_index := f.body_index
1219 end
1220 ensure
1221 original_class_type_set: original_class_type = t
1222 context_class_type_set: context_class_type = t
1223 class_type_set: class_type = t
1224 not_is_class_type_changed: not is_class_type_changed
1225 end
1226
1227 is_ancestor (other: CLASS_TYPE): BOOLEAN is
1228 -- Is `other' an ancestor of `context_class_type'?
1229 do
1230 Result := context_class_type.type.type_a.is_conformant_to (other.type.type_a)
1231 end
1232
1233 is_written_context: BOOLEAN is
1234 -- Does current context match the context where the code is written?
1235 do
1236 Result := context_class_type = class_type
1237 end
1238
1239 set_class_type (t: CLASS_TYPE) is
1240 -- Assign `t' to `class_type'.
1241 require
1242 t_not_void: t /= Void
1243 context_class_type_not_void: context_class_type /= Void
1244 is_ancestor: is_ancestor (t)
1245 do
1246 class_type := t
1247 current_type := t.type
1248 -- Decide whether once routines can be optimized so that their results
1249 -- can be retrieved directly from memory without making actual calls.
1250 if
1251 workbench_mode or else assertion_level.is_precondition or else
1252 assertion_level.is_invariant or else assertion_level.is_postcondition
1253 then
1254 fixme ("[
1255 Even with precondition and postcondition checks turned on there is a possibility that
1256 routine has no preconditions and postconditions. Then if class invariants are not checked
1257 the optimization is still applicable.
1258 ]")
1259 is_once_call_optimized := False
1260 else
1261 is_once_call_optimized := True
1262 end
1263 ensure
1264 class_type_set: class_type = t
1265 end
1266
1267 change_class_type_context (new_context_class_type: CLASS_TYPE; new_written_class_type: CLASS_TYPE) is
1268 -- Change the current `class_type' to `new_written_class_type',
1269 -- not related to `original_class_type', but to `new_context_class_type'.
1270 -- (Multiple calls to this feature are allowed and should
1271 -- be paired with the calls to `restore_class_type_context').
1272 require
1273 new_context_class_type_not_void: new_context_class_type /= Void
1274 new_written_class_type_not_void: new_written_class_type /= Void
1275 context_class_type_not_void: context_class_type /= Void
1276 class_type_not_void: class_type /= Void
1277 is_ancestor: -- new_context_cl_type.type_a.is_conformant_to (new_written_class_type.type.type_a)
1278 do
1279 class_type_stack.put (create {PAIR [CLASS_TYPE, CLASS_TYPE]}.make (context_class_type, class_type))
1280 context_class_type := new_context_class_type
1281 set_class_type (new_written_class_type)
1282 ensure
1283 class_type_set: class_type = new_written_class_type
1284 context_class_type_set: context_class_type = new_context_class_type
1285 is_class_type_changed: is_class_type_changed
1286 end
1287
1288 restore_class_type_context is
1289 -- Restore the state of context to the one before the
1290 -- earlier call to `change_class_type_context'.
1291 require
1292 is_class_type_changed: is_class_type_changed
1293 local
1294 previous_context: PAIR [CLASS_TYPE, CLASS_TYPE]
1295 do
1296 -- Remove stack item before calling `set_class_type'
1297 previous_context := class_type_stack.item
1298 class_type_stack.remove
1299 context_class_type := previous_context.first
1300 set_class_type (previous_context.second)
1301 ensure
1302 context_class_type_set: context_class_type = old class_type_stack.item.first
1303 class_type_set: class_type = old class_type_stack.item.second
1304 end
1305
1306 set_current_feature (f: FEATURE_I) is
1307 -- Assign `f' to `current_feature'.
1308 require
1309 valid_f: f /= Void
1310 do
1311 current_feature := f
1312 original_body_index := f.body_index
1313 ensure
1314 current_feature_set: current_feature = f
1315 original_body_index_set: original_body_index = f.body_index
1316 end
1317
1318 set_original_body_index (new_original_body_index: like original_body_index) is
1319 -- Set `original_body_index' to `new_original_body_index'.
1320 do
1321 original_body_index := new_original_body_index
1322 ensure
1323 original_body_index_set: original_body_index = new_original_body_index
1324 end
1325
1326 init_propagation is
1327 -- Reset `propagated' to False.
1328 do
1329 propagated := False
1330 end
1331
1332 set_propagated is
1333 -- Signals register has been caught.
1334 do
1335 propagated := True
1336 end
1337
1338 propagate_no_register: BOOLEAN is
1339 -- Is the propagation of `No_register' allowed ?
1340 do
1341 Result := not ( workbench_mode
1342 or else
1343 assertion_level.is_precondition)
1344 end
1345
1346 add_dt_current is
1347 -- One more time we need to compute Current's type.
1348 do
1349 if in_inlined_code then
1350 inlined_dt_current := inlined_dt_current + 1
1351 else
1352 dt_current := dt_current + 1
1353 end
1354 end
1355
1356 add_dftype_current is
1357 -- On more time we need to compute Current's full dynamic type.
1358 do
1359 if in_inlined_code then
1360 inlined_dftype_current := inlined_dftype_current + 1
1361 else
1362 dftype_current := dftype_current + 1
1363 end
1364 end
1365
1366 set_inlined_dt_current (i: INTEGER) is
1367 -- Set the value of `inlined_dt_current' to `i'
1368 require
1369 i_non_negative: i >= 0
1370 do
1371 inlined_dt_current := i
1372 ensure
1373 inlined_dt_current_set: inlined_dt_current = i
1374 end
1375
1376 set_inlined_dftype_current (i: INTEGER) is
1377 -- Set value of `inlined_dftype_current' to `i'.
1378 require
1379 i_non_negative: i >= 0
1380 do
1381 inlined_dftype_current := i
1382 ensure
1383 inlined_dftype_current_set: inlined_dftype_current = i
1384 end
1385
1386 reset_inlined_dt_current is
1387 -- Reset `inlined_dt_current' to 0
1388 do
1389 inlined_dt_current := 0
1390 ensure
1391 inlined_dt_current_set: inlined_dt_current = 0
1392 end
1393
1394 reset_inlined_dftype_current is
1395 -- Reset `inlined_dftype_current' to 0
1396 do
1397 inlined_dftype_current := 0
1398 ensure
1399 inlined_dftype_current_set: inlined_dftype_current = 0
1400 end
1401
1402 mark_current_used is
1403 -- Signals that a reference is made to Current (apart
1404 -- from computing a DT) and thus needs to be pushed on
1405 -- the local stack in case it'd be moved by the GC.
1406 -- As a side effect, compute an index for Current in the
1407 -- local variable array
1408 do
1409 -- Not marking if inside inlined code:
1410 -- Current is NOT in Current_b
1411 current_used_count := current_used_count + 1
1412 if not (current_used or else in_inlined_code) then
1413 set_local_index ("Current", Current_b)
1414 current_used := True
1415 end
1416 end
1417
1418 mark_result_used is
1419 -- Signals that an assignment in Result is made
1420 -- As a side effect, compute an index for Result in the local
1421 -- variable array, if the type is a pointer one and we are not
1422 -- inside a once function.
1423 do
1424 if not in_inlined_code then
1425 if not result_used and
1426 real_type (byte_code.result_type).c_type.is_pointer and
1427 not byte_code.is_once
1428 then
1429 set_local_index ("Result", Result_register)
1430 end
1431 result_used := True
1432 end
1433 end
1434
1435 mark_local_used (an_index: INTEGER) is
1436 -- Signals that local variable `an_index' is used
1437 do
1438 local_vars.force (True, an_index)
1439 end
1440
1441 inc_label is
1442 -- Increment `label'
1443 do
1444 label := label + 1
1445 end
1446
1447 generate_body_label is
1448 -- Generate label "body"
1449 --|Note: the semi-colon is added, otherwise C compilers
1450 --|complain when there are no instructions after the label.
1451 local
1452 buf: GENERATION_BUFFER
1453 do
1454 buf := buffer
1455 buf.exdent
1456 buf.put_string ("body:;")
1457 buf.put_new_line
1458 buf.indent
1459 end
1460
1461 print_body_label is
1462 -- Print label "body"
1463 do
1464 buffer.put_string ("body")
1465 end
1466
1467 generate_current_label_definition is
1468 -- Generate current label `label'.
1469 do
1470 generate_label_definition (label)
1471 end
1472
1473 generate_label_definition (l: INTEGER) is
1474 -- Generate label number `l'
1475 require
1476 label_exists: l >= 0
1477 local
1478 buf: GENERATION_BUFFER
1479 do
1480 if label > 0 then
1481 buf := buffer
1482 buf.exdent
1483 buf.put_new_line
1484 print_label (l)
1485 buf.put_character (':')
1486 buf.put_new_line
1487 buf.indent
1488 end
1489 end
1490
1491 print_current_label is
1492 -- Print label number `label'.
1493 do
1494 print_label (label)
1495 end
1496
1497 print_label (l: INTEGER) is
1498 -- Print label number `l'
1499 require
1500 label_exists: l > 0
1501 local
1502 buf: GENERATION_BUFFER
1503 do
1504 buf := buffer
1505 buf.put_string ("label_")
1506 buf.put_integer (l)
1507 end
1508
1509 set_local_index (s: STRING; r: REGISTRABLE) is
1510 -- Record the instance `r' into the `associated_register_table'
1511 -- as register named `s'.
1512 require
1513 s_not_void: s /= Void
1514 local
1515 key: STRING
1516 do
1517 if not local_index_table.has (s) then
1518 key := s.twin
1519 local_index_table.put (local_index_counter, key)
1520 local_index_counter := local_index_counter + 1
1521 associated_register_table.put (r, key)
1522 end
1523 end
1524
1525 need_gc_hook: BOOLEAN
1526 -- Do we need to generate GC hooks?
1527 -- Computed by compute_need_gc_hooks for each instance of BYTE_CODE.
1528
1529 force_gc_hooks is
1530 -- Force usage of GC hooks
1531 do
1532 need_gc_hook := True
1533 end
1534
1535 compute_need_gc_hooks (has_assertions_checking_enabled: BOOLEAN) is
1536 -- Set `need_gc_hook' for current instance of BYTE_CODE
1537 -- If `has_assertions_checking_enabled', `need_gc_hook' is set to True.
1538 local
1539 l_assign: ASSIGN_BL
1540 reverse_b: REVERSE_BL
1541 call: CALL_B
1542 expr_b: EXPR_B
1543 creation_expr: CREATION_EXPR_B
1544 instruction_call: INSTR_CALL_B
1545 attribute_b: ATTRIBUTE_B
1546 compound: BYTE_LIST [BYTE_NODE]
1547 byte_node: BYTE_NODE
1548 tmp: BOOLEAN
1549 do
1550 -- We won't need any RTLI if the only statement is an expanded
1551 -- assignment in Result or a single call.
1552
1553 -- If there is a rescue clause, then we'll
1554 -- need an execution vector, hence GC hooks
1555 -- are really needed.
1556 -- If some calls are inlined, we need to save Current, Result,
1557 -- the arguments and locals in registers
1558 -- If there are some pre/post conditions to check, we choose
1559 -- to be safe by encapsulating even when not needed if the checks
1560 -- are generated.
1561 tmp := has_rescue or byte_code.has_inlined_code or has_assertions_checking_enabled
1562
1563 if not tmp and then assertion_type /= In_invariant then
1564 tmp := True
1565 -- Not in an invariant generation
1566 compound := byte_code.compound
1567 if compound /= Void and then compound.count = 1 then
1568 byte_node := compound.first
1569 l_assign ?= byte_node
1570 if l_assign /= Void then
1571 if l_assign.expand_return then
1572 -- Assignment in Result is expanded in a return instruction
1573 tmp := False
1574 elseif not l_assign.source.allocates_memory_for_type (real_type (l_assign.target.type)) then
1575 reverse_b ?= l_assign
1576 -- FIXME: Manu 05/31/2002: we should try to optimize
1577 -- so that not all reverse assignment prevent the optimization
1578 -- to be made.
1579 call ?= l_assign.source
1580 if call /= Void and then call.is_single and then reverse_b = Void then
1581 -- Simple assignment of a single call
1582 creation_expr ?= call
1583 if creation_expr /= Void or has_invariant then
1584 -- We do not optimize if we are handling a creation expression or
1585 -- if invariant checking is enabled.
1586 tmp := True
1587 else
1588 if call.is_constant then
1589 tmp := False
1590 elseif l_assign.target.is_predefined then
1591 -- Assignment on a predefined target is always safe.
1592 tmp := False
1593 else
1594 -- We can optimize target := call when
1595 -- no metamorphosis occurs on source.
1596 tmp := not real_type (l_assign.target.type).is_basic and
1597 real_type (call.type).is_basic
1598
1599 if not tmp then
1600 attribute_b ?= call
1601 if attribute_b /= Void then
1602 -- An attribute access is always safe
1603 tmp := False
1604 else
1605 -- If it is an instruction target := call
1606 -- where the source is a predefined item
1607 -- (local, current, result or argument),
1608 -- we can still optimize. Xavier
1609 tmp := not call.is_predefined
1610 end
1611 end
1612 end
1613 end
1614 else
1615 expr_b ?= l_assign.source
1616 tmp := expr_b.has_call or expr_b.allocates_memory or else expr_b.allocates_memory_for_type (real_type (l_assign.target.type))
1617 end
1618 end
1619 else
1620 instruction_call ?= byte_node
1621 if instruction_call /= Void then
1622 if instruction_call.call.is_single then
1623 -- A single instruction call
1624 tmp := has_invariant
1625 end
1626 end
1627 end
1628 end
1629 end
1630 need_gc_hook := tmp
1631 end
1632
1633 make_from_context (other: like Current) is
1634 -- Save context for later restoration. This makes the
1635 -- use of unanalyze possible and meaningful.
1636 do
1637 copy (other)
1638 register_server := other.register_server.duplicate
1639 local_index_table := other.local_index_table.twin
1640 associated_register_table := other.associated_register_table.twin
1641 end
1642
1643 restore (saved_context: like Current) is
1644 -- Restore the saved context after an analyze followed by an
1645 -- unanalyze, so that we may analyze again with different
1646 -- propagations (kind of feedback).
1647 do
1648 register_server := saved_context.register_server
1649 current_used := saved_context.current_used
1650 current_used_count := saved_context.current_used_count
1651 need_gc_hook := saved_context.need_gc_hook
1652 current_feature := saved_context.current_feature
1653 result_used := saved_context.result_used
1654 dt_current := saved_context.dt_current
1655 inlined_dt_current := saved_context.inlined_dt_current
1656 dftype_current := saved_context.dftype_current
1657 inlined_dftype_current := saved_context.inlined_dftype_current
1658 local_index_table := saved_context.local_index_table
1659 local_index_counter := saved_context.local_index_counter
1660 associated_register_table := saved_context.associated_register_table
1661 end
1662
1663 generate_current_dtype is
1664 -- Generate the dynamic type of `Current'
1665 do
1666 if inlined_dt_current > 1 then
1667 buffer.put_string (gc_inlined_dtype)
1668 elseif dt_current > 1 then
1669 buffer.put_string (gc_dtype)
1670 else
1671 buffer.put_string (gc_upper_dtype_lparan)
1672 Current_register.print_register
1673 buffer.put_character (')')
1674 end
1675 end
1676
1677 generate_current_dftype is
1678 -- Generate the dynamic type of `Current'
1679 do
1680 if inlined_dftype_current > 1 then
1681 buffer.put_string (gc_inlined_dftype)
1682 elseif dftype_current > 1 then
1683 buffer.put_string (gc_dftype)
1684 else
1685 buffer.put_string (gc_upper_dftype_lparan)
1686 Current_register.print_register
1687 buffer.put_character (')')
1688 end
1689 end
1690
1691 generate_temporary_ref_variables is
1692 -- Generate temporary variables under the control of the
1693 -- garbage collector.
1694 local
1695 i, j, nb_vars: INTEGER
1696 do
1697 from
1698 i := (c_nb_types - 1) * 2
1699 until
1700 i <= 0
1701 loop
1702 from
1703 j := 1
1704 nb_vars := register_server.needed_registers_by_clevel (i)
1705 until
1706 j > nb_vars
1707 loop
1708 generate_tmp_var (i, j)
1709 j := j + 1
1710 end
1711 i := i - 1
1712 end
1713 end
1714
1715 generate_tmp_var (ctype, num: INTEGER) is
1716 -- Generate declaration for temporary variable `num'
1717 -- whose C type is `ctype'.
1718 local
1719 buf: GENERATION_BUFFER
1720 value_type: TYPE_C
1721 variable_type: STRING
1722 is_generic: BOOLEAN
1723 do
1724 buf := buffer
1725
1726 -- First get type and name of temporary local.
1727 value_type := register_type (ctype)
1728 if ctype >= c_nb_types then
1729 -- This is a register to hold generic argument value
1730 is_generic := True
1731 variable_type := once "EIF_UNION"
1732 else
1733 variable_type := value_type.c_string
1734 end
1735 buf.put_string (variable_type)
1736 buf.put_character (' ')
1737 if has_rescue and then not is_generic then
1738 buf.put_string (once " EIF_VOLATILE ")
1739 end
1740 put_register_name (ctype, num, buf)
1741 if is_generic then
1742 -- Record register type and zero pointer value for GC.
1743 buf.put_string (once "x = {0, ")
1744 buf.put_string (register_sk_value (ctype))
1745 buf.put_string ("};")
1746 buf.left_margin
1747 buf.put_new_line
1748 buf.put_string ("#undef ")
1749 put_register_name (ctype, num, buf)
1750 buf.put_new_line
1751 buf.put_string ("#define ")
1752 put_register_name (ctype, num, buf)
1753 buf.put_character (' ')
1754 put_register_name (ctype, num, buf)
1755 buf.put_string ("x.")
1756 value_type.generate_typed_field (buf)
1757 buf.restore_margin
1758 else
1759 if ctype = c_ref then
1760 -- Because it is a reference we absolutely need to initialize it
1761 -- to its default value, otherwise it would mess up the GC local tracking.
1762 buf.put_string (once " = NULL")
1763 end
1764 buf.put_character (';')
1765 end
1766 buf.put_new_line
1767 end
1768
1769 generate_gc_hooks (compound_or_post: BOOLEAN) is
1770 -- In case there are some local reference variables,
1771 -- generate the hooks for the GC by filling the local variable
1772 -- array. Unfortunately, I cannot use bzero() on the array, in
1773 -- case it would be a function call--RAM.
1774 --| `compound_or_post' indicate the generation of hooks
1775 --| for the compound or post- pre- or invariant routine. -- FREDD
1776 local
1777 nb_refs: INTEGER -- Total number of references to be pushed
1778 hash_table: HASH_TABLE [INTEGER, STRING]
1779 associated: HASH_TABLE [REGISTRABLE, STRING]
1780 rname: STRING
1781 position: INTEGER
1782 reg: REGISTRABLE
1783 buf: GENERATION_BUFFER
1784 do
1785 buf := buffer
1786 -- if more than, say, 20 local variables are to be initialized,
1787 -- then it might be worthy to call bzero() instead of manually
1788 -- setting the entries (beneficial both in code size and execution
1789 -- time
1790 -- Current is needed only if used
1791 nb_refs := ref_var_used
1792
1793 -- The hooks are only needed if there is at least one reference
1794 if nb_refs > 0 then
1795 if compound_or_post or else byte_code.rescue_clause = Void then
1796 buf.put_string ("RTLI(")
1797 else
1798 buf.put_string ("RTXI(")
1799 end
1800 buf.put_integer (nb_refs)
1801 buf.put_string (gc_rparan_semi_c)
1802 buf.put_new_line
1803 from
1804 hash_table := local_index_table
1805 associated := associated_register_table
1806 hash_table.start
1807 until
1808 hash_table.after
1809 loop
1810 rname := hash_table.key_for_iteration
1811 position := hash_table.item_for_iteration
1812 reg := associated.item (rname)
1813
1814 check
1815 reference_type: not reg.is_current implies reg.c_type.is_pointer
1816 end
1817
1818 if
1819 ((reg.is_predefined or reg.is_temporary)
1820 and not (reg.is_current or reg.is_argument)
1821 and not (reg.is_result and compound_or_post))
1822 then
1823 buf.put_local_registration (position, rname)
1824 else
1825 if (reg.c_type.is_bit) and (reg.is_argument) then
1826 -- Clone argument if it is bit
1827 buf.put_local_registration (position, rname)
1828 buf.put_new_line
1829 buf.put_string (rname)
1830 buf.put_string (" = RTCB(")
1831 buf.put_string (rname)
1832 buf.put_character (')')
1833 buf.put_character (';')
1834 else
1835 buf.put_local_registration (position, rname)
1836 end
1837 end
1838 buf.put_new_line
1839 hash_table.forth
1840 end
1841 buf.put_new_line
1842 end
1843 end
1844
1845 expanded_number (arg_pos: INTEGER): INTEGER is
1846 -- Compute the argument's ordinal position within the expanded
1847 -- subset of arguments.
1848 local
1849 arg_array: ARRAY [TYPE_I]
1850 i, count: INTEGER
1851 nb_exp: INTEGER
1852 do
1853 arg_array := byte_code.arguments
1854 from
1855 i := arg_array.lower
1856 count := arg_array.count
1857 until
1858 Result /= 0 or i > count or i > arg_pos
1859 loop
1860 if real_type (arg_array.item (i)).is_true_expanded then
1861 nb_exp := nb_exp + 1
1862 end
1863 if i = arg_pos then
1864 Result := nb_exp
1865 end
1866 i := i + 1
1867 end
1868 end
1869
1870 remove_gc_hooks is
1871 -- Pop off pushed addresses on local stack
1872 local
1873 vars: INTEGER
1874 buf: GENERATION_BUFFER
1875 do
1876 buf := buffer
1877 if byte_code.rescue_clause /= Void then
1878 buf.put_string ("RTEOK;")
1879 buf.put_new_line
1880 end
1881 vars := ref_var_used
1882 if vars > 0 then
1883 if byte_code.rescue_clause /= Void then
1884 buf.put_string ("RTXE;")
1885 buf.put_new_line
1886 else
1887 buf.put_string ("RTLE;")
1888 buf.put_new_line
1889 end
1890 end
1891 end
1892
1893 ref_var_used: INTEGER is
1894 -- Number of reference variable needed for GC hooks
1895 do
1896 if not need_gc_hook then
1897 Result := 0
1898 else
1899 Result := local_index_table.count
1900 end
1901 end
1902
1903 local_list: LINKED_LIST [TYPE_I]
1904 -- Local type list for byte code: it includes Eiffel local
1905 -- variables types, variant local integer and hector
1906 -- temporary varaibles
1907
1908 add_local (t: TYPE_I) is
1909 -- Add local type to `local_list'.
1910 require
1911 good_argument: t /= Void
1912 do
1913 local_list.finish
1914 local_list.put_right (t)
1915 end
1916
1917 feature -- Clearing
1918
1919 array_opt_clear is
1920 -- Clear during the array optimization
1921 do
1922 class_type := Void
1923 byte_code := Void
1924 class_type_stack.wipe_out
1925 end
1926
1927 clear_feature_data is
1928 -- Clear feature-specific data.
1929 do
1930 local_vars.clear_all
1931 local_index_table.clear_all
1932 associated_register_table.clear_all
1933 local_index_counter := 0
1934 dt_current := 0
1935 inlined_dt_current := 0
1936 dftype_current := 0
1937 inlined_dftype_current := 0
1938 is_first_precondition_block_generated := False
1939 is_new_precondition_block := False
1940 result_used := False
1941 current_feature := Void
1942 original_body_index := 0
1943 current_used := False
1944 current_used_count := 0
1945 need_gc_hook := False
1946 label := 0
1947 local_list.wipe_out
1948 breakpoint_slots_number := 0;
1949 -- This should not be necessary but may limit the
1950 -- effect of bugs in register allocation (if any).
1951 register_server.clear_all
1952 end
1953
1954 clear_class_type_data is
1955 -- Clear class-type-specific data.
1956 do
1957 if workbench_mode then
1958 -- Wipe out content of `global_onces'.
1959 global_onces.wipe_out
1960 -- Wipe out content of `onces'.
1961 onces.wipe_out
1962 end
1963 -- Wipe out once manifest strings records.
1964 once_manifest_string_table.wipe_out
1965 class_type_stack.wipe_out
1966 generated_inlines.wipe_out
1967 ensure
1968 global_onces_is_empty: workbench_mode implies global_onces.is_empty
1969 onces_is_empty: workbench_mode implies onces.is_empty
1970 once_manifest_string_table_is_empty: once_manifest_string_table.is_empty
1971 generated_inlines_empty: generated_inlines.is_empty
1972 end
1973
1974 clear_system_data is
1975 -- Clear system-wide data.
1976 do
1977 global_onces.wipe_out
1978 onces.wipe_out
1979 once_manifest_string_count_table.wipe_out
1980 class_type_stack.wipe_out
1981 generic_wrappers.wipe_out
1982 expanded_descendants := Void
1983 ensure
1984 global_onces_is_empty: global_onces.is_empty
1985 onces_is_empty: onces.is_empty
1986 once_manifest_string_count_table_is_empty: once_manifest_string_count_table.is_empty
1987 generic_wrappers_is_empty: generic_wrappers.is_empty
1988 has_no_expanded_descendants_information: not has_expanded_descendants_information
1989 end
1990
1991 feature -- Debugger
1992
1993 instruction_line: LINE [AST_EIFFEL]
1994 -- List of breakable instructions on which a breakpoint may be set.
1995
1996 breakpoint_slots_number: INTEGER
1997 -- current number of breakpoint slots known
1998
1999 set_instruction_line (l: like instruction_line) is
2000 -- Assign `l' to `instruction_line' and position FIFO stack at the
2001 -- beginning as a side effect, ready for usage by byte code classes.
2002 do
2003 instruction_line := l
2004 l.start
2005 end
2006
2007 get_next_breakpoint_slot: INTEGER is
2008 -- increase the current number of breakpoint slots and then
2009 -- return the current number of breakpoint slots. It is used
2010 -- to get a "line number" when recording a breakable point
2011 do
2012 breakpoint_slots_number := breakpoint_slots_number + 1
2013 Result := breakpoint_slots_number
2014 end
2015
2016 get_breakpoint_slot: INTEGER is
2017 -- Return the current number of breakpoint slots. It is used
2018 -- to get a "line number" when recording a breakable point
2019 do
2020 Result := breakpoint_slots_number
2021 end
2022
2023 set_breakpoint_slot (a_number: INTEGER) is
2024 -- Set the current number of breakpoint slots to `a_number'
2025 do
2026 breakpoint_slots_number := a_number
2027 end
2028
2029 byte_prepend (ba, array: BYTE_ARRAY) is
2030 -- Prepend `array' to byte array `ba' and update positions in the
2031 -- breakable point list (provided we are in debug mode).
2032 do
2033 ba.prepend (array)
2034 end
2035
2036 feature -- Inlining
2037
2038 in_inlined_code: BOOLEAN is
2039 -- Are we dealing with inlined code?
2040 do
2041 Result := inlined_current_register /= Void
2042 end
2043
2044 inlined_current_register: REGISTRABLE
2045 -- pseudo Current register for inlined code
2046
2047 set_inlined_current_register (r: REGISTRABLE) is
2048 do
2049 inlined_current_register := r
2050 end
2051
2052 feature -- Descendants information
2053
2054 has_expanded_descendants_information: BOOLEAN is
2055 -- Is information about expanded descendants available?
2056 require
2057 is_final_mode: final_mode
2058 do
2059 Result := expanded_descendants /= Void
2060 ensure
2061 definition: Result = (expanded_descendants /= Void)
2062 end
2063
2064 has_expanded_descendants (type_id: INTEGER): BOOLEAN is
2065 -- Are there expanded descendants for class type of `type_id'?
2066 require
2067 is_final_mode: final_mode
2068 has_expanded_descendants_information: has_expanded_descendants_information
2069 valid_type_id: type_id > 0 and then type_id <= system.class_types.count
2070 do
2071 Result := expanded_descendants.item (type_id)
2072 ensure
2073 definition: Result = expanded_descendants.item (type_id)
2074 end
2075
2076 compute_expanded_descendants is
2077 -- Compute
2078 require
2079 is_final_mode: final_mode
2080 has_no_expanded_descendants_information: not has_expanded_descendants_information
2081 local
2082 i: INTEGER
2083 class_types: ARRAY [CLASS_TYPE]
2084 c: CLASS_TYPE
2085 t: CL_TYPE_I
2086 do
2087 from
2088 class_types := system.class_types
2089 i := class_types.count
2090 create expanded_descendants.make (i)
2091 until
2092 i <= 0
2093 loop
2094 c := class_types.item (i)
2095 if c /= Void and then c.is_expanded then
2096 expanded_descendants.include (c.conformance_table)
2097 t := c.type.reference_type
2098 if t.has_associated_class_type then
2099 expanded_descendants.put (True, t.associated_class_type.type_id)
2100 end
2101 end
2102 i := i - 1
2103 end
2104 ensure
2105 has_expanded_descendants_information: has_expanded_descendants_information
2106 expanded_descendants_is_filled: expanded_descendants.count >= system.class_types.count
2107 end
2108
2109 feature -- Generic code generation
2110
2111 record_wrapper (body_index: INTEGER; routine_id: INTEGER) is
2112 -- Ensure the wrapper of the routine `body_index' is generated
2113 -- for the polymorphic table `routine_id'
2114 require
2115 final_mode: final_mode
2116 local
2117 r: ROUT_ID_SET
2118 do
2119 generic_wrappers.search (body_index)
2120 if generic_wrappers.found then
2121 r := generic_wrappers.found_item
2122 else
2123 create r.make
2124 generic_wrappers.put (r, body_index)
2125 end
2126 r.put (routine_id)
2127 end
2128
2129 generic_wrapper_ids (body_index: INTEGER): ROUT_ID_SET is
2130 -- Routine IDs of generic wrappers for a feature with `body_index' (if any)
2131 do
2132 Result := generic_wrappers.item (body_index)
2133 end
2134
2135 feature {NONE} -- Generic code generation
2136
2137 generic_wrappers: HASH_TABLE [ROUT_ID_SET, INTEGER]
2138 -- Set of routine IDs identified by the body index
2139 -- for which a wrapper has to be generated
2140
2141 feature {NONE} -- Implementation
2142
2143 class_type_stack: STACK [PAIR [CLASS_TYPE, CLASS_TYPE]]
2144 -- Class types saved due to the context change by `change_class_type_context'
2145
2146 expanded_descendants: PACKED_BOOLEANS
2147 -- Marks for class types whether they have an expanded descendant or not
2148
2149 invariant
2150 global_onces_not_void: global_onces /= Void
2151 onces_not_void: onces /= Void
2152 once_manifest_string_count_table_not_void: once_manifest_string_count_table /= Void
2153 once_manifest_string_table_not_void: once_manifest_string_table /= Void
2154 class_type_valid_with_current_type: class_type /= Void implies class_type.type = current_type
2155 class_type_stack_not_void: class_type_stack /= Void
2156
2157 indexing
2158 copyright: "Copyright (c) 1984-2006, Eiffel Software"
2159 license: "GPL version 2 (see http://www.eiffel.com/licensing/gpl.txt)"
2160 licensing_options: "http://www.eiffel.com/licensing"
2161 copying: "[
2162 This file is part of Eiffel Software's Eiffel Development Environment.
2163
2164 Eiffel Software's Eiffel Development Environment is free
2165 software; you can redistribute it and/or modify it under
2166 the terms of the GNU General Public License as published
2167 by the Free Software Foundation, version 2 of the License
2168 (available at the URL listed under "license" above).
2169
2170 Eiffel Software's Eiffel Development Environment is
2171 distributed in the hope that it will be useful, but
2172 WITHOUT ANY WARRANTY; without even the implied warranty
2173 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
2174 See the GNU General Public License for more details.
2175
2176 You should have received a copy of the GNU General Public
2177 License along with Eiffel Software's Eiffel Development
2178 Environment; if not, write to the Free Software Foundation,
2179 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2180 ]"
2181 source: "[
2182 Eiffel Software
2183 356 Storke Road, Goleta, CA 93117 USA
2184 Telephone 805-685-1006, Fax 805-685-6869
2185 Website http://www.eiffel.com
2186 Customer support http://support.eiffel.com
2187 ]"
2188
2189 end

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

  ViewVC Help
Powered by ViewVC 1.1.23