<div dir="ltr"><div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr">On Wed, Jan 9, 2019 at 5:05 AM Pavel Labath <<a href="mailto:pavel@labath.sk">pavel@labath.sk</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">On 08/01/2019 21:57, Jonas Devlieghere wrote:<br>
> Before I got around to coding this up I realized you can't take the <br>
> address of constructors in C++, so the function address won't work as an <br>
> identifier.<br>
> <br>
<br>
You gave up way too easily. :P<br></blockquote><div><br></div><div>I counted on you having something in mind, it sounded too obvious for you to have missed. ;-) </div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
I realized that constructors are going to be tricky, but I didn't want <br>
to dive into those details until I knew if you liked the general idea. <br>
The most important thing to realize here is that for the identifier <br>
thingy to work, you don't actually need to use the address of that <br>
method/constructor as the identifier. It is sufficient to have something <br>
that can be deterministically computed from the function. Then you can <br>
use the address of *that* as the identifier.<br></blockquote><div><br></div><div>I was thinking about that yesterday. I still feel like it would be better to have this mapping all done at compile time. I was considering some kind of constexpr hashing but that sounded overkill. </div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
I've created a very simple prototype <<a href="https://godbolt.org/z/_xDt5r" rel="noreferrer" target="_blank">https://godbolt.org/z/_xDt5r</a>>, <br>
where I do just that. The way I handle constructors there is that I <br>
create a special class template (construct), whose instantiations are <br>
going to be unique for each constructor (I achieve that by making the <br>
class name and the constructor argument types the template parameters of <br>
that function). Then I can take the address of the static member <br>
function inside this class (&construct<class, arguments...>::doit), and <br>
use *that* as the ID.</blockquote><div><br></div><div>Clever! </div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
As a nice side-effect, the "doit" method actually does invoke the <br>
constructor in question, so I can also use that in the replay code to <br>
treat constructors like any other method that returns an object.<br></blockquote><div><br></div><div>This is really neat.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
I also do the same thing for (non-static) member functions via the <br>
"invoke" template, because even though it is possible to take the <br>
address of those, it is very hard to do anything else with the retrieved <br>
pointer. So the effect of this that in the rest of the code, I only have <br>
to work with free functions, as both constructors and member functions <br>
are converted into equivalent free functions. I haven't tried to handle <br>
destructors yet, but I don't think those should pose any problems that <br>
we haven't encountered already.<br>
<br>
The example also show how you can use templates to automatically <br>
generate replay code for "simple" (i.e. those where you can <br>
(de)serialize each argument independently) functions, and then uses that <br>
to record/replay a very simple API.<br>
<br>
You can see it in action like this:<br>
$ g++ a.cc # compile<br>
$ ./a.out 2>/tmp/recording # generate the recording<br>
SBFoo 47 42<br>
Method 1 2<br>
Static 10 11<br>
$ cat /tmp/recording<br>
0 # ID of the constructor<br>
47 # constructor arg 1<br>
42 # constructor arg 2<br>
0x7ffd74d9a0f7 # constructor result<br>
1 # id of SBFoo::Method<br>
0x7ffd74d9a0f7 # this<br>
1 # arg 1<br>
2 # arg 2<br>
2 # id of SBFoo::Static<br>
10 # arg 1<br>
11 # arg 2<br>
$ ./a.out 1 < /tmp/recording # replay the recording<br>
SBFoo 47 42<br>
SBFoo 42 47<br>
Method 1 2<br>
Static 10 11<br>
<br>
Note that when replaying the SBFoo constructor is called twice. This is <br>
because this code does not attempt to track the object instances in any <br>
way... it just creates a new one each time. This obviously needs to be <br>
fixed, but that's independent of the function ID issue.<br>
<br>
hope you find that useful,<br>
pl<br></blockquote><div><br></div><div>Definitely, thank you for taking the time to code up a prototype. </div><div><br></div><div>Cheers,</div><div>Jonas </div></div></div></div>