!standard 13.03 (58) 02-10-09 AI95-00319/01 !class amendment 02-10-09 !status No Action (6-1-1) 03-02-08 !status work item 02-10-09 !status received 02-10-09 !priority Medium !difficulty Medium !subject Object_Size attribute !summary The new attribute S'Object_Size denotes the size of most objects of subtype S. !problem (* TBD. *) !proposal (See Wording.) !wording Add Object_Size to 13.3(9/1): The following representation attributes are defined, Address, Alignment, Size, Object_Size, Storage_Size, and Component_Size. Insert the following after 13.3(58): For every subtype S: S'Object_Size If S is definite, denotes the size (in bits) that the implementation would choose for the following objects of subtype S: * A stand-alone object of subtype S. * A record component of subtype S when the record type has no representation items applied. * An array component of subtype S when the array type has no representation items applied. If S is indefinite, the meaning is implementation-defined. The value of this attribute is of the type universal_integer. The Object_Size of a subtype is at least as large as the Size of the subtype. Object_Size may be specified via an attribute_definition_clause; the expression of such a clause shall be static and its value nonnegative. Implementation Advice If S is a definite first subtype and S'Object_Size is not specified, S'Object_Size should be the smallest multiple of the storage element size larger than S'Size which is consistent with the alignment of S. AARM Note Reason: Many implementations "round up" allocations to the nearest multiple of the alignment. For instance, this example appears in the GNAT documentation: [Given] a record containing an integer and a character: type Rec is record I : Integer; C : Character; end record; will have a size of 40 (that is Rec'Size will be 40. The alignment will be 4, because of the integer field, and so the default size of record objects for this type will be 64 (8 bytes). We purposely used the vague phrase "consistent with the alignment of S" so that implementations that do not round up allocations (just using padding to provide alignment) are not required to do any rounding up. If X denotes an object (including components) of subtype S, X'Size should be S'Object_Size, unless: X'Size is specified; or The size of X is determined by a component_clause or Component_Size clause; or Pragma Pack applies to the type containing component X. An Object_Size clause on a composite type should not affect the internal layout of components. The recommended level of support for the Object_Size attribute of subtypes is: The implementation should allow S'Object_Size to be specified if S is a first subtype. If S is a static signed integer subtype, the implementation should support specifying S'Object_Size to be the size of any signed integer base type provided by the implementation that is at least as large as S'Size. If S is a static modular subtype, the implementation should support specifying S'Object_Size to be the size of any modular base type provided by the implementation that is at least as large as S'Size. If S is a static enumeration subtype, the implementation should support specifying S'Object_Size to be the size of any modular base type provided by the implementation that is at least as large as S'Size. If S is a static fixed point subtype, the implementation should support specifying S'Object_Size to be the size of any signed integer base type provided by the implementation that is at least as large as S'Size. If S is a floating point, access, or composite subtype, the implementation need allow only the specification of S'Object_Size to be the same as what the implementation would choose by default. AARM Note Ramification: An implementation need not support Object_Size on non-first subtypes. We allow this freedom, as Rational^H^H^H^H^H^H^H^H some implementations may have trouble with static matching if the Object_Sizes of subtypes can be different (see 4.9.1). We will let the market decide whether subtype specification of Object_Size is necessary. Change 13.3(50) to: If the Object_Size of a subtype is not specified, the Size of the subtype is specified, and allows for efficient independent addressability (see 9.10) on the target architecture, then the Size of the following objects of the subtype should equal the Size of the subtype: AARM Note: Ramification: If Object_Size is specified, this rule does not apply; the rules for Object_Size apply instead. If Object_Size is not specified, this rule implies that the default Object_Size is the same as the specified Size if the Size allows for efficient independent addressability (which, BTW, is not defined in 9.10). Reason: We need to specify what happens if both Object_Size and Size are specified incompatibly. Change the first sentence of 4.9.1(2) to: A subtype statically matches another subtype of the same type if they have statically matching constraints and their Object_Sizes (see 13.3) are the same. AARM note: Ramification: If one of the subtypes is not yet frozen, an implementation may have to repeat the check when the subtypes are both frozen. This can only make to previously statically matching subtype fail to match; it cannot make a match legal. This deferred check is only necessary if the implementation chooses to allow subtypes to have different Object_Size values. (This is not required, but will be possible if the implementation allows specification of Object_Size for non-first subtypes.) !discussion Object_Size covers the cases that are not specified by Size. Size is only constraining for components of packed arrays and records. Other representation items ('Component_Size, component_clauses) override Size for components. And the only requirement on normal objects is that they be the same size or larger. 13.9(6) should require that S'Object_Size = Target'Object_Size, as many more conversions would then be well-defined. However, this could be incompatible on some implementations, and the change does not seem critical. The recommended level of support for integer and fixed point subtypes is defined to only require object sizes matching the native integer sizes of the machine. Other sizes are unlikely to be selected (by default) for stand-alone objects. This attribute was originally defined by the GNAT compiler. This definition is intended to be compatible with their existing implementation. One problem with Size is that it is possible to define subtypes that have a larger size value than their base type. type T is range 0..255; for T'Size use 8; -- Confirming in Ada 95, allowed in Ada 83. subtype S is T'Base range -255..255; -- S'Size = 9 The point here is that S'Size has to be larger than T'Size; it cannot be required to be the same. This also can occur for Object_Size. It is not as likely as with Size (Object_Size has only a weakly suggested value, so it is likely that T'Object_Size = T'Base'Object_Size in the absense of a specification for T'Object_Size). Moreover, this behavior is not really a problem. An implementation that wants to avoid checking Object_Size when static matching merely has to avoid selecting different Object_Sizes for subtypes that statically match. (Such an implementation cannot allow specification of Object_Size for non-first subtypes anyway.) There is no problem with using a different Object_Size for an "expanding" subtype, as it cannot statically match the base type. (* More to come here. *) !example (* TBD. *) !ACATS test !appendix From: Randy Brukardt Sent: Wednesday, October 9, 2002 11:40 PM Below you will find a partial writeup for the Object_Size attribute. I've concentrated on the wording as opposed to the justification and examples - I'll add them later. I'm sending out the wording now because: -- I won't have enough time before the meeting to finish it anyway; -- I'd like to find out if this proposal is compatible with GNAT. It is compatible vis-a-vis their documentation, but that's pretty skimpy; -- Requiring subtype specifiability would simplify the wording some, but I believe that Rational would scream bloody murder (because that would force a legality check to depend on representation). Any ideas on avoiding that trap? (The discussion of AI-109 would suggest that there is not); -- I might as well find out if its the right approach before trying to justify it. No one here probably remembers the September 1999 discussion on this attribute, so I figure I'm pretty safe even if I missed it by a mile. :-) So, go ahead and take some potshots. :-) (* This was version 01 of the AI *) **************************************************************** From: Robert A. Duff Sent: Thursday, October 10, 2002 9:03 AM > -- Requiring subtype specifiability would simplify the wording some, but > I believe that Rational would scream bloody murder (because that would > force a legality check to depend on representation). Any ideas on > avoiding that trap? (The discussion of AI-109 would suggest that there > is not); I spent years arguing about this point with Robert Dewar. I think I'll say "no comment" this time. ;-) (The truth is, I can't remember all the issues.) > -- I might as well find out if its the right approach before trying to > justify it. ;-) > A new attribute, 'Object_Size, is defined to cleanly the representation of > subtypes. Last clause no verb. ;-) At first I thought you meant "specify", but the normal RM style sort of assumes that attributes' primary purpose is to *query*. So how about something like "The new attribute S'Object_Size denotes the size of certain objects of subtype S." (I know S'Object_Size is an attribute_reference, not an attribute, but we can be informal here.) > For every subtype S: > > S'Object_Size If S is definite, denotes the size (in bits) that the > implementation would choose for the following objects of subtype S: > * A stand-alone object of subtype S. > * A record component of subtype S when the record type has > no representation items applied. > * An array component of subtype S when the array type has > no representation items applied. Hmm. This seems to require that all of these kinds of objects must be the same size. I have the impression that some compilers don't do that currently, and they should not be forced to change. (I think some compilers pack arrays and maybe records more tightly than stack frames. True?) > We purposely used the vague phrase "consistent with the alignment of S" > so that implementations that do not round up allocations (just using > padding to provide alignment) are not required to do any rounding up. I didn't find the term "vague" until you said it was. I understood it to mean precisely, "S'Object_Size shall be a multiple of S'Alignment". I'm not sure *any* advice is wise, here. The above appears to give advice on the value of 'Object_Size, but it's really indirectly giving advice on how to lay out objects. I think compilers should be free to do what they like (when 'Object_Size is not specified). Certainly any such advice should not contradict what any existing compilers do. Anyway, why give advice if it doesn't say anything (as the above vagueness claim seems to be saying)? I presume the above advice is *not* intended to be "Recommended Level of Support" -- i.e., it remains "merely" advice even in the Systems Prog Annex. > If X denotes an object (including components) of S, X'Size should ^^^^ "of subtype S". And "should be". > If S is a static signed integer subtype, the implementation should > support specifying S'Object_Size to be the size of any signed integer > base type provided by the implementation that is at least as large > as S'Size. No such thing as "base type". Why say all this anyway? Why not just say something about "naturally supported by the hardware"? > AARM Note > Ramification: An implementation need not support Object_Size on non-first > subtypes. We allow this freedom, as Rational^H^H^H^H^H^H^H^H some > implementations may have trouble with static matching if the Object_Sizes > of subtypes can be different (see 4.9.1). We will let the market decide > of subtype specification of Object_Size is necessary. ^^ if (or whether?) > Change the first sentence of 4.9.1(2) to: > > A subtype statically matches another subtype of the same type if they have > statically matching constraints and their Object_Sizes (see 13.3) are the > same. This seems like a loophole. Shouldn't the *default* 'Object_Size be required to be the same for subtypes of the same type with statically matching constraints? > This also can occur for Object_Size. It is not as likely as with Size > (Object_Size has only a weakly suggested value, so it is likely that > T'Object_Size = T'Base'Object in the absense of a specification for _Size **************************************************************** From: Randy Brukardt Sent: Thursday, October 10, 2002 12:28 AM > > -- Requiring subtype specifiability would simplify the wording some, but > > I believe that Rational would scream bloody murder (because that would > > force a legality check to depend on representation). Any ideas on > > avoiding that trap? (The discussion of AI-109 would suggest that there > > is not); > > I spent years arguing about this point with Robert Dewar. > I think I'll say "no comment" this time. ;-) Ah, you've just been waiting years for some other poor sucker to take a crack at this. :-) :-) > > A new attribute, 'Object_Size, is defined to cleanly the representation of > > subtypes. > > Last clause no verb. ;-) > > At first I thought you meant "specify", but the normal RM style sort of > assumes that attributes' primary purpose is to *query*. So how about > something like "The new attribute S'Object_Size denotes the size of > certain objects of subtype S." (I know S'Object_Size is an > attribute_reference, not an attribute, but we can be informal here.) I've used your wording. > > For every subtype S: > > > > S'Object_Size If S is definite, denotes the size (in bits) that the > > implementation would choose for the following objects of subtype S: > > * A stand-alone object of subtype S. > > * A record component of subtype S when the record type has > > no representation items applied. > > * An array component of subtype S when the array type has > > no representation items applied. > > Hmm. This seems to require that all of these kinds of objects must be > the same size. I have the impression that some compilers don't do that > currently, and they should not be forced to change. (I think some > compilers pack arrays and maybe records more tightly than stack frames. > True?) I don't know, but it certainly is my intent that they be the same. Else we have the same problem that we have with 'Size (it doesn't mean anything). We'll need to talk about this. > > We purposely used the vague phrase "consistent with the alignment of S" > > so that implementations that do not round up allocations (just using > > padding to provide alignment) are not required to do any rounding up. > > I didn't find the term "vague" until you said it was. I understood it > to mean precisely, "S'Object_Size shall be a multiple of S'Alignment". Because you use that strange model that requires something with an alignment of 4 to have a size that is a multiple of it. I (and Janus/Ada) do not use such a model. (A byte can have alignment 4, there is no problem with that IMHO). In our compiler, "consistent with the alignment of S" has no effect. So the phrase means whatever makes sense to the implementation. And that's good. > I'm not sure *any* advice is wise, here. The above appears to give > advice on the value of 'Object_Size, but it's really indirectly giving > advice on how to lay out objects. I think compilers should be free to > do what they like (when 'Object_Size is not specified). Certainly any > such advice should not contradict what any existing compilers do. It's ADVICE for a reason. Compilers should be free to ignore it if it makes sense. That's true of all ADVICE. > Anyway, why give advice if it doesn't say anything (as the above > vagueness claim seems to be saying)? No, it says quite a bit. It just doesn't say exactly what alignment rule a compiler is going to use, because that is silly (I think the rule that you guys use is silly, but I don't see any reason to suggest that you change). > I presume the above advice is *not* intended to be "Recommended Level of > Support" -- i.e., it remains "merely" advice even in the Systems Prog > Annex. Correct. That's why it doesn't use that phrase. > > If S is a static signed integer subtype, the implementation should > > support specifying S'Object_Size to be the size of any signed integer > > base type provided by the implementation that is at least as large > > as S'Size. > > No such thing as "base type". Why say all this anyway? Why not just > say something about "naturally supported by the hardware"? Because that NOT what Annex B says about Interfaces, and this ought to be consistent with that. I'm fairly confident that this is wrong anyway, because of signed/unsigned issues. I'm going to have to revisit it, but no time now. > > Change the first sentence of 4.9.1(2) to: > > > > A subtype statically matches another subtype of the same type if they have > > statically matching constraints and their Object_Sizes (see 13.3) are the > > same. > > This seems like a loophole. Shouldn't the *default* 'Object_Size be > required to be the same for subtypes of the same type with statically > matching constraints? That's required by 13.1(15/1); if it isn't, that paragraph should be fixed to do so (that is part of AI-109, but I doubt that AI will ever be finished...). I've noticed another problem as well: I didn't say what happens when both Object_Size and Size are specified incompatibly. I've fixed that in draft /02. It will be posted on the web site momentarily. (Along with all other changes to date.) **************************************************************** From: Robert Dewar Sent: Thursday, October 10, 2002 5:55 PM > I spent years arguing about this point with Robert Dewar. > I think I'll say "no comment" this time. ;-) The reason that subtype specifiability is so important is that otherwise you have a fundamental and serious source of non-portability. The compiler is free to choose miscellaneous sizes for objects of a subtype, and this is a serious source of non-portability. Normally we can pin down representations where they cause portability problems, but this is one case where you cannot do so in standard Ada 95. We have found the ability to specify object sizes for subtypes to be extremely useful in practice. **************************************************************** From: Robert A. Duff Sent: Thursday, October 10, 2002 12:58 PM > Because you use that strange model that requires something with an alignment > of 4 to have a size that is a multiple of it. I agree that the size of an object should not be required to be a multiple of its alignment. This is certainly useful in cases like a record containing an Integer followed by a Character (size is 5 bytes, alignment is 4 bytes, perhaps). I don't know what all the compilers (including ours) support in this regard. I know our C-generating compiler has some representation-related constraints imposed by C (or implementations of C). The fact remains that I misunderstood "consistent with the alignment of" to mean something non-vague (until I saw the AARM annotation). **************************************************************** From: Robert Dewar Sent: Thursday, October 10, 2002 6:33 PM <> I think it is perfectly reasonable for the object size to meet this requirement. In GNAT, we would have the Value_Size (and hence 'Size) of such a record be 5 bytes, but the object size would be 8 bytes. I see no reason for changing this. **************************************************************** From: Robert Dewar Sent: Thursday, October 10, 2002 7:16 PM Note incidentally that in C it is fundamental that the object size is a multiple of the alignment (or arrays would never work). I really think that the gain from insisting on allowing object sizes that are not multiples of alignment are minimal. Certainly we would simply ignore such a requirement (since it would mean that the existing backend could not be used). Consider the cases: 1. Stand alone variables. Here the gain is a tiny saving in space, compared with significantly inefficient code (e.g. for the 5 byte record in question, can no longer use 8 byte load/store). 2. Arrays, here you definitely expect the alignment. To not align would generate simply horrible code. 3. Records. If you have multiple such fields, again without packing you would definitely expect alignment 4. The ONLY case where this is relevant is when you have a field in a record followed by some other field that has a smaller alignment. I really see no reason in insisting on this working, and indeed I am not sure what language you would use here. The bottom line is that in any case there is no language in the RM to require that object size is the same as type size, and surely we do not want to add such language. **************************************************************** From: Robert A. Duff Sent: Thursday, October 10, 2002 9:13 PM > I think it is perfectly reasonable for the object size to meet this > requirement. In GNAT, we would have the Value_Size (and hence 'Size) > of such a record be 5 bytes, but the object size would be 8 bytes. > I see no reason for changing this. I'm not sure what you're saying. Consider: type R1 is record I: Integer; C: Character; end record; type R2 is record R1_Comp: R1; C2: Character; end record; R2_Obj: R2; Assume a fairly typical 32-bit machine, with Integer'Alignment = 4. Are you saying that (in GNAT), R1_Comp is allocated 8 bytes, and R2_Obj is allocated 12 bytes? And are you further saying that this should be *allowed* behavior or *required* behavior of all Ada compilers? A compiler could (according current rules, I believe) allocate 5 bytes for R1_Comp, and put C2 immediately after that, for 6 bytes for R2. Are you saying that should be forbidden? **************************************************************** From: Robert A. Duff Sent: Thursday, October 10, 2002 9:17 PM > Note incidentally that in C it is fundamental that the object size is > a multiple of the alignment (or arrays would never work). Yes. > I really think that the gain from insisting on allowing object sizes > that are not multiples of alignment are minimal. > > Certainly we would simply ignore such a requirement (since it would mean that > the existing backend could not be used). I do not advocate *requiring* compilers to do any such thing. But I think they should be *allowed* to. > Consider the cases: > > 1. Stand alone variables. Here the gain is a tiny saving in space, compared > with significantly inefficient code (e.g. for the 5 byte record in question, > can no longer use 8 byte load/store). Agreed. > 2. Arrays, here you definitely expect the alignment. To not align would > generate simply horrible code. Agreed. Well, at least I expect 'Component_Size to obey the 'Alignment. > 3. Records. If you have multiple such fields, again without packing you > would definitely expect alignment Right. > 4. The ONLY case where this is relevant is when you have a field in > a record followed by some other field that has a smaller alignment. > I really see no reason in insisting on this working, and indeed I am > not sure what language you would use here. Fair enough, but I'm not sure if you're in favor of *forbidding* this, or if you just don't want to *require* it. > The bottom line is that in any case there is no language in the RM to > require that object size is the same as type size, and surely we do not > want to add such language. **************************************************************** From: Robert Dewar Sent: Thursday, October 10, 2002 10:04 PM <> Allowed, not required <> We would do this only if the record were packed. The trouble with doing it unconditionally is that it would generate inefficient code for copying the field out of the record. We consider that such inefficiencies should be bought only with pragma Packed. **************************************************************** From: Robert Dewar Sent: Thursday, October 10, 2002 10:05 PM <> Yes, of course, they are allowed to now, so what's the issue? <> It should be allowed but not required ****************************************************************