blogs-debugging-article4.pod 4.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. In the <a href="http://blogs.perl.org/users/rurban/2010/01/debugging-bc-hitting-the-recursion-depth.html">first B::C debugging article</a> we stepped into the B::C compiler with <b>Od</b>.
  2. In the <a href="http://blogs.perl.org/users/rurban/2010/01/debugging-bc-gdb-into-it-part-2.html">second B::C debugging article</a> we stepped the c code with <b>gdb</b>.
  3. We saw that the compiler is missing a method_named sub (aka a package->method call), the most typical problem with the compiler.
  4. In the <a href="http://blogs.perl.org/users/rurban/2010/01/debugging-bc-the-workaround-part-3.html">third B::C debugging article</a> we saw the easy workaround, using -u<package> to force using the package subs from the package given in the <strong>-u</strong> option.
  5. Now let's finally fix this bug which was introduced with the addition of the opcode <strong>method_named</strong> forever.
  6. Looking at the source of pp_method_named() we see that the package name is a PV at
  7. [PL_stack_base+TOPMARK+1], and the method name is at the stack.
  8. Looking at the <a href="http://search.cpan.org/dist/illguts/index.html#markstack">illguts stack page</a>, inspecting the optree generator in op.c and debugging into pp_method_named we confirm that the missing package PV is the SVOP->sv of the previous op. The name of the CONST.
  9. <pre>
  10. (gdb) <strong>b S_method_common</strong>
  11. (gdb) <strong>c</strong>
  12. S_method_common (meth=0x148c060, hashp=0xc1cb0c) at pp_hot.c:3039
  13. (gdb) <strong>p name</strong>
  14. $2 = 0x14930dc "meth"
  15. (gdb) <strong>p *sv</strong>
  16. $3 = {sv_any = 0x1471138, sv_refcnt = 1, sv_flags = 134235141, sv_u = {
  17. svu_iv = -5931823458978044120, svu_uv = 12514920614731507496,
  18. svu_rv = 0x148e728, svu_pv = 0x148e728 "dummy", svu_array = 0x148e728,
  19. svu_hash = 0x148e728, svu_gp = 0x148e728}}
  20. (gdb) <strong>p **(PL_stack_base+1)</strong>
  21. $9 = {sv_any = 0x1471138, sv_refcnt = 1, sv_flags = 134235141, sv_u = {
  22. svu_iv = -5931823458978044120, svu_uv = 12514920614731507496,
  23. svu_rv = 0x148e728, svu_pv = 0x148e728 "dummy", svu_array = 0x148e728,
  24. svu_hash = 0x148e728, svu_gp = 0x148e728}}
  25. </pre>
  26. When we look in opcode.pl for method_named we see that is a combined
  27. SVOP_OR_PADOP, a SVOP unthreaded and a PADOP threaded. So we have to
  28. fix two methods, B::SVOP::save and B::PADOP::save to store the
  29. undetected cv for method_named.
  30. The compiler just walks the ops but does not store away the optree, so
  31. we have no access to the previous op.
  32. So we need to add
  33. <pre>
  34. if ($op->name eq 'method_named') {
  35. my $cv = method_named($sv);
  36. $cv->save;
  37. }
  38. </pre>
  39. to the SVOP and PADOP save methods and add the helper function to get us the cv.
  40. <pre>
  41. sub method_named {
  42. my $sv = shift;
  43. my $name = $sv->PVX;
  44. # Note: the pkg PV is at PL_stack_base+TOPMARK+1,
  45. # the previous op->sv->PVX. We store it away in op->_save_common.
  46. my $stash = $package_pv ? $package_pv."::" : "main::";
  47. $name = $stash . $name;
  48. warn "save method_name \"$name\"\n" if $debug{cv};
  49. return svref_2object( \&{$name} );
  50. }
  51. </pre>
  52. Fortunately we have a common method for all ops, where we can store
  53. away the $package_pv for any upcoming method_named op.
  54. <pre>
  55. sub B::OP::_save_common {
  56. my $op = shift;
  57. if ($op->next
  58. and $op->next->can('name')
  59. and $op->next->name eq 'method_named')
  60. {
  61. # need to store away the pkg pv
  62. $package_pv = $op->sv->PVX;
  63. }
  64. ...
  65. </pre>
  66. Test it:
  67. <pre>
  68. $ <strong>t/testc.sh 35</strong>
  69. =>
  70. ./ccode35
  71. PASS => 'ok'
  72. </pre>
  73. We just fixed one of the oldest compiler bugs, the methodcall syntax: pkg->method.
  74. It's not fixed for CC, because CC unrolls the runops loop and does not use B::OP::_save_common. In CC the most common ops have their own optimized method.
  75. The testsuite
  76. <b>make test</b> <em>(~2 min with the current perl)</em> and
  77. <b>perlall-maketest</b> <em>(~20 min for all installed perls)</em> and
  78. <b>perltestvm</b> <em>(~60min for all installed perls in all accessible platforms - freebsd, debian, centos, solaris, ...)</em>
  79. confirms that.
  80. Let's look what the biggest testsuite, cpantesters, says.
  81. make dist, upload to pause and wait for the smoke.