perf: add perfdirs command

This measures the cost of computing the dirstate's dirs structure,
which becomes very expensive in a large working directory.
dicthelpers: add docstrings for diff and join
dicthelpers: inline diff and join code

mpm suggested this change since it improves performance slightly.

Benchmarking hg perfcalculate -r .

Before:
! wall 0.141173 comb 0.140000 user 0.140000 sys 0.000000 (best of 66)

After:
! wall 0.138619 comb 0.140000 user 0.140000 sys 0.000000 (best of 69)
pull: rename local rb to remotebookmarks

This local will become more important in an upcoming patch, so give it a more
descriptive name.
bookmarks.updatefromremote: rename local rb to remotemarks

This local will become a parameter in an upcoming patch, so give it a more
descriptive name. The name stays similar to the existing localmarks.
test-hook.t: remove prelistkeys.forbid hook before moving on

An upcoming patch will change the order of operations and perform a listkeys
before a changegroup fetch. This will cause a few tests to print out the wrong
error message.
pull: list bookmarks before pulling changesets (issue3873)

Consider a bookmark B that exists both locally and remotely. If B is updated
remotely, and then a pull is performed where the pull set contains the new
location of B, the bookmark is updated locally. However, if remote B is
updated in the middle of a pull to a location not in the pull set, the
bookmark won't be updated locally at all.

To fix this, list bookmarks before pulling in changesets, not after. This
still leaves a race open if B gets moved in between listing bookmarks and
pulling in changesets, but the race window is much smaller. Fixing the race
properly would require a bundle format upgrade.

test-hook.t's output changes because we no longer do two listkeys calls during
pull, just one.

test-pull-http.t's output changes because we now search for bookmarks before
searching for changes.
duplicatecopies: fix arg name and docstring

While most callers do indeed use duplicatecopies with a rev and its parent,
rebase doesn't.
duplicatecopies: do not mark items not in the dirstate as copies

Consider the following repo:

  0 -- 1 (renames a to b)
    \
     - 2

If we're rebasing 2 onto 1, then duplicatecopies is called with arguments (2,
1). copies.pathcopies goes backwards from 1 to 0 and returns the pair dst = a,
src = b. Of course, since we're working on top of 2, at this point a doesn't
exist in the dirstate.

Extra entries in the copymap are currently harmless because the copymap is
only queried for items in the dirstate map. However, if the dirstate.copy
method becomes one of the sources used to determine which files have changed,
this will prove problematic.

Note that we can't avoid going backwards in general -- consider this repo:

  0 -- 1 (renames a to b)
    \
     - 2 (renames a to c)

Rebasing 2 onto 1 should produce a rename from b to c.