Update ChangeLog and version files for release
[official-gcc.git] / gcc / ada / a-tags.adb
blob203d19ed6764eeccbddc9584119e9952e2180336
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME COMPONENTS --
4 -- --
5 -- A D A . T A G S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1992-2015, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
29 -- --
30 ------------------------------------------------------------------------------
32 with Ada.Exceptions;
33 with Ada.Unchecked_Conversion;
35 with System.HTable;
36 with System.Storage_Elements; use System.Storage_Elements;
37 with System.WCh_Con; use System.WCh_Con;
38 with System.WCh_StW; use System.WCh_StW;
40 pragma Elaborate (System.HTable);
41 -- Elaborate needed instead of Elaborate_All to avoid elaboration cycles
42 -- when polling is turned on. This is safe because HTable doesn't do anything
43 -- at elaboration time; it just contains a generic package we want to
44 -- instantiate.
46 package body Ada.Tags is
48 -----------------------
49 -- Local Subprograms --
50 -----------------------
52 function CW_Membership (Obj_Tag : Tag; Typ_Tag : Tag) return Boolean;
53 -- Given the tag of an object and the tag associated to a type, return
54 -- true if Obj is in Typ'Class.
56 function Get_External_Tag (T : Tag) return System.Address;
57 -- Returns address of a null terminated string containing the external name
59 function Is_Primary_DT (T : Tag) return Boolean;
60 -- Given a tag returns True if it has the signature of a primary dispatch
61 -- table. This is Inline_Always since it is called from other Inline_
62 -- Always subprograms where we want no out of line code to be generated.
64 function Length (Str : Cstring_Ptr) return Natural;
65 -- Length of string represented by the given pointer (treating the string
66 -- as a C-style string, which is Nul terminated). See comment in body
67 -- explaining why we cannot use the normal strlen built-in.
69 function OSD (T : Tag) return Object_Specific_Data_Ptr;
70 -- Ada 2005 (AI-251): Given a pointer T to a secondary dispatch table,
71 -- retrieve the address of the record containing the Object Specific
72 -- Data table.
74 function SSD (T : Tag) return Select_Specific_Data_Ptr;
75 -- Ada 2005 (AI-251): Given a pointer T to a dispatch Table, retrieves the
76 -- address of the record containing the Select Specific Data in T's TSD.
78 pragma Inline_Always (CW_Membership);
79 pragma Inline_Always (Get_External_Tag);
80 pragma Inline_Always (Is_Primary_DT);
81 pragma Inline_Always (OSD);
82 pragma Inline_Always (SSD);
84 -- Unchecked conversions
86 function To_Address is
87 new Unchecked_Conversion (Cstring_Ptr, System.Address);
89 function To_Cstring_Ptr is
90 new Unchecked_Conversion (System.Address, Cstring_Ptr);
92 -- Disable warnings on possible aliasing problem
94 function To_Tag is
95 new Unchecked_Conversion (Integer_Address, Tag);
97 function To_Addr_Ptr is
98 new Ada.Unchecked_Conversion (System.Address, Addr_Ptr);
100 function To_Address is
101 new Ada.Unchecked_Conversion (Tag, System.Address);
103 function To_Dispatch_Table_Ptr is
104 new Ada.Unchecked_Conversion (Tag, Dispatch_Table_Ptr);
106 function To_Dispatch_Table_Ptr is
107 new Ada.Unchecked_Conversion (System.Address, Dispatch_Table_Ptr);
109 function To_Object_Specific_Data_Ptr is
110 new Ada.Unchecked_Conversion (System.Address, Object_Specific_Data_Ptr);
112 function To_Tag_Ptr is
113 new Ada.Unchecked_Conversion (System.Address, Tag_Ptr);
115 function To_Type_Specific_Data_Ptr is
116 new Ada.Unchecked_Conversion (System.Address, Type_Specific_Data_Ptr);
118 -------------------------------
119 -- Inline_Always Subprograms --
120 -------------------------------
122 -- Inline_always subprograms must be placed before their first call to
123 -- avoid defeating the frontend inlining mechanism and thus ensure the
124 -- generation of their correct debug info.
126 -------------------
127 -- CW_Membership --
128 -------------------
130 -- Canonical implementation of Classwide Membership corresponding to:
132 -- Obj in Typ'Class
134 -- Each dispatch table contains a reference to a table of ancestors (stored
135 -- in the first part of the Tags_Table) and a count of the level of
136 -- inheritance "Idepth".
138 -- Obj is in Typ'Class if Typ'Tag is in the table of ancestors that are
139 -- contained in the dispatch table referenced by Obj'Tag . Knowing the
140 -- level of inheritance of both types, this can be computed in constant
141 -- time by the formula:
143 -- TSD (Obj'tag).Tags_Table (TSD (Obj'tag).Idepth - TSD (Typ'tag).Idepth)
144 -- = Typ'tag
146 function CW_Membership (Obj_Tag : Tag; Typ_Tag : Tag) return Boolean is
147 Obj_TSD_Ptr : constant Addr_Ptr :=
148 To_Addr_Ptr (To_Address (Obj_Tag) - DT_Typeinfo_Ptr_Size);
149 Typ_TSD_Ptr : constant Addr_Ptr :=
150 To_Addr_Ptr (To_Address (Typ_Tag) - DT_Typeinfo_Ptr_Size);
151 Obj_TSD : constant Type_Specific_Data_Ptr :=
152 To_Type_Specific_Data_Ptr (Obj_TSD_Ptr.all);
153 Typ_TSD : constant Type_Specific_Data_Ptr :=
154 To_Type_Specific_Data_Ptr (Typ_TSD_Ptr.all);
155 Pos : constant Integer := Obj_TSD.Idepth - Typ_TSD.Idepth;
156 begin
157 return Pos >= 0 and then Obj_TSD.Tags_Table (Pos) = Typ_Tag;
158 end CW_Membership;
160 ----------------------
161 -- Get_External_Tag --
162 ----------------------
164 function Get_External_Tag (T : Tag) return System.Address is
165 TSD_Ptr : constant Addr_Ptr :=
166 To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
167 TSD : constant Type_Specific_Data_Ptr :=
168 To_Type_Specific_Data_Ptr (TSD_Ptr.all);
169 begin
170 return To_Address (TSD.External_Tag);
171 end Get_External_Tag;
173 -------------------
174 -- Is_Primary_DT --
175 -------------------
177 function Is_Primary_DT (T : Tag) return Boolean is
178 begin
179 return DT (T).Signature = Primary_DT;
180 end Is_Primary_DT;
182 ---------
183 -- OSD --
184 ---------
186 function OSD (T : Tag) return Object_Specific_Data_Ptr is
187 OSD_Ptr : constant Addr_Ptr :=
188 To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
189 begin
190 return To_Object_Specific_Data_Ptr (OSD_Ptr.all);
191 end OSD;
193 ---------
194 -- SSD --
195 ---------
197 function SSD (T : Tag) return Select_Specific_Data_Ptr is
198 TSD_Ptr : constant Addr_Ptr :=
199 To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
200 TSD : constant Type_Specific_Data_Ptr :=
201 To_Type_Specific_Data_Ptr (TSD_Ptr.all);
202 begin
203 return TSD.SSD;
204 end SSD;
206 -------------------------
207 -- External_Tag_HTable --
208 -------------------------
210 type HTable_Headers is range 1 .. 64;
212 -- The following internal package defines the routines used for the
213 -- instantiation of a new System.HTable.Static_HTable (see below). See
214 -- spec in g-htable.ads for details of usage.
216 package HTable_Subprograms is
217 procedure Set_HT_Link (T : Tag; Next : Tag);
218 function Get_HT_Link (T : Tag) return Tag;
219 function Hash (F : System.Address) return HTable_Headers;
220 function Equal (A, B : System.Address) return Boolean;
221 end HTable_Subprograms;
223 package External_Tag_HTable is new System.HTable.Static_HTable (
224 Header_Num => HTable_Headers,
225 Element => Dispatch_Table,
226 Elmt_Ptr => Tag,
227 Null_Ptr => null,
228 Set_Next => HTable_Subprograms.Set_HT_Link,
229 Next => HTable_Subprograms.Get_HT_Link,
230 Key => System.Address,
231 Get_Key => Get_External_Tag,
232 Hash => HTable_Subprograms.Hash,
233 Equal => HTable_Subprograms.Equal);
235 ------------------------
236 -- HTable_Subprograms --
237 ------------------------
239 -- Bodies of routines for hash table instantiation
241 package body HTable_Subprograms is
243 -----------
244 -- Equal --
245 -----------
247 function Equal (A, B : System.Address) return Boolean is
248 Str1 : constant Cstring_Ptr := To_Cstring_Ptr (A);
249 Str2 : constant Cstring_Ptr := To_Cstring_Ptr (B);
250 J : Integer;
251 begin
252 J := 1;
253 loop
254 if Str1 (J) /= Str2 (J) then
255 return False;
256 elsif Str1 (J) = ASCII.NUL then
257 return True;
258 else
259 J := J + 1;
260 end if;
261 end loop;
262 end Equal;
264 -----------------
265 -- Get_HT_Link --
266 -----------------
268 function Get_HT_Link (T : Tag) return Tag is
269 TSD_Ptr : constant Addr_Ptr :=
270 To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
271 TSD : constant Type_Specific_Data_Ptr :=
272 To_Type_Specific_Data_Ptr (TSD_Ptr.all);
273 begin
274 return TSD.HT_Link.all;
275 end Get_HT_Link;
277 ----------
278 -- Hash --
279 ----------
281 function Hash (F : System.Address) return HTable_Headers is
282 function H is new System.HTable.Hash (HTable_Headers);
283 Str : constant Cstring_Ptr := To_Cstring_Ptr (F);
284 Res : constant HTable_Headers := H (Str (1 .. Length (Str)));
285 begin
286 return Res;
287 end Hash;
289 -----------------
290 -- Set_HT_Link --
291 -----------------
293 procedure Set_HT_Link (T : Tag; Next : Tag) is
294 TSD_Ptr : constant Addr_Ptr :=
295 To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
296 TSD : constant Type_Specific_Data_Ptr :=
297 To_Type_Specific_Data_Ptr (TSD_Ptr.all);
298 begin
299 TSD.HT_Link.all := Next;
300 end Set_HT_Link;
302 end HTable_Subprograms;
304 ------------------
305 -- Base_Address --
306 ------------------
308 function Base_Address (This : System.Address) return System.Address is
309 begin
310 return This - Offset_To_Top (This);
311 end Base_Address;
313 ---------------
314 -- Check_TSD --
315 ---------------
317 procedure Check_TSD (TSD : Type_Specific_Data_Ptr) is
318 T : Tag;
320 E_Tag_Len : constant Integer := Length (TSD.External_Tag);
321 E_Tag : String (1 .. E_Tag_Len);
322 for E_Tag'Address use TSD.External_Tag.all'Address;
323 pragma Import (Ada, E_Tag);
325 Dup_Ext_Tag : constant String := "duplicated external tag """;
327 begin
328 -- Verify that the external tag of this TSD is not registered in the
329 -- runtime hash table.
331 T := External_Tag_HTable.Get (To_Address (TSD.External_Tag));
333 if T /= null then
335 -- Avoid concatenation, as it is not allowed in no run time mode
337 declare
338 Msg : String (1 .. Dup_Ext_Tag'Length + E_Tag_Len + 1);
339 begin
340 Msg (1 .. Dup_Ext_Tag'Length) := Dup_Ext_Tag;
341 Msg (Dup_Ext_Tag'Length + 1 .. Dup_Ext_Tag'Length + E_Tag_Len) :=
342 E_Tag;
343 Msg (Msg'Last) := '"';
344 raise Program_Error with Msg;
345 end;
346 end if;
347 end Check_TSD;
349 --------------------
350 -- Descendant_Tag --
351 --------------------
353 function Descendant_Tag (External : String; Ancestor : Tag) return Tag is
354 Int_Tag : constant Tag := Internal_Tag (External);
355 begin
356 if not Is_Descendant_At_Same_Level (Int_Tag, Ancestor) then
357 raise Tag_Error;
358 else
359 return Int_Tag;
360 end if;
361 end Descendant_Tag;
363 --------------
364 -- Displace --
365 --------------
367 function Displace (This : System.Address; T : Tag) return System.Address is
368 Iface_Table : Interface_Data_Ptr;
369 Obj_Base : System.Address;
370 Obj_DT : Dispatch_Table_Ptr;
371 Obj_DT_Tag : Tag;
373 begin
374 if System."=" (This, System.Null_Address) then
375 return System.Null_Address;
376 end if;
378 Obj_Base := Base_Address (This);
379 Obj_DT_Tag := To_Tag_Ptr (Obj_Base).all;
380 Obj_DT := DT (To_Tag_Ptr (Obj_Base).all);
381 Iface_Table := To_Type_Specific_Data_Ptr (Obj_DT.TSD).Interfaces_Table;
383 if Iface_Table /= null then
384 for Id in 1 .. Iface_Table.Nb_Ifaces loop
385 if Iface_Table.Ifaces_Table (Id).Iface_Tag = T then
387 -- Case of Static value of Offset_To_Top
389 if Iface_Table.Ifaces_Table (Id).Static_Offset_To_Top then
390 Obj_Base := Obj_Base +
391 Iface_Table.Ifaces_Table (Id).Offset_To_Top_Value;
393 -- Otherwise call the function generated by the expander to
394 -- provide the value.
396 else
397 Obj_Base := Obj_Base +
398 Iface_Table.Ifaces_Table (Id).Offset_To_Top_Func.all
399 (Obj_Base);
400 end if;
402 return Obj_Base;
403 end if;
404 end loop;
405 end if;
407 -- Check if T is an immediate ancestor. This is required to handle
408 -- conversion of class-wide interfaces to tagged types.
410 if CW_Membership (Obj_DT_Tag, T) then
411 return Obj_Base;
412 end if;
414 -- If the object does not implement the interface we must raise CE
416 raise Constraint_Error with "invalid interface conversion";
417 end Displace;
419 --------
420 -- DT --
421 --------
423 function DT (T : Tag) return Dispatch_Table_Ptr is
424 Offset : constant SSE.Storage_Offset :=
425 To_Dispatch_Table_Ptr (T).Prims_Ptr'Position;
426 begin
427 return To_Dispatch_Table_Ptr (To_Address (T) - Offset);
428 end DT;
430 -------------------
431 -- IW_Membership --
432 -------------------
434 -- Canonical implementation of Classwide Membership corresponding to:
436 -- Obj in Iface'Class
438 -- Each dispatch table contains a table with the tags of all the
439 -- implemented interfaces.
441 -- Obj is in Iface'Class if Iface'Tag is found in the table of interfaces
442 -- that are contained in the dispatch table referenced by Obj'Tag.
444 function IW_Membership (This : System.Address; T : Tag) return Boolean is
445 Iface_Table : Interface_Data_Ptr;
446 Obj_Base : System.Address;
447 Obj_DT : Dispatch_Table_Ptr;
448 Obj_TSD : Type_Specific_Data_Ptr;
450 begin
451 Obj_Base := Base_Address (This);
452 Obj_DT := DT (To_Tag_Ptr (Obj_Base).all);
453 Obj_TSD := To_Type_Specific_Data_Ptr (Obj_DT.TSD);
454 Iface_Table := Obj_TSD.Interfaces_Table;
456 if Iface_Table /= null then
457 for Id in 1 .. Iface_Table.Nb_Ifaces loop
458 if Iface_Table.Ifaces_Table (Id).Iface_Tag = T then
459 return True;
460 end if;
461 end loop;
462 end if;
464 -- Look for the tag in the ancestor tags table. This is required for:
465 -- Iface_CW in Typ'Class
467 for Id in 0 .. Obj_TSD.Idepth loop
468 if Obj_TSD.Tags_Table (Id) = T then
469 return True;
470 end if;
471 end loop;
473 return False;
474 end IW_Membership;
476 -------------------
477 -- Expanded_Name --
478 -------------------
480 function Expanded_Name (T : Tag) return String is
481 Result : Cstring_Ptr;
482 TSD_Ptr : Addr_Ptr;
483 TSD : Type_Specific_Data_Ptr;
485 begin
486 if T = No_Tag then
487 raise Tag_Error;
488 end if;
490 TSD_Ptr := To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
491 TSD := To_Type_Specific_Data_Ptr (TSD_Ptr.all);
492 Result := TSD.Expanded_Name;
493 return Result (1 .. Length (Result));
494 end Expanded_Name;
496 ------------------
497 -- External_Tag --
498 ------------------
500 function External_Tag (T : Tag) return String is
501 Result : Cstring_Ptr;
502 TSD_Ptr : Addr_Ptr;
503 TSD : Type_Specific_Data_Ptr;
505 begin
506 if T = No_Tag then
507 raise Tag_Error;
508 end if;
510 TSD_Ptr := To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
511 TSD := To_Type_Specific_Data_Ptr (TSD_Ptr.all);
512 Result := TSD.External_Tag;
513 return Result (1 .. Length (Result));
514 end External_Tag;
516 ---------------------
517 -- Get_Entry_Index --
518 ---------------------
520 function Get_Entry_Index (T : Tag; Position : Positive) return Positive is
521 begin
522 return SSD (T).SSD_Table (Position).Index;
523 end Get_Entry_Index;
525 ----------------------
526 -- Get_Prim_Op_Kind --
527 ----------------------
529 function Get_Prim_Op_Kind
530 (T : Tag;
531 Position : Positive) return Prim_Op_Kind
533 begin
534 return SSD (T).SSD_Table (Position).Kind;
535 end Get_Prim_Op_Kind;
537 ----------------------
538 -- Get_Offset_Index --
539 ----------------------
541 function Get_Offset_Index
542 (T : Tag;
543 Position : Positive) return Positive
545 begin
546 if Is_Primary_DT (T) then
547 return Position;
548 else
549 return OSD (T).OSD_Table (Position);
550 end if;
551 end Get_Offset_Index;
553 ---------------------
554 -- Get_Tagged_Kind --
555 ---------------------
557 function Get_Tagged_Kind (T : Tag) return Tagged_Kind is
558 begin
559 return DT (T).Tag_Kind;
560 end Get_Tagged_Kind;
562 -----------------------------
563 -- Interface_Ancestor_Tags --
564 -----------------------------
566 function Interface_Ancestor_Tags (T : Tag) return Tag_Array is
567 TSD_Ptr : constant Addr_Ptr :=
568 To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
569 TSD : constant Type_Specific_Data_Ptr :=
570 To_Type_Specific_Data_Ptr (TSD_Ptr.all);
571 Iface_Table : constant Interface_Data_Ptr := TSD.Interfaces_Table;
573 begin
574 if Iface_Table = null then
575 declare
576 Table : Tag_Array (1 .. 0);
577 begin
578 return Table;
579 end;
581 else
582 declare
583 Table : Tag_Array (1 .. Iface_Table.Nb_Ifaces);
584 begin
585 for J in 1 .. Iface_Table.Nb_Ifaces loop
586 Table (J) := Iface_Table.Ifaces_Table (J).Iface_Tag;
587 end loop;
589 return Table;
590 end;
591 end if;
592 end Interface_Ancestor_Tags;
594 ------------------
595 -- Internal_Tag --
596 ------------------
598 -- Internal tags have the following format:
599 -- "Internal tag at 16#ADDRESS#: <full-name-of-tagged-type>"
601 Internal_Tag_Header : constant String := "Internal tag at ";
602 Header_Separator : constant Character := '#';
604 function Internal_Tag (External : String) return Tag is
605 Ext_Copy : aliased String (External'First .. External'Last + 1);
606 Res : Tag := null;
608 begin
609 -- Handle locally defined tagged types
611 if External'Length > Internal_Tag_Header'Length
612 and then
613 External (External'First ..
614 External'First + Internal_Tag_Header'Length - 1) =
615 Internal_Tag_Header
616 then
617 declare
618 Addr_First : constant Natural :=
619 External'First + Internal_Tag_Header'Length;
620 Addr_Last : Natural;
621 Addr : Integer_Address;
623 begin
624 -- Search the second separator (#) to identify the address
626 Addr_Last := Addr_First;
628 for J in 1 .. 2 loop
629 while Addr_Last <= External'Last
630 and then External (Addr_Last) /= Header_Separator
631 loop
632 Addr_Last := Addr_Last + 1;
633 end loop;
635 -- Skip the first separator
637 if J = 1 then
638 Addr_Last := Addr_Last + 1;
639 end if;
640 end loop;
642 if Addr_Last <= External'Last then
644 -- Protect the run-time against wrong internal tags. We
645 -- cannot use exception handlers here because it would
646 -- disable the use of this run-time compiling with
647 -- restriction No_Exception_Handler.
649 declare
650 C : Character;
651 Wrong_Tag : Boolean := False;
653 begin
654 if External (Addr_First) /= '1'
655 or else External (Addr_First + 1) /= '6'
656 or else External (Addr_First + 2) /= '#'
657 then
658 Wrong_Tag := True;
660 else
661 for J in Addr_First + 3 .. Addr_Last - 1 loop
662 C := External (J);
664 if not (C in '0' .. '9')
665 and then not (C in 'A' .. 'F')
666 and then not (C in 'a' .. 'f')
667 then
668 Wrong_Tag := True;
669 exit;
670 end if;
671 end loop;
672 end if;
674 -- Convert the numeric value into a tag
676 if not Wrong_Tag then
677 Addr := Integer_Address'Value
678 (External (Addr_First .. Addr_Last));
680 -- Internal tags never have value 0
682 if Addr /= 0 then
683 return To_Tag (Addr);
684 end if;
685 end if;
686 end;
687 end if;
688 end;
690 -- Handle library-level tagged types
692 else
693 -- Make NUL-terminated copy of external tag string
695 Ext_Copy (External'Range) := External;
696 Ext_Copy (Ext_Copy'Last) := ASCII.NUL;
697 Res := External_Tag_HTable.Get (Ext_Copy'Address);
698 end if;
700 if Res = null then
701 declare
702 Msg1 : constant String := "unknown tagged type: ";
703 Msg2 : String (1 .. Msg1'Length + External'Length);
705 begin
706 Msg2 (1 .. Msg1'Length) := Msg1;
707 Msg2 (Msg1'Length + 1 .. Msg1'Length + External'Length) :=
708 External;
709 Ada.Exceptions.Raise_Exception (Tag_Error'Identity, Msg2);
710 end;
711 end if;
713 return Res;
714 end Internal_Tag;
716 ---------------------------------
717 -- Is_Descendant_At_Same_Level --
718 ---------------------------------
720 function Is_Descendant_At_Same_Level
721 (Descendant : Tag;
722 Ancestor : Tag) return Boolean
724 D_TSD_Ptr : constant Addr_Ptr :=
725 To_Addr_Ptr (To_Address (Descendant) - DT_Typeinfo_Ptr_Size);
726 A_TSD_Ptr : constant Addr_Ptr :=
727 To_Addr_Ptr (To_Address (Ancestor) - DT_Typeinfo_Ptr_Size);
728 D_TSD : constant Type_Specific_Data_Ptr :=
729 To_Type_Specific_Data_Ptr (D_TSD_Ptr.all);
730 A_TSD : constant Type_Specific_Data_Ptr :=
731 To_Type_Specific_Data_Ptr (A_TSD_Ptr.all);
733 begin
734 return CW_Membership (Descendant, Ancestor)
735 and then D_TSD.Access_Level = A_TSD.Access_Level;
736 end Is_Descendant_At_Same_Level;
738 ------------
739 -- Length --
740 ------------
742 -- Note: This unit is used in the Ravenscar runtime library, so it cannot
743 -- depend on System.CTRL. Furthermore, this happens on CPUs where the GCC
744 -- intrinsic strlen may not be available, so we need to recode our own Ada
745 -- version here.
747 function Length (Str : Cstring_Ptr) return Natural is
748 Len : Integer;
750 begin
751 Len := 1;
752 while Str (Len) /= ASCII.NUL loop
753 Len := Len + 1;
754 end loop;
756 return Len - 1;
757 end Length;
759 -------------------
760 -- Offset_To_Top --
761 -------------------
763 function Offset_To_Top
764 (This : System.Address) return SSE.Storage_Offset
766 Tag_Size : constant SSE.Storage_Count :=
767 SSE.Storage_Count (1 * (Standard'Address_Size / System.Storage_Unit));
769 type Storage_Offset_Ptr is access SSE.Storage_Offset;
770 function To_Storage_Offset_Ptr is
771 new Unchecked_Conversion (System.Address, Storage_Offset_Ptr);
773 Curr_DT : Dispatch_Table_Ptr;
775 begin
776 Curr_DT := DT (To_Tag_Ptr (This).all);
778 if Curr_DT.Offset_To_Top = SSE.Storage_Offset'Last then
779 return To_Storage_Offset_Ptr (This + Tag_Size).all;
780 else
781 return Curr_DT.Offset_To_Top;
782 end if;
783 end Offset_To_Top;
785 ------------------------
786 -- Needs_Finalization --
787 ------------------------
789 function Needs_Finalization (T : Tag) return Boolean is
790 TSD_Ptr : constant Addr_Ptr :=
791 To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
792 TSD : constant Type_Specific_Data_Ptr :=
793 To_Type_Specific_Data_Ptr (TSD_Ptr.all);
794 begin
795 return TSD.Needs_Finalization;
796 end Needs_Finalization;
798 -----------------
799 -- Parent_Size --
800 -----------------
802 function Parent_Size
803 (Obj : System.Address;
804 T : Tag) return SSE.Storage_Count
806 Parent_Slot : constant Positive := 1;
807 -- The tag of the parent is always in the first slot of the table of
808 -- ancestor tags.
810 TSD_Ptr : constant Addr_Ptr :=
811 To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
812 TSD : constant Type_Specific_Data_Ptr :=
813 To_Type_Specific_Data_Ptr (TSD_Ptr.all);
814 -- Pointer to the TSD
816 Parent_Tag : constant Tag := TSD.Tags_Table (Parent_Slot);
817 Parent_TSD_Ptr : constant Addr_Ptr :=
818 To_Addr_Ptr (To_Address (Parent_Tag) - DT_Typeinfo_Ptr_Size);
819 Parent_TSD : constant Type_Specific_Data_Ptr :=
820 To_Type_Specific_Data_Ptr (Parent_TSD_Ptr.all);
822 begin
823 -- Here we compute the size of the _parent field of the object
825 return SSE.Storage_Count (Parent_TSD.Size_Func.all (Obj));
826 end Parent_Size;
828 ----------------
829 -- Parent_Tag --
830 ----------------
832 function Parent_Tag (T : Tag) return Tag is
833 TSD_Ptr : Addr_Ptr;
834 TSD : Type_Specific_Data_Ptr;
836 begin
837 if T = No_Tag then
838 raise Tag_Error;
839 end if;
841 TSD_Ptr := To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
842 TSD := To_Type_Specific_Data_Ptr (TSD_Ptr.all);
844 -- The Parent_Tag of a root-level tagged type is defined to be No_Tag.
845 -- The first entry in the Ancestors_Tags array will be null for such
846 -- a type, but it's better to be explicit about returning No_Tag in
847 -- this case.
849 if TSD.Idepth = 0 then
850 return No_Tag;
851 else
852 return TSD.Tags_Table (1);
853 end if;
854 end Parent_Tag;
856 -------------------------------
857 -- Register_Interface_Offset --
858 -------------------------------
860 procedure Register_Interface_Offset
861 (This : System.Address;
862 Interface_T : Tag;
863 Is_Static : Boolean;
864 Offset_Value : SSE.Storage_Offset;
865 Offset_Func : Offset_To_Top_Function_Ptr)
867 Prim_DT : Dispatch_Table_Ptr;
868 Iface_Table : Interface_Data_Ptr;
870 begin
871 -- "This" points to the primary DT and we must save Offset_Value in
872 -- the Offset_To_Top field of the corresponding dispatch table.
874 Prim_DT := DT (To_Tag_Ptr (This).all);
875 Iface_Table := To_Type_Specific_Data_Ptr (Prim_DT.TSD).Interfaces_Table;
877 -- Save Offset_Value in the table of interfaces of the primary DT.
878 -- This data will be used by the subprogram "Displace" to give support
879 -- to backward abstract interface type conversions.
881 -- Register the offset in the table of interfaces
883 if Iface_Table /= null then
884 for Id in 1 .. Iface_Table.Nb_Ifaces loop
885 if Iface_Table.Ifaces_Table (Id).Iface_Tag = Interface_T then
886 if Is_Static or else Offset_Value = 0 then
887 Iface_Table.Ifaces_Table (Id).Static_Offset_To_Top := True;
888 Iface_Table.Ifaces_Table (Id).Offset_To_Top_Value :=
889 Offset_Value;
890 else
891 Iface_Table.Ifaces_Table (Id).Static_Offset_To_Top := False;
892 Iface_Table.Ifaces_Table (Id).Offset_To_Top_Func :=
893 Offset_Func;
894 end if;
896 return;
897 end if;
898 end loop;
899 end if;
901 -- If we arrive here there is some error in the run-time data structure
903 raise Program_Error;
904 end Register_Interface_Offset;
906 ------------------
907 -- Register_Tag --
908 ------------------
910 procedure Register_Tag (T : Tag) is
911 begin
912 External_Tag_HTable.Set (T);
913 end Register_Tag;
915 -------------------
916 -- Secondary_Tag --
917 -------------------
919 function Secondary_Tag (T, Iface : Tag) return Tag is
920 Iface_Table : Interface_Data_Ptr;
921 Obj_DT : Dispatch_Table_Ptr;
923 begin
924 if not Is_Primary_DT (T) then
925 raise Program_Error;
926 end if;
928 Obj_DT := DT (T);
929 Iface_Table := To_Type_Specific_Data_Ptr (Obj_DT.TSD).Interfaces_Table;
931 if Iface_Table /= null then
932 for Id in 1 .. Iface_Table.Nb_Ifaces loop
933 if Iface_Table.Ifaces_Table (Id).Iface_Tag = Iface then
934 return Iface_Table.Ifaces_Table (Id).Secondary_DT;
935 end if;
936 end loop;
937 end if;
939 -- If the object does not implement the interface we must raise CE
941 raise Constraint_Error with "invalid interface conversion";
942 end Secondary_Tag;
944 ---------------------
945 -- Set_Entry_Index --
946 ---------------------
948 procedure Set_Entry_Index
949 (T : Tag;
950 Position : Positive;
951 Value : Positive)
953 begin
954 SSD (T).SSD_Table (Position).Index := Value;
955 end Set_Entry_Index;
957 -----------------------
958 -- Set_Offset_To_Top --
959 -----------------------
961 procedure Set_Dynamic_Offset_To_Top
962 (This : System.Address;
963 Interface_T : Tag;
964 Offset_Value : SSE.Storage_Offset;
965 Offset_Func : Offset_To_Top_Function_Ptr)
967 Sec_Base : System.Address;
968 Sec_DT : Dispatch_Table_Ptr;
970 begin
971 -- Save the offset to top field in the secondary dispatch table
973 if Offset_Value /= 0 then
974 Sec_Base := This + Offset_Value;
975 Sec_DT := DT (To_Tag_Ptr (Sec_Base).all);
976 Sec_DT.Offset_To_Top := SSE.Storage_Offset'Last;
977 end if;
979 Register_Interface_Offset
980 (This, Interface_T, False, Offset_Value, Offset_Func);
981 end Set_Dynamic_Offset_To_Top;
983 ----------------------
984 -- Set_Prim_Op_Kind --
985 ----------------------
987 procedure Set_Prim_Op_Kind
988 (T : Tag;
989 Position : Positive;
990 Value : Prim_Op_Kind)
992 begin
993 SSD (T).SSD_Table (Position).Kind := Value;
994 end Set_Prim_Op_Kind;
996 ----------------------
997 -- Type_Is_Abstract --
998 ----------------------
1000 function Type_Is_Abstract (T : Tag) return Boolean is
1001 TSD_Ptr : Addr_Ptr;
1002 TSD : Type_Specific_Data_Ptr;
1004 begin
1005 if T = No_Tag then
1006 raise Tag_Error;
1007 end if;
1009 TSD_Ptr := To_Addr_Ptr (To_Address (T) - DT_Typeinfo_Ptr_Size);
1010 TSD := To_Type_Specific_Data_Ptr (TSD_Ptr.all);
1011 return TSD.Type_Is_Abstract;
1012 end Type_Is_Abstract;
1014 --------------------
1015 -- Unregister_Tag --
1016 --------------------
1018 procedure Unregister_Tag (T : Tag) is
1019 begin
1020 External_Tag_HTable.Remove (Get_External_Tag (T));
1021 end Unregister_Tag;
1023 ------------------------
1024 -- Wide_Expanded_Name --
1025 ------------------------
1027 WC_Encoding : Character;
1028 pragma Import (C, WC_Encoding, "__gl_wc_encoding");
1029 -- Encoding method for source, as exported by binder
1031 function Wide_Expanded_Name (T : Tag) return Wide_String is
1032 S : constant String := Expanded_Name (T);
1033 W : Wide_String (1 .. S'Length);
1034 L : Natural;
1035 begin
1036 String_To_Wide_String
1037 (S, W, L, Get_WC_Encoding_Method (WC_Encoding));
1038 return W (1 .. L);
1039 end Wide_Expanded_Name;
1041 -----------------------------
1042 -- Wide_Wide_Expanded_Name --
1043 -----------------------------
1045 function Wide_Wide_Expanded_Name (T : Tag) return Wide_Wide_String is
1046 S : constant String := Expanded_Name (T);
1047 W : Wide_Wide_String (1 .. S'Length);
1048 L : Natural;
1049 begin
1050 String_To_Wide_Wide_String
1051 (S, W, L, Get_WC_Encoding_Method (WC_Encoding));
1052 return W (1 .. L);
1053 end Wide_Wide_Expanded_Name;
1055 end Ada.Tags;