1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME COMPONENTS --
9 -- Copyright (C) 1992-2017, Free Software Foundation, Inc. --
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. --
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. --
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/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
33 with Ada
.Unchecked_Conversion
;
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
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 IW_Membership
65 (Descendant_TSD
: Type_Specific_Data_Ptr
;
66 T
: Tag
) return Boolean;
67 -- Subsidiary function of IW_Membership and CW_Membership which factorizes
68 -- the functionality needed to check if a given descendant implements an
71 function Length
(Str
: Cstring_Ptr
) return Natural;
72 -- Length of string represented by the given pointer (treating the string
73 -- as a C-style string, which is Nul terminated). See comment in body
74 -- explaining why we cannot use the normal strlen built-in.
76 function OSD
(T
: Tag
) return Object_Specific_Data_Ptr
;
77 -- Ada 2005 (AI-251): Given a pointer T to a secondary dispatch table,
78 -- retrieve the address of the record containing the Object Specific
81 function SSD
(T
: Tag
) return Select_Specific_Data_Ptr
;
82 -- Ada 2005 (AI-251): Given a pointer T to a dispatch Table, retrieves the
83 -- address of the record containing the Select Specific Data in T's TSD.
85 pragma Inline_Always
(CW_Membership
);
86 pragma Inline_Always
(Get_External_Tag
);
87 pragma Inline_Always
(Is_Primary_DT
);
88 pragma Inline_Always
(OSD
);
89 pragma Inline_Always
(SSD
);
91 -- Unchecked conversions
93 function To_Address
is
94 new Unchecked_Conversion
(Cstring_Ptr
, System
.Address
);
96 function To_Cstring_Ptr
is
97 new Unchecked_Conversion
(System
.Address
, Cstring_Ptr
);
99 -- Disable warnings on possible aliasing problem
102 new Unchecked_Conversion
(Integer_Address
, Tag
);
104 function To_Addr_Ptr
is
105 new Ada
.Unchecked_Conversion
(System
.Address
, Addr_Ptr
);
107 function To_Address
is
108 new Ada
.Unchecked_Conversion
(Tag
, System
.Address
);
110 function To_Dispatch_Table_Ptr
is
111 new Ada
.Unchecked_Conversion
(Tag
, Dispatch_Table_Ptr
);
113 function To_Dispatch_Table_Ptr
is
114 new Ada
.Unchecked_Conversion
(System
.Address
, Dispatch_Table_Ptr
);
116 function To_Object_Specific_Data_Ptr
is
117 new Ada
.Unchecked_Conversion
(System
.Address
, Object_Specific_Data_Ptr
);
119 function To_Tag_Ptr
is
120 new Ada
.Unchecked_Conversion
(System
.Address
, Tag_Ptr
);
122 function To_Type_Specific_Data_Ptr
is
123 new Ada
.Unchecked_Conversion
(System
.Address
, Type_Specific_Data_Ptr
);
125 -------------------------------
126 -- Inline_Always Subprograms --
127 -------------------------------
129 -- Inline_always subprograms must be placed before their first call to
130 -- avoid defeating the frontend inlining mechanism and thus ensure the
131 -- generation of their correct debug info.
137 -- Canonical implementation of Classwide Membership corresponding to:
141 -- Each dispatch table contains a reference to a table of ancestors (stored
142 -- in the first part of the Tags_Table) and a count of the level of
143 -- inheritance "Idepth".
145 -- Obj is in Typ'Class if Typ'Tag is in the table of ancestors that are
146 -- contained in the dispatch table referenced by Obj'Tag . Knowing the
147 -- level of inheritance of both types, this can be computed in constant
148 -- time by the formula:
150 -- TSD (Obj'tag).Tags_Table (TSD (Obj'tag).Idepth - TSD (Typ'tag).Idepth)
153 function CW_Membership
(Obj_Tag
: Tag
; Typ_Tag
: Tag
) return Boolean is
154 Obj_TSD_Ptr
: constant Addr_Ptr
:=
155 To_Addr_Ptr
(To_Address
(Obj_Tag
) - DT_Typeinfo_Ptr_Size
);
156 Typ_TSD_Ptr
: constant Addr_Ptr
:=
157 To_Addr_Ptr
(To_Address
(Typ_Tag
) - DT_Typeinfo_Ptr_Size
);
158 Obj_TSD
: constant Type_Specific_Data_Ptr
:=
159 To_Type_Specific_Data_Ptr
(Obj_TSD_Ptr
.all);
160 Typ_TSD
: constant Type_Specific_Data_Ptr
:=
161 To_Type_Specific_Data_Ptr
(Typ_TSD_Ptr
.all);
162 Pos
: constant Integer := Obj_TSD
.Idepth
- Typ_TSD
.Idepth
;
164 return Pos
>= 0 and then Obj_TSD
.Tags_Table
(Pos
) = Typ_Tag
;
167 ----------------------
168 -- Get_External_Tag --
169 ----------------------
171 function Get_External_Tag
(T
: Tag
) return System
.Address
is
172 TSD_Ptr
: constant Addr_Ptr
:=
173 To_Addr_Ptr
(To_Address
(T
) - DT_Typeinfo_Ptr_Size
);
174 TSD
: constant Type_Specific_Data_Ptr
:=
175 To_Type_Specific_Data_Ptr
(TSD_Ptr
.all);
177 return To_Address
(TSD
.External_Tag
);
178 end Get_External_Tag
;
184 function Is_Abstract
(T
: Tag
) return Boolean is
186 TSD
: Type_Specific_Data_Ptr
;
193 TSD_Ptr
:= To_Addr_Ptr
(To_Address
(T
) - DT_Typeinfo_Ptr_Size
);
194 TSD
:= To_Type_Specific_Data_Ptr
(TSD_Ptr
.all);
195 return TSD
.Is_Abstract
;
202 function Is_Primary_DT
(T
: Tag
) return Boolean is
204 return DT
(T
).Signature
= Primary_DT
;
211 function OSD
(T
: Tag
) return Object_Specific_Data_Ptr
is
212 OSD_Ptr
: constant Addr_Ptr
:=
213 To_Addr_Ptr
(To_Address
(T
) - DT_Typeinfo_Ptr_Size
);
215 return To_Object_Specific_Data_Ptr
(OSD_Ptr
.all);
222 function SSD
(T
: Tag
) return Select_Specific_Data_Ptr
is
223 TSD_Ptr
: constant Addr_Ptr
:=
224 To_Addr_Ptr
(To_Address
(T
) - DT_Typeinfo_Ptr_Size
);
225 TSD
: constant Type_Specific_Data_Ptr
:=
226 To_Type_Specific_Data_Ptr
(TSD_Ptr
.all);
231 -------------------------
232 -- External_Tag_HTable --
233 -------------------------
235 type HTable_Headers
is range 1 .. 64;
237 -- The following internal package defines the routines used for the
238 -- instantiation of a new System.HTable.Static_HTable (see below). See
239 -- spec in g-htable.ads for details of usage.
241 package HTable_Subprograms
is
242 procedure Set_HT_Link
(T
: Tag
; Next
: Tag
);
243 function Get_HT_Link
(T
: Tag
) return Tag
;
244 function Hash
(F
: System
.Address
) return HTable_Headers
;
245 function Equal
(A
, B
: System
.Address
) return Boolean;
246 end HTable_Subprograms
;
248 package External_Tag_HTable
is new System
.HTable
.Static_HTable
(
249 Header_Num
=> HTable_Headers
,
250 Element
=> Dispatch_Table
,
253 Set_Next
=> HTable_Subprograms
.Set_HT_Link
,
254 Next
=> HTable_Subprograms
.Get_HT_Link
,
255 Key
=> System
.Address
,
256 Get_Key
=> Get_External_Tag
,
257 Hash
=> HTable_Subprograms
.Hash
,
258 Equal
=> HTable_Subprograms
.Equal
);
260 ------------------------
261 -- HTable_Subprograms --
262 ------------------------
264 -- Bodies of routines for hash table instantiation
266 package body HTable_Subprograms
is
272 function Equal
(A
, B
: System
.Address
) return Boolean is
273 Str1
: constant Cstring_Ptr
:= To_Cstring_Ptr
(A
);
274 Str2
: constant Cstring_Ptr
:= To_Cstring_Ptr
(B
);
279 if Str1
(J
) /= Str2
(J
) then
281 elsif Str1
(J
) = ASCII
.NUL
then
293 function Get_HT_Link
(T
: Tag
) return 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);
299 return TSD
.HT_Link
.all;
306 function Hash
(F
: System
.Address
) return HTable_Headers
is
307 function H
is new System
.HTable
.Hash
(HTable_Headers
);
308 Str
: constant Cstring_Ptr
:= To_Cstring_Ptr
(F
);
309 Res
: constant HTable_Headers
:= H
(Str
(1 .. Length
(Str
)));
318 procedure Set_HT_Link
(T
: Tag
; Next
: Tag
) is
319 TSD_Ptr
: constant Addr_Ptr
:=
320 To_Addr_Ptr
(To_Address
(T
) - DT_Typeinfo_Ptr_Size
);
321 TSD
: constant Type_Specific_Data_Ptr
:=
322 To_Type_Specific_Data_Ptr
(TSD_Ptr
.all);
324 TSD
.HT_Link
.all := Next
;
327 end HTable_Subprograms
;
333 function Base_Address
(This
: System
.Address
) return System
.Address
is
335 return This
+ Offset_To_Top
(This
);
342 procedure Check_TSD
(TSD
: Type_Specific_Data_Ptr
) is
345 E_Tag_Len
: constant Integer := Length
(TSD
.External_Tag
);
346 E_Tag
: String (1 .. E_Tag_Len
);
347 for E_Tag
'Address use TSD
.External_Tag
.all'Address;
348 pragma Import
(Ada
, E_Tag
);
350 Dup_Ext_Tag
: constant String := "duplicated external tag """;
353 -- Verify that the external tag of this TSD is not registered in the
354 -- runtime hash table.
356 T
:= External_Tag_HTable
.Get
(To_Address
(TSD
.External_Tag
));
360 -- Avoid concatenation, as it is not allowed in no run time mode
363 Msg
: String (1 .. Dup_Ext_Tag
'Length + E_Tag_Len
+ 1);
365 Msg
(1 .. Dup_Ext_Tag
'Length) := Dup_Ext_Tag
;
366 Msg
(Dup_Ext_Tag
'Length + 1 .. Dup_Ext_Tag
'Length + E_Tag_Len
) :=
368 Msg
(Msg
'Last) := '"';
369 raise Program_Error
with Msg
;
378 function Descendant_Tag
(External
: String; Ancestor
: Tag
) return Tag
is
379 Int_Tag
: constant Tag
:= Internal_Tag
(External
);
381 if not Is_Descendant_At_Same_Level
(Int_Tag
, Ancestor
) then
392 function Displace
(This
: System
.Address
; T
: Tag
) return System
.Address
is
393 Iface_Table
: Interface_Data_Ptr
;
394 Obj_Base
: System
.Address
;
395 Obj_DT
: Dispatch_Table_Ptr
;
399 if System
."=" (This
, System
.Null_Address
) then
400 return System
.Null_Address
;
403 Obj_Base
:= Base_Address
(This
);
404 Obj_DT_Tag
:= To_Tag_Ptr
(Obj_Base
).all;
405 Obj_DT
:= DT
(To_Tag_Ptr
(Obj_Base
).all);
406 Iface_Table
:= To_Type_Specific_Data_Ptr
(Obj_DT
.TSD
).Interfaces_Table
;
408 if Iface_Table
/= null then
409 for Id
in 1 .. Iface_Table
.Nb_Ifaces
loop
410 if Iface_Table
.Ifaces_Table
(Id
).Iface_Tag
= T
then
412 -- Case of Static value of Offset_To_Top
414 if Iface_Table
.Ifaces_Table
(Id
).Static_Offset_To_Top
then
415 Obj_Base
:= Obj_Base
-
416 Iface_Table
.Ifaces_Table
(Id
).Offset_To_Top_Value
;
418 -- Otherwise call the function generated by the expander to
419 -- provide the value.
422 Obj_Base
:= Obj_Base
-
423 Iface_Table
.Ifaces_Table
(Id
).Offset_To_Top_Func
.all
432 -- Check if T is an immediate ancestor. This is required to handle
433 -- conversion of class-wide interfaces to tagged types.
435 if CW_Membership
(Obj_DT_Tag
, T
) then
439 -- If the object does not implement the interface we must raise CE
441 raise Constraint_Error
with "invalid interface conversion";
448 function DT
(T
: Tag
) return Dispatch_Table_Ptr
is
449 Offset
: constant SSE
.Storage_Offset
:=
450 To_Dispatch_Table_Ptr
(T
).Prims_Ptr
'Position;
452 return To_Dispatch_Table_Ptr
(To_Address
(T
) - Offset
);
459 function IW_Membership
460 (Descendant_TSD
: Type_Specific_Data_Ptr
;
461 T
: Tag
) return Boolean
463 Iface_Table
: Interface_Data_Ptr
;
466 Iface_Table
:= Descendant_TSD
.Interfaces_Table
;
468 if Iface_Table
/= null then
469 for Id
in 1 .. Iface_Table
.Nb_Ifaces
loop
470 if Iface_Table
.Ifaces_Table
(Id
).Iface_Tag
= T
then
476 -- Look for the tag in the ancestor tags table. This is required for:
477 -- Iface_CW in Typ'Class
479 for Id
in 0 .. Descendant_TSD
.Idepth
loop
480 if Descendant_TSD
.Tags_Table
(Id
) = T
then
492 -- Canonical implementation of Classwide Membership corresponding to:
494 -- Obj in Iface'Class
496 -- Each dispatch table contains a table with the tags of all the
497 -- implemented interfaces.
499 -- Obj is in Iface'Class if Iface'Tag is found in the table of interfaces
500 -- that are contained in the dispatch table referenced by Obj'Tag.
502 function IW_Membership
(This
: System
.Address
; T
: Tag
) return Boolean is
503 Obj_Base
: System
.Address
;
504 Obj_DT
: Dispatch_Table_Ptr
;
505 Obj_TSD
: Type_Specific_Data_Ptr
;
508 Obj_Base
:= Base_Address
(This
);
509 Obj_DT
:= DT
(To_Tag_Ptr
(Obj_Base
).all);
510 Obj_TSD
:= To_Type_Specific_Data_Ptr
(Obj_DT
.TSD
);
512 return IW_Membership
(Obj_TSD
, T
);
519 function Expanded_Name
(T
: Tag
) return String is
520 Result
: Cstring_Ptr
;
522 TSD
: Type_Specific_Data_Ptr
;
529 TSD_Ptr
:= To_Addr_Ptr
(To_Address
(T
) - DT_Typeinfo_Ptr_Size
);
530 TSD
:= To_Type_Specific_Data_Ptr
(TSD_Ptr
.all);
531 Result
:= TSD
.Expanded_Name
;
532 return Result
(1 .. Length
(Result
));
539 function External_Tag
(T
: Tag
) return String is
540 Result
: Cstring_Ptr
;
542 TSD
: Type_Specific_Data_Ptr
;
549 TSD_Ptr
:= To_Addr_Ptr
(To_Address
(T
) - DT_Typeinfo_Ptr_Size
);
550 TSD
:= To_Type_Specific_Data_Ptr
(TSD_Ptr
.all);
551 Result
:= TSD
.External_Tag
;
552 return Result
(1 .. Length
(Result
));
555 ---------------------
556 -- Get_Entry_Index --
557 ---------------------
559 function Get_Entry_Index
(T
: Tag
; Position
: Positive) return Positive is
561 return SSD
(T
).SSD_Table
(Position
).Index
;
564 ----------------------
565 -- Get_Prim_Op_Kind --
566 ----------------------
568 function Get_Prim_Op_Kind
570 Position
: Positive) return Prim_Op_Kind
573 return SSD
(T
).SSD_Table
(Position
).Kind
;
574 end Get_Prim_Op_Kind
;
576 ----------------------
577 -- Get_Offset_Index --
578 ----------------------
580 function Get_Offset_Index
582 Position
: Positive) return Positive
585 if Is_Primary_DT
(T
) then
588 return OSD
(T
).OSD_Table
(Position
);
590 end Get_Offset_Index
;
592 ---------------------
593 -- Get_Tagged_Kind --
594 ---------------------
596 function Get_Tagged_Kind
(T
: Tag
) return Tagged_Kind
is
598 return DT
(T
).Tag_Kind
;
601 -----------------------------
602 -- Interface_Ancestor_Tags --
603 -----------------------------
605 function Interface_Ancestor_Tags
(T
: Tag
) return Tag_Array
is
606 TSD_Ptr
: constant Addr_Ptr
:=
607 To_Addr_Ptr
(To_Address
(T
) - DT_Typeinfo_Ptr_Size
);
608 TSD
: constant Type_Specific_Data_Ptr
:=
609 To_Type_Specific_Data_Ptr
(TSD_Ptr
.all);
610 Iface_Table
: constant Interface_Data_Ptr
:= TSD
.Interfaces_Table
;
613 if Iface_Table
= null then
615 Table
: Tag_Array
(1 .. 0);
622 Table
: Tag_Array
(1 .. Iface_Table
.Nb_Ifaces
);
624 for J
in 1 .. Iface_Table
.Nb_Ifaces
loop
625 Table
(J
) := Iface_Table
.Ifaces_Table
(J
).Iface_Tag
;
631 end Interface_Ancestor_Tags
;
637 -- Internal tags have the following format:
638 -- "Internal tag at 16#ADDRESS#: <full-name-of-tagged-type>"
640 Internal_Tag_Header
: constant String := "Internal tag at ";
641 Header_Separator
: constant Character := '#';
643 function Internal_Tag
(External
: String) return Tag
is
644 pragma Unsuppress
(All_Checks
);
645 -- To make T'Class'Input robust in the case of bad data
650 -- Raise Tag_Error for empty strings and very long strings. This makes
651 -- T'Class'Input robust in the case of bad data, for example
653 -- String (123456789..1234)
655 -- The limit of 10,000 characters is arbitrary, but is unlikely to be
656 -- exceeded by legitimate external tag names.
658 if External
'Length not in 1 .. 10_000
then
662 -- Handle locally defined tagged types
664 if External
'Length > Internal_Tag_Header
'Length
666 External
(External
'First ..
667 External
'First + Internal_Tag_Header
'Length - 1) =
671 Addr_First
: constant Natural :=
672 External
'First + Internal_Tag_Header
'Length;
674 Addr
: Integer_Address
;
677 -- Search the second separator (#) to identify the address
679 Addr_Last
:= Addr_First
;
682 while Addr_Last
<= External
'Last
683 and then External
(Addr_Last
) /= Header_Separator
685 Addr_Last
:= Addr_Last
+ 1;
688 -- Skip the first separator
691 Addr_Last
:= Addr_Last
+ 1;
695 if Addr_Last
<= External
'Last then
697 -- Protect the run-time against wrong internal tags. We
698 -- cannot use exception handlers here because it would
699 -- disable the use of this run-time compiling with
700 -- restriction No_Exception_Handler.
704 Wrong_Tag
: Boolean := False;
707 if External
(Addr_First
) /= '1'
708 or else External
(Addr_First
+ 1) /= '6'
709 or else External
(Addr_First
+ 2) /= '#'
714 for J
in Addr_First
+ 3 .. Addr_Last
- 1 loop
717 if not (C
in '0' .. '9')
718 and then not (C
in 'A' .. 'F')
719 and then not (C
in 'a' .. 'f')
727 -- Convert the numeric value into a tag
729 if not Wrong_Tag
then
730 Addr
:= Integer_Address
'Value
731 (External
(Addr_First
.. Addr_Last
));
733 -- Internal tags never have value 0
736 return To_Tag
(Addr
);
743 -- Handle library-level tagged types
746 -- Make NUL-terminated copy of external tag string
749 Ext_Copy
: aliased String (External
'First .. External
'Last + 1);
750 pragma Assert
(Ext_Copy
'Length > 1); -- See Length check at top
752 Ext_Copy
(External
'Range) := External
;
753 Ext_Copy
(Ext_Copy
'Last) := ASCII
.NUL
;
754 Res
:= External_Tag_HTable
.Get
(Ext_Copy
'Address);
760 Msg1
: constant String := "unknown tagged type: ";
761 Msg2
: String (1 .. Msg1
'Length + External
'Length);
764 Msg2
(1 .. Msg1
'Length) := Msg1
;
765 Msg2
(Msg1
'Length + 1 .. Msg1
'Length + External
'Length) :=
767 Ada
.Exceptions
.Raise_Exception
(Tag_Error
'Identity, Msg2
);
774 ---------------------------------
775 -- Is_Descendant_At_Same_Level --
776 ---------------------------------
778 function Is_Descendant_At_Same_Level
780 Ancestor
: Tag
) return Boolean
783 if Descendant
= Ancestor
then
788 D_TSD_Ptr
: constant Addr_Ptr
:=
789 To_Addr_Ptr
(To_Address
(Descendant
) - DT_Typeinfo_Ptr_Size
);
790 A_TSD_Ptr
: constant Addr_Ptr
:=
791 To_Addr_Ptr
(To_Address
(Ancestor
) - DT_Typeinfo_Ptr_Size
);
792 D_TSD
: constant Type_Specific_Data_Ptr
:=
793 To_Type_Specific_Data_Ptr
(D_TSD_Ptr
.all);
794 A_TSD
: constant Type_Specific_Data_Ptr
:=
795 To_Type_Specific_Data_Ptr
(A_TSD_Ptr
.all);
798 D_TSD
.Access_Level
= A_TSD
.Access_Level
799 and then (CW_Membership
(Descendant
, Ancestor
)
800 or else IW_Membership
(D_TSD
, Ancestor
));
803 end Is_Descendant_At_Same_Level
;
809 -- Note: This unit is used in the Ravenscar runtime library, so it cannot
810 -- depend on System.CTRL. Furthermore, this happens on CPUs where the GCC
811 -- intrinsic strlen may not be available, so we need to recode our own Ada
814 function Length
(Str
: Cstring_Ptr
) return Natural is
819 while Str
(Len
) /= ASCII
.NUL
loop
830 function Offset_To_Top
831 (This
: System
.Address
) return SSE
.Storage_Offset
833 Tag_Size
: constant SSE
.Storage_Count
:=
834 SSE
.Storage_Count
(1 * (Standard
'Address_Size / System
.Storage_Unit
));
836 type Storage_Offset_Ptr
is access SSE
.Storage_Offset
;
837 function To_Storage_Offset_Ptr
is
838 new Unchecked_Conversion
(System
.Address
, Storage_Offset_Ptr
);
840 Curr_DT
: Dispatch_Table_Ptr
;
843 Curr_DT
:= DT
(To_Tag_Ptr
(This
).all);
845 -- See the documentation of Dispatch_Table_Wrapper.Offset_To_Top
847 if Curr_DT
.Offset_To_Top
= SSE
.Storage_Offset
'Last then
849 -- The parent record type has variable-size components, so the
850 -- instance-specific offset is stored in the tagged record, right
851 -- after the reference to Curr_DT (which is a secondary dispatch
854 return To_Storage_Offset_Ptr
(This
+ Tag_Size
).all;
857 -- The offset is compile-time known, so it is simply stored in the
858 -- Offset_To_Top field.
860 return Curr_DT
.Offset_To_Top
;
864 ------------------------
865 -- Needs_Finalization --
866 ------------------------
868 function Needs_Finalization
(T
: Tag
) return Boolean is
869 TSD_Ptr
: constant Addr_Ptr
:=
870 To_Addr_Ptr
(To_Address
(T
) - DT_Typeinfo_Ptr_Size
);
871 TSD
: constant Type_Specific_Data_Ptr
:=
872 To_Type_Specific_Data_Ptr
(TSD_Ptr
.all);
874 return TSD
.Needs_Finalization
;
875 end Needs_Finalization
;
882 (Obj
: System
.Address
;
883 T
: Tag
) return SSE
.Storage_Count
885 Parent_Slot
: constant Positive := 1;
886 -- The tag of the parent is always in the first slot of the table of
889 TSD_Ptr
: constant Addr_Ptr
:=
890 To_Addr_Ptr
(To_Address
(T
) - DT_Typeinfo_Ptr_Size
);
891 TSD
: constant Type_Specific_Data_Ptr
:=
892 To_Type_Specific_Data_Ptr
(TSD_Ptr
.all);
893 -- Pointer to the TSD
895 Parent_Tag
: constant Tag
:= TSD
.Tags_Table
(Parent_Slot
);
896 Parent_TSD_Ptr
: constant Addr_Ptr
:=
897 To_Addr_Ptr
(To_Address
(Parent_Tag
) - DT_Typeinfo_Ptr_Size
);
898 Parent_TSD
: constant Type_Specific_Data_Ptr
:=
899 To_Type_Specific_Data_Ptr
(Parent_TSD_Ptr
.all);
902 -- Here we compute the size of the _parent field of the object
904 return SSE
.Storage_Count
(Parent_TSD
.Size_Func
.all (Obj
));
911 function Parent_Tag
(T
: Tag
) return Tag
is
913 TSD
: Type_Specific_Data_Ptr
;
920 TSD_Ptr
:= To_Addr_Ptr
(To_Address
(T
) - DT_Typeinfo_Ptr_Size
);
921 TSD
:= To_Type_Specific_Data_Ptr
(TSD_Ptr
.all);
923 -- The Parent_Tag of a root-level tagged type is defined to be No_Tag.
924 -- The first entry in the Ancestors_Tags array will be null for such
925 -- a type, but it's better to be explicit about returning No_Tag in
928 if TSD
.Idepth
= 0 then
931 return TSD
.Tags_Table
(1);
935 -------------------------------
936 -- Register_Interface_Offset --
937 -------------------------------
939 procedure Register_Interface_Offset
943 Offset_Value
: SSE
.Storage_Offset
;
944 Offset_Func
: Offset_To_Top_Function_Ptr
)
946 Prim_DT
: constant Dispatch_Table_Ptr
:= DT
(Prim_T
);
947 Iface_Table
: constant Interface_Data_Ptr
:=
948 To_Type_Specific_Data_Ptr
(Prim_DT
.TSD
).Interfaces_Table
;
951 -- Save Offset_Value in the table of interfaces of the primary DT.
952 -- This data will be used by the subprogram "Displace" to give support
953 -- to backward abstract interface type conversions.
955 -- Register the offset in the table of interfaces
957 if Iface_Table
/= null then
958 for Id
in 1 .. Iface_Table
.Nb_Ifaces
loop
959 if Iface_Table
.Ifaces_Table
(Id
).Iface_Tag
= Interface_T
then
960 if Is_Static
or else Offset_Value
= 0 then
961 Iface_Table
.Ifaces_Table
(Id
).Static_Offset_To_Top
:= True;
962 Iface_Table
.Ifaces_Table
(Id
).Offset_To_Top_Value
:=
965 Iface_Table
.Ifaces_Table
(Id
).Static_Offset_To_Top
:= False;
966 Iface_Table
.Ifaces_Table
(Id
).Offset_To_Top_Func
:=
975 -- If we arrive here there is some error in the run-time data structure
978 end Register_Interface_Offset
;
984 procedure Register_Tag
(T
: Tag
) is
986 External_Tag_HTable
.Set
(T
);
993 function Secondary_Tag
(T
, Iface
: Tag
) return Tag
is
994 Iface_Table
: Interface_Data_Ptr
;
995 Obj_DT
: Dispatch_Table_Ptr
;
998 if not Is_Primary_DT
(T
) then
1003 Iface_Table
:= To_Type_Specific_Data_Ptr
(Obj_DT
.TSD
).Interfaces_Table
;
1005 if Iface_Table
/= null then
1006 for Id
in 1 .. Iface_Table
.Nb_Ifaces
loop
1007 if Iface_Table
.Ifaces_Table
(Id
).Iface_Tag
= Iface
then
1008 return Iface_Table
.Ifaces_Table
(Id
).Secondary_DT
;
1013 -- If the object does not implement the interface we must raise CE
1015 raise Constraint_Error
with "invalid interface conversion";
1018 ---------------------
1019 -- Set_Entry_Index --
1020 ---------------------
1022 procedure Set_Entry_Index
1024 Position
: Positive;
1028 SSD
(T
).SSD_Table
(Position
).Index
:= Value
;
1029 end Set_Entry_Index
;
1031 -----------------------
1032 -- Set_Offset_To_Top --
1033 -----------------------
1035 procedure Set_Dynamic_Offset_To_Top
1036 (This
: System
.Address
;
1039 Offset_Value
: SSE
.Storage_Offset
;
1040 Offset_Func
: Offset_To_Top_Function_Ptr
)
1042 Sec_Base
: System
.Address
;
1043 Sec_DT
: Dispatch_Table_Ptr
;
1046 -- Save the offset to top field in the secondary dispatch table
1048 if Offset_Value
/= 0 then
1049 Sec_Base
:= This
- Offset_Value
;
1050 Sec_DT
:= DT
(To_Tag_Ptr
(Sec_Base
).all);
1051 Sec_DT
.Offset_To_Top
:= SSE
.Storage_Offset
'Last;
1054 Register_Interface_Offset
1055 (Prim_T
, Interface_T
, False, Offset_Value
, Offset_Func
);
1056 end Set_Dynamic_Offset_To_Top
;
1058 ----------------------
1059 -- Set_Prim_Op_Kind --
1060 ----------------------
1062 procedure Set_Prim_Op_Kind
1064 Position
: Positive;
1065 Value
: Prim_Op_Kind
)
1068 SSD
(T
).SSD_Table
(Position
).Kind
:= Value
;
1069 end Set_Prim_Op_Kind
;
1071 --------------------
1072 -- Unregister_Tag --
1073 --------------------
1075 procedure Unregister_Tag
(T
: Tag
) is
1077 External_Tag_HTable
.Remove
(Get_External_Tag
(T
));
1080 ------------------------
1081 -- Wide_Expanded_Name --
1082 ------------------------
1084 WC_Encoding
: Character;
1085 pragma Import
(C
, WC_Encoding
, "__gl_wc_encoding");
1086 -- Encoding method for source, as exported by binder
1088 function Wide_Expanded_Name
(T
: Tag
) return Wide_String is
1089 S
: constant String := Expanded_Name
(T
);
1090 W
: Wide_String (1 .. S
'Length);
1093 String_To_Wide_String
1094 (S
, W
, L
, Get_WC_Encoding_Method
(WC_Encoding
));
1096 end Wide_Expanded_Name
;
1098 -----------------------------
1099 -- Wide_Wide_Expanded_Name --
1100 -----------------------------
1102 function Wide_Wide_Expanded_Name
(T
: Tag
) return Wide_Wide_String
is
1103 S
: constant String := Expanded_Name
(T
);
1104 W
: Wide_Wide_String
(1 .. S
'Length);
1107 String_To_Wide_Wide_String
1108 (S
, W
, L
, Get_WC_Encoding_Method
(WC_Encoding
));
1110 end Wide_Wide_Expanded_Name
;