Article View: comp.std.c++
Article #2724Re: an optimization I claim is illegal
From: James Kanze US/ESC 60/3/141 #407...
Date: Thu, 23 Nov 1995 15:32
Date: Thu, 23 Nov 1995 15:32
139 lines
6974 bytes
6974 bytes
In article <48ngom$r5f@oznet07.ozemail.com.au> John Max Skaller
<maxtal@suphys.physics.su.oz.au> writes:
|> bgibbons@taligent.com (Bill Gibbons) wrote:
|> >In article <48gmat$i43@engnews1.eng.sun.com>, clamage@Eng.Sun.COM wrote:
|> >
|> >> The key point is whether you can do that during execution of a member
|> >> function on behalf of the original object.
|> >>
|> >> I think the answer is no.
|> >
|> >I beg to differ. I believe the issue of destroying an object from within
|> >a member's execution has been resolved, and the answer was that it's OK:
|> >
|> > void A::f() { delete this; } // OK
|> This is unfortunate, because it may force _unloading_ of cached
|> addresses before calling a member function. For example on the 486:
|> ; function g() { f(); }
|> LES BX, object_address ; load ES:BX with 'this' pointer
|> CALL f ; call member function
|> RET
|> This machine code may LOOK OK, but it ISNT. Why? Because an
|> interrupt may come flying in after the call to f and before the
|> return. The machine registers are pushed onto the stack
|> in the interrupt. After the interrupt has done its job
|> it pops the register back. WOOPS!!! A segment register
|> gets loaded with an invalid address. A general protection
|> fault ensues.
I find it difficult to believe this. First, of course, in protected
mode, interrupts use a different stack than the application, so they
cannot cause the problem. (And of course, if the processor is not in
protected mode, there isn't any problem to begin with.)
More fundamentally, as you describe it, it doesn't require a delete
this to cause the problem; anytime a pointer to something which
happens to get deleted is in a register, it will occur. If what you
describe is true, then the compiler must generate code to invalidate
all segment registers once they are no longer used. Consider:
*p // Load segment of p.
f() // But f could legitimately delete p.
If the register use conventions make segment registers volatile, then
the delete operator will simply clear them, and no problem. But the
compiler cannot cache pointers in a volatile register. (Note that I
am not using volatile in the C++ sense here. A volatile register is
one that doesn't need to be saved across function calls.) If p has
been loaded into a volatile segment, however... It is almost certain
that the operator delete function will use some of the segment
registers, saving them on the stack before execution, and restoring
them afterwards. So you will systematically get the error,
immediately on returning from operator delete.
|> This is NOT a hyposthetical example, it happens right now
|> (under Borland 4.5), and it happened to a friend of mine
|> who had to debug someone else's code.
|> ES must be loaded with a valid address
|> at all times, 0 will do. But in general there's no way to tell
|> when deallocating memory whether a register contains a reference
|> to that memory (other than an address comparison on the segment
|> register in the deallocator ??).
If this is true, then the compiler must clear all segment registers
before calling *any* function, unless it can prove that the called
function has no access to the address contained in the segment
register.
|> So IF the 'this' pointer is to be cached across calls to
|> unknown functions, the compiler has to assume the object
|> is not deleted.
Note that you have expanded your argument. Earlier, you were talking
about member functions (delete this); here you are saying that it must
be illegal to delete an object in a function (any function) called
from a function which has a pointer to that object. I don't think
that this is at all acceptable; after all, operator delete is a
function, too.
|> The argument against changing the type is similar -- IF
|> the virtual table pointer is to be cached in a register,
|> it can't be allowed to be changed until the (lexical)
|> end of the block of code for which it was loaded.
If this were the only argument against changing types, then I think it
would be allowed. (Note that in fact, delete *does* change types,
since raw memory can be considered an array of unsigned char, and is
definitly not a T. Practically, however, this exception is necessary
in order to write any reasonable programs.)
|> Otherwise the wrong offset may be used in looking up
|> a subsequent virtual function call or pointer
|> offset adjustment.
Even without a cache, if you change the type, you may get the wrong
vtable. More likely, you will end up accessing random memory as if it
were a vtable.
|> >Here's a somewhat more robust version of the example:
|> >
|> > virtual void Derived::f() {
|> > if (--n == 0) {
|> > void *mem = dynamic_cast<void*>(this); // start of complete object
|> > this->~Derived();
|> > new (mem) Base;
|> > }
|> > }
|> >
|> >I agree that this is pretty ugly, but I think the current working paper
|> >makes it well-formed.
|> A great pity if this is the case, a major optimisation opportunity
|> appears to be lost on the most common processor.
The most common processor? The optimization is fully valid in
non-protected mode; I suspect that this covers most PC's. And in
protected mode, I believe that even the newer Windows use flat
addressing, so you never touch segment registers.
Of course, this will affect programs trying to push the processor/OS
beyond its limits. But this is generally true. If I write programs
with data sets bigger than my real memory on my Sun, the resulting
page faults don't speed things up either. That's life.
--
James Kanze Tel.: (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils, études et réalisations en logiciel orienté objet --
-- A la recherche d'une activité dans une region francophone
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Technical Details
Message-ID:
<9511231034.AA13272@lts.sel.alcatel.de>Path:
arc1-ca.pugleaf.net!engnews1.Eng.Sun.COM!taumet!clamageReferences:
<48ge05$h00@engnews1.eng.sun.com> <48gmat$i43@engnews1.eng.sun.com> <9511171831.AA42637@mailserv.taligent.com> <48ngom$r5f@oznet07.ozemail.com.au>Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!engnews1.Eng.Sun.COM!taumet!clamage From: James Kanze US/ESC 60/3/141 #40763 <kanze@lts.sel.alcatel.de> Newsgroups: comp.std.c++ Subject: Re: an optimization I claim is illegal Date: 23 Nov 1995 15:32:11 GMT Organization: ? Approved: clamage@eng.sun.com (comp.std.c++) Message-ID: <9511231034.AA13272@lts.sel.alcatel.de> References: <48ge05$h00@engnews1.eng.sun.com> <48gmat$i43@engnews1.eng.sun.com> <9511171831.AA42637@mailserv.taligent.com> <48ngom$r5f@oznet07.ozemail.com.au> NNTP-Posting-Host: taumet.eng.sun.com Content-Type: text In-Reply-To: John Max Skaller's message of 19 Nov 1995 19:20:13 GMT Content-Length: 5942 Originator: clamage@taumet