diff --git a/mercurial/cext/parsers.c b/mercurial/cext/parsers.c
--- a/mercurial/cext/parsers.c
+++ b/mercurial/cext/parsers.c
@@ -142,6 +142,15 @@ static PyObject *dirstate_item_v1_mtime(
 	return PyInt_FromLong(self->mtime);
 };
 
+static PyObject *dm_nonnormal(dirstateItemObject *self)
+{
+	if (self->state != 'n' || self->mtime == ambiguous_time) {
+		Py_RETURN_TRUE;
+	} else {
+		Py_RETURN_FALSE;
+	}
+};
+
 static PyObject *dirstate_item_need_delay(dirstateItemObject *self,
                                           PyObject *value)
 {
@@ -221,6 +230,8 @@ static PyMethodDef dirstate_item_methods
      "build a new DirstateItem object from V1 data"},
     {"set_possibly_dirty", (PyCFunction)dirstate_item_set_possibly_dirty,
      METH_NOARGS, "mark a file as \"possibly dirty\""},
+    {"dm_nonnormal", (PyCFunction)dm_nonnormal, METH_NOARGS,
+     "True is the entry is non-normal in the dirstatemap sense"},
     {NULL} /* Sentinel */
 };
 
diff --git a/mercurial/dirstatemap.py b/mercurial/dirstatemap.py
--- a/mercurial/dirstatemap.py
+++ b/mercurial/dirstatemap.py
@@ -196,8 +196,8 @@ class dirstatemap(object):
             self._dirs.addpath(f)
         if old_entry is None and "_alldirs" in self.__dict__:
             self._alldirs.addpath(f)
-        self._map[f] = DirstateItem(state, mode, size, mtime)
-        if state != b'n' or mtime == AMBIGUOUS_TIME:
+        e = self._map[f] = DirstateItem(state, mode, size, mtime)
+        if e.dm_nonnormal:
             self.nonnormalset.add(f)
         if size == FROM_P2:
             self.otherparentset.add(f)
@@ -274,7 +274,7 @@ class dirstatemap(object):
             nonnorm = set()
             otherparent = set()
             for fname, e in pycompat.iteritems(self._map):
-                if e.state != b'n' or e.mtime == AMBIGUOUS_TIME:
+                if e.dm_nonnormal:
                     nonnorm.add(fname)
                 if e.from_p2:
                     otherparent.add(fname)
diff --git a/mercurial/pure/parsers.py b/mercurial/pure/parsers.py
--- a/mercurial/pure/parsers.py
+++ b/mercurial/pure/parsers.py
@@ -187,6 +187,14 @@ class DirstateItem(object):
         """
         return self._state == b'r' and self._size == NONNORMAL
 
+    @property
+    def dm_nonnormal(self):
+        """True is the entry is non-normal in the dirstatemap sense
+
+        There is no reason for any code, but the dirstatemap one to use this.
+        """
+        return self.state != b'n' or self.mtime == AMBIGUOUS_TIME
+
     def v1_state(self):
         """return a "state" suitable for v1 serialization"""
         return self._state