[RTL]
[reactos.git] / reactos / lib / rtl / heap.c
index 9b0a6f7..6d0161c 100644 (file)
@@ -23,7 +23,7 @@
 #define NDEBUG
 #include <debug.h>
 
-HEAP_LOCK RtlpProcessHeapsListLock;
+RTL_CRITICAL_SECTION RtlpProcessHeapsListLock;
 
 /* Bitmaps stuff */
 
@@ -80,50 +80,60 @@ UCHAR FillPattern[HEAP_ENTRY_SIZE] =
     HEAP_TAIL_FILL
 };
 
-
-ULONG NTAPI
-RtlCompareMemoryUlong(PVOID Source, ULONG Length, ULONG Value);
-
 /* FUNCTIONS *****************************************************************/
 
-VOID NTAPI
-RtlpInitializeHeap(PHEAP Heap,
-                   PULONG HeaderSize,
-                   ULONG Flags,
-                   BOOLEAN AllocateLock,
-                   PVOID Lock)
+NTSTATUS NTAPI
+RtlpInitializeHeap(OUT PHEAP Heap,
+                   IN ULONG Flags,
+                   IN PHEAP_LOCK Lock OPTIONAL,
+                   IN PRTL_HEAP_PARAMETERS Parameters)
 {
-    PVOID NextHeapBase = Heap + 1;
-    PHEAP_UCR_DESCRIPTOR UcrDescriptor;
     ULONG NumUCRs = 8;
-    ULONG i;
+    ULONG Index;
+    SIZE_T HeaderSize;
     NTSTATUS Status;
+    PHEAP_UCR_DESCRIPTOR UcrDescriptor;
 
-    /* Add UCRs size */
-    *HeaderSize += NumUCRs * sizeof(*UcrDescriptor);
+    /* Preconditions */
+    ASSERT(Heap != NULL);
+    ASSERT(Parameters != NULL);
+    ASSERT(!(Flags & HEAP_LOCK_USER_ALLOCATED));
+    ASSERT(!(Flags & HEAP_NO_SERIALIZE) || (Lock == NULL));  /* HEAP_NO_SERIALIZE => no lock */
 
-    /* Prepare a list of UCRs */
-    InitializeListHead(&Heap->UCRList);
-    InitializeListHead(&Heap->UCRSegments);
-    UcrDescriptor = NextHeapBase;
+    /* Start out with the size of a plain Heap header */
+    HeaderSize = ROUND_UP(sizeof(HEAP), sizeof(HEAP_ENTRY));
 
-    for (i=0; i<NumUCRs; i++, UcrDescriptor++)
+    /* Check if space needs to be added for the Heap Lock */
+    if (!(Flags & HEAP_NO_SERIALIZE))
     {
-        InsertTailList(&Heap->UCRList, &UcrDescriptor->ListEntry);
+        if (Lock != NULL)
+            /* The user manages the Heap Lock */
+            Flags |= HEAP_LOCK_USER_ALLOCATED;
+        else
+        if (RtlpGetMode() == UserMode)
+        {
+            /* In user mode, the Heap Lock trails the Heap header */
+            Lock = (PHEAP_LOCK) ((ULONG_PTR) (Heap) + HeaderSize);
+            HeaderSize += ROUND_UP(sizeof(HEAP_LOCK), sizeof(HEAP_ENTRY));
+        }
     }
 
-    NextHeapBase = UcrDescriptor;
-    // TODO: Add tagging
+    /* Add space for the initial Heap UnCommitted Range Descriptor list */
+    UcrDescriptor = (PHEAP_UCR_DESCRIPTOR) ((ULONG_PTR) (Heap) + HeaderSize);
+    HeaderSize += ROUND_UP(NumUCRs * sizeof(HEAP_UCR_DESCRIPTOR), sizeof(HEAP_ENTRY));
 
-    /* Round up header size again */
-    *HeaderSize = ROUND_UP(*HeaderSize, HEAP_ENTRY_SIZE);
+    /* Sanity check */
+    ASSERT(HeaderSize <= PAGE_SIZE);
 
-    ASSERT(*HeaderSize <= PAGE_SIZE);
-
-    /* Initialize heap's header */
-    Heap->Entry.Size = (*HeaderSize) >> HEAP_ENTRY_SHIFT;
+    /* Initialise the Heap Entry header containing the Heap header */
+    Heap->Entry.Size = (USHORT)(HeaderSize >> HEAP_ENTRY_SHIFT);
     Heap->Entry.Flags = HEAP_ENTRY_BUSY;
+    Heap->Entry.SmallTagIndex = LOBYTE(Heap->Entry.Size) ^ HIBYTE(Heap->Entry.Size) ^ Heap->Entry.Flags;
+    Heap->Entry.PreviousSize = 0;
+    Heap->Entry.SegmentOffset = 0;
+    Heap->Entry.UnusedBytes = 0;
 
+    /* Initialise the Heap header */
     Heap->Signature = HEAP_SIGNATURE;
     Heap->Flags = Flags;
     Heap->ForceFlags = (Flags & (HEAP_NO_SERIALIZE |
@@ -135,32 +145,64 @@ RtlpInitializeHeap(PHEAP Heap,
                                  HEAP_TAIL_CHECKING_ENABLED |
                                  HEAP_CREATE_ALIGN_16 |
                                  HEAP_FREE_CHECKING_ENABLED));
+
+    /* Initialise the Heap parameters */
+    Heap->VirtualMemoryThreshold = ROUND_UP(Parameters->VirtualMemoryThreshold, sizeof(HEAP_ENTRY)) >> HEAP_ENTRY_SHIFT;
+    Heap->SegmentReserve = Parameters->SegmentReserve;
+    Heap->SegmentCommit = Parameters->SegmentCommit;
+    Heap->DeCommitFreeBlockThreshold = Parameters->DeCommitFreeBlockThreshold >> HEAP_ENTRY_SHIFT;
+    Heap->DeCommitTotalFreeThreshold = Parameters->DeCommitTotalFreeThreshold >> HEAP_ENTRY_SHIFT;
+    Heap->MaximumAllocationSize = Parameters->MaximumAllocationSize;
+    Heap->CommitRoutine = Parameters->CommitRoutine;
+
+    /* Initialise the Heap validation info */
     Heap->HeaderValidateCopy = NULL;
-    Heap->HeaderValidateLength = ((PCHAR)NextHeapBase - (PCHAR)Heap);
+    Heap->HeaderValidateLength = (USHORT)HeaderSize;
 
-    /* Initialize free lists */
-    for (i=0; i<HEAP_FREELISTS; i++)
+    /* Initialise the Heap Lock */
+    if (!(Flags & HEAP_NO_SERIALIZE) && !(Flags & HEAP_LOCK_USER_ALLOCATED))
     {
-        InitializeListHead(&Heap->FreeLists[i]);
+        Status = RtlInitializeHeapLock(&Lock);
+        if (!NT_SUCCESS(Status))
+            return Status;
     }
+    Heap->LockVariable = Lock;
 
-    /* Initialize "big" allocations list */
-    InitializeListHead(&Heap->VirtualAllocdBlocks);
-
-    /* Initialize lock */
-    if (AllocateLock)
+    /* Initialise the Heap alignment info */
+    if (Flags & HEAP_CREATE_ALIGN_16)
     {
-        Lock = NextHeapBase;
-        Status = RtlInitializeHeapLock((PHEAP_LOCK)Lock);
-        if (!NT_SUCCESS(Status))
-        {
-            DPRINT1("Initializing the lock failed!\n");
-            return /*NULL*/; // FIXME!
-        }
+        Heap->AlignMask = (ULONG) ~15;
+        Heap->AlignRound = 15 + sizeof(HEAP_ENTRY);
+    }
+    else
+    {
+        Heap->AlignMask = (ULONG) ~(sizeof(HEAP_ENTRY) - 1);
+        Heap->AlignRound = 2 * sizeof(HEAP_ENTRY) - 1;
     }
 
-    /* Set the lock variable */
-    Heap->LockVariable = Lock;
+    if (Flags & HEAP_TAIL_CHECKING_ENABLED)
+        Heap->AlignRound += sizeof(HEAP_ENTRY);
+
+    /* Initialise the Heap Segment list */
+    for (Index = 0; Index < HEAP_SEGMENTS; ++Index)
+        Heap->Segments[Index] = NULL;
+
+    /* Initialise the Heap Free Heap Entry lists */
+    for (Index = 0; Index < HEAP_FREELISTS; ++Index)
+        InitializeListHead(&Heap->FreeLists[Index]);
+
+    /* Initialise the Heap Virtual Allocated Blocks list */
+    InitializeListHead(&Heap->VirtualAllocdBlocks);
+
+    /* Initialise the Heap UnCommitted Region lists */
+    InitializeListHead(&Heap->UCRSegments);
+    InitializeListHead(&Heap->UCRList);
+
+    /* Register the initial Heap UnCommitted Region Descriptors */
+    for (Index = 0; Index < NumUCRs; ++Index)
+        InsertTailList(&Heap->UCRList, &UcrDescriptor[Index].ListEntry);
+
+    return STATUS_SUCCESS;
 }
 
 VOID FORCEINLINE
@@ -306,7 +348,7 @@ RtlpInsertFreeBlock(PHEAP Heap,
         }
         else
         {
-            Size = BlockSize;
+            Size = (USHORT)BlockSize;
             FreeEntry->Flags = Flags;
         }
 
@@ -341,18 +383,9 @@ RtlpRemoveFreeBlock(PHEAP Heap,
                     BOOLEAN NoFill)
 {
     SIZE_T Result, RealSize;
-    PLIST_ENTRY OldBlink, OldFlink;
-
-    // FIXME: Maybe use RemoveEntryList?
-
-    /* Remove the free block */
-    OldFlink = FreeEntry->FreeList.Flink;
-    OldBlink = FreeEntry->FreeList.Blink;
-    OldBlink->Flink = OldFlink;
-    OldFlink->Blink = OldBlink;
 
-    /* Update the freelists bitmap */
-    if ((OldFlink == OldBlink) &&
+    /* Remove the free block and update the freelists bitmap */
+    if (RemoveEntryList(&FreeEntry->FreeList) &&
         (Dedicated || (!Dedicated && FreeEntry->Size < HEAP_FREELISTS)))
     {
         RtlpClearFreeListsBit(Heap, FreeEntry);
@@ -414,7 +447,7 @@ RtlpCreateUnCommittedRange(PHEAP_SEGMENT Segment)
     if (IsListEmpty(&Heap->UCRList))
     {
         /* Get a pointer to the first UCR segment */
-        UcrSegment = CONTAINING_RECORD(&Heap->UCRSegments.Flink, HEAP_UCR_SEGMENT, ListEntry);
+        UcrSegment = CONTAINING_RECORD(Heap->UCRSegments.Flink, HEAP_UCR_SEGMENT, ListEntry);
 
         /* Check the list of UCR segments */
         if (IsListEmpty(&Heap->UCRSegments) ||
@@ -443,7 +476,7 @@ RtlpCreateUnCommittedRange(PHEAP_SEGMENT Segment)
             {
                 /* Release reserved memory */
                 ZwFreeVirtualMemory(NtCurrentProcess(),
-                                    (PVOID *)&UcrDescriptor,
+                                    (PVOID *)&UcrSegment,
                                     &ReserveSize,
                                     MEM_RELEASE);
                 return NULL;
@@ -477,7 +510,7 @@ RtlpCreateUnCommittedRange(PHEAP_SEGMENT Segment)
         }
 
         /* There is a whole bunch of new UCR descriptors. Put them into the unused list */
-        while ((PCHAR)UcrDescriptor < ((PCHAR)UcrSegment + UcrSegment->CommittedSize))
+        while ((PCHAR)(UcrDescriptor + 1) <= (PCHAR)UcrSegment + UcrSegment->CommittedSize)
         {
             InsertTailList(&Heap->UCRList, &UcrDescriptor->ListEntry);
             UcrDescriptor++;
@@ -515,7 +548,7 @@ RtlpInsertUnCommittedPages(PHEAP_SEGMENT Segment,
     /* Go through the list of UCR descriptors, they are sorted from lowest address
        to the highest */
     Current = Segment->UCRSegmentList.Flink;
-    while(Current != &Segment->UCRSegmentList)
+    while (Current != &Segment->UCRSegmentList)
     {
         UcrDescriptor = CONTAINING_RECORD(Current, HEAP_UCR_DESCRIPTOR, SegmentEntry);
 
@@ -530,7 +563,7 @@ RtlpInsertUnCommittedPages(PHEAP_SEGMENT Segment,
                 return;
             }
 
-            /* We found the block after which the new one should go */
+            /* We found the block before which the new one should go */
             break;
         }
         else if (((ULONG_PTR)UcrDescriptor->Address + UcrDescriptor->Size) == Address)
@@ -539,8 +572,11 @@ RtlpInsertUnCommittedPages(PHEAP_SEGMENT Segment,
             Address = (ULONG_PTR)UcrDescriptor->Address;
             Size += UcrDescriptor->Size;
 
-            /* Remove it from the list and destroy it */
-            RemoveEntryList(Current);
+            /* Advance to the next descriptor */
+            Current = Current->Flink;
+
+            /* Remove the current descriptor from the list and destroy it */
+            RemoveEntryList(&UcrDescriptor->SegmentEntry);
             RtlpDestroyUnCommittedRange(Segment, UcrDescriptor);
 
             Segment->NumberOfUnCommittedRanges--;
@@ -559,7 +595,7 @@ RtlpInsertUnCommittedPages(PHEAP_SEGMENT Segment,
     UcrDescriptor->Address = (PVOID)Address;
     UcrDescriptor->Size = Size;
 
-    /* "Current" is the descriptor after which our one should go */
+    /* "Current" is the descriptor before which our one should go */
     InsertTailList(Current, &UcrDescriptor->SegmentEntry);
 
     DPRINT("Added segment UCR with base %p, size 0x%x\n", Address, Size);
@@ -577,14 +613,14 @@ RtlpFindAndCommitPages(PHEAP Heap,
     PLIST_ENTRY Current;
     ULONG_PTR Address = 0;
     PHEAP_UCR_DESCRIPTOR UcrDescriptor, PreviousUcr = NULL;
-    PHEAP_ENTRY FirstEntry, LastEntry, PreviousLastEntry;
+    PHEAP_ENTRY FirstEntry, LastEntry;
     NTSTATUS Status;
 
     DPRINT("RtlpFindAndCommitPages(%p %p %x %p)\n", Heap, Segment, *Size, Address);
 
     /* Go through UCRs in a segment */
     Current = Segment->UCRSegmentList.Flink;
-    while(Current != &Segment->UCRSegmentList)
+    while (Current != &Segment->UCRSegmentList)
     {
         UcrDescriptor = CONTAINING_RECORD(Current, HEAP_UCR_DESCRIPTOR, SegmentEntry);
 
@@ -620,45 +656,23 @@ RtlpFindAndCommitPages(PHEAP Heap,
             }
 
             /* Update tracking numbers */
-            Segment->NumberOfUnCommittedPages -= *Size / PAGE_SIZE;
+            Segment->NumberOfUnCommittedPages -= (ULONG)(*Size / PAGE_SIZE);
 
             /* Calculate first and last entries */
             FirstEntry = (PHEAP_ENTRY)Address;
 
-            if ((Segment->LastEntryInSegment->Flags & HEAP_ENTRY_LAST_ENTRY) &&
-                (ULONG_PTR)(Segment->LastEntryInSegment + Segment->LastEntryInSegment->Size) == (ULONG_PTR)UcrDescriptor->Address)
-            {
-                LastEntry = Segment->LastEntryInSegment;
-            }
+            /* Go through the entries to find the last one */
+            if (PreviousUcr)
+                LastEntry = (PHEAP_ENTRY)((ULONG_PTR)PreviousUcr->Address + PreviousUcr->Size);
             else
-            {
-                /* Go through the entries to find the last one */
+                LastEntry = &Segment->Entry;
 
-                if (PreviousUcr)
-                    LastEntry = (PHEAP_ENTRY)((ULONG_PTR)PreviousUcr->Address + PreviousUcr->Size);
-                else
-                    LastEntry = Segment->FirstEntry;
-
-                while (!(LastEntry->Flags & HEAP_ENTRY_LAST_ENTRY))
-                {
-                    PreviousLastEntry = LastEntry;
-                    LastEntry += LastEntry->Size;
-
-                    if ((ULONG_PTR)LastEntry >= (ULONG_PTR)Segment->LastValidEntry ||
-                        LastEntry->Size == 0)
-                    {
-                        if (LastEntry == (PHEAP_ENTRY)Address)
-                        {
-                            /* Found it */
-                            LastEntry = PreviousLastEntry;
-                            break;
-                        }
-
-                        DPRINT1("Last entry not found in a committed range near to %p\n", PreviousLastEntry);
-                        return NULL;
-                    }
-                }
+            while (!(LastEntry->Flags & HEAP_ENTRY_LAST_ENTRY))
+            {
+                ASSERT(LastEntry->Size != 0);
+                LastEntry += LastEntry->Size;
             }
+            ASSERT((LastEntry + LastEntry->Size) == FirstEntry);
 
             /* Unmark it as a last entry */
             LastEntry->Flags &= ~HEAP_ENTRY_LAST_ENTRY;
@@ -670,19 +684,27 @@ RtlpFindAndCommitPages(PHEAP Heap,
             DPRINT("Updating UcrDescriptor %p, new Address %p, size %d\n",
                 UcrDescriptor, UcrDescriptor->Address, UcrDescriptor->Size);
 
+            /* Set various first entry fields */
+            FirstEntry->SegmentOffset = LastEntry->SegmentOffset;
+            FirstEntry->Size = (USHORT)(*Size >> HEAP_ENTRY_SHIFT);
+            FirstEntry->PreviousSize = LastEntry->Size;
+
             /* Check if anything left in this UCR */
             if (UcrDescriptor->Size == 0)
             {
                 /* It's fully exhausted */
-                if (UcrDescriptor->Address == Segment->LastValidEntry)
+
+                /* Check if this is the end of the segment */
+                if(UcrDescriptor->Address == Segment->LastValidEntry)
                 {
                     FirstEntry->Flags = HEAP_ENTRY_LAST_ENTRY;
-                    Segment->LastEntryInSegment = FirstEntry;
                 }
                 else
                 {
                     FirstEntry->Flags = 0;
-                    Segment->LastEntryInSegment = Segment->FirstEntry;
+                    /* Update field of next entry */
+                    ASSERT((FirstEntry + FirstEntry->Size)->PreviousSize == 0);
+                    (FirstEntry + FirstEntry->Size)->PreviousSize = FirstEntry->Size;
                 }
 
                 /* This UCR needs to be removed because it became useless */
@@ -694,18 +716,8 @@ RtlpFindAndCommitPages(PHEAP Heap,
             else
             {
                 FirstEntry->Flags = HEAP_ENTRY_LAST_ENTRY;
-                Segment->LastEntryInSegment = FirstEntry;
             }
 
-            /* Set various first entry fields*/
-            FirstEntry->SegmentOffset = LastEntry->SegmentOffset;
-            FirstEntry->Size = *Size >> HEAP_ENTRY_SHIFT;
-            FirstEntry->PreviousSize = LastEntry->Size;
-
-            /* Update previous size */
-            if (!(FirstEntry->Flags & HEAP_ENTRY_LAST_ENTRY))
-                (FirstEntry + FirstEntry->Size)->PreviousSize = FirstEntry->Size;
-
             /* We're done */
             return (PHEAP_FREE_ENTRY)FirstEntry;
         }
@@ -727,7 +739,7 @@ RtlpDeCommitFreeBlock(PHEAP Heap,
     PHEAP_ENTRY PrecedingInUseEntry = NULL, NextInUseEntry = NULL;
     PHEAP_FREE_ENTRY NextFreeEntry;
     PHEAP_UCR_DESCRIPTOR UcrDescriptor;
-    ULONG PrecedingSize, NextSize, DecommitSize;
+    SIZE_T PrecedingSize, NextSize, DecommitSize;
     ULONG_PTR DecommitBase;
     NTSTATUS Status;
 
@@ -817,18 +829,15 @@ RtlpDeCommitFreeBlock(PHEAP Heap,
 
     /* Insert uncommitted pages */
     RtlpInsertUnCommittedPages(Segment, DecommitBase, DecommitSize);
-    Segment->NumberOfUnCommittedPages += (DecommitSize / PAGE_SIZE);
+    Segment->NumberOfUnCommittedPages += (ULONG)(DecommitSize / PAGE_SIZE);
 
     if (PrecedingSize)
     {
         /* Adjust size of this free entry and insert it */
         FreeEntry->Flags = HEAP_ENTRY_LAST_ENTRY;
-        FreeEntry->Size = PrecedingSize;
+        FreeEntry->Size = (USHORT)PrecedingSize;
         Heap->TotalFreeSize += PrecedingSize;
 
-        /* Set last entry in the segment to this entry */
-        Segment->LastEntryInSegment = (PHEAP_ENTRY)FreeEntry;
-
         /* Insert it into the free list */
         RtlpInsertFreeBlockHelper(Heap, FreeEntry, PrecedingSize, FALSE);
     }
@@ -836,12 +845,6 @@ RtlpDeCommitFreeBlock(PHEAP Heap,
     {
         /* Adjust preceding in use entry */
         PrecedingInUseEntry->Flags |= HEAP_ENTRY_LAST_ENTRY;
-        Segment->LastEntryInSegment = PrecedingInUseEntry;
-    } else if ((ULONG_PTR)Segment->LastEntryInSegment >= DecommitBase &&
-               ((PCHAR)Segment->LastEntryInSegment < ((PCHAR)DecommitBase + DecommitSize)))
-    {
-        /* Update this segment's last entry */
-        Segment->LastEntryInSegment = Segment->FirstEntry;
     }
 
     /* Now the next one */
@@ -851,9 +854,9 @@ RtlpDeCommitFreeBlock(PHEAP Heap,
         NextFreeEntry->Flags = 0;
         NextFreeEntry->PreviousSize = 0;
         NextFreeEntry->SegmentOffset = Segment->Entry.SegmentOffset;
-        NextFreeEntry->Size = NextSize;
+        NextFreeEntry->Size = (USHORT)NextSize;
 
-        ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)NextFreeEntry + NextSize))->PreviousSize = NextSize;
+        ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)NextFreeEntry + NextSize))->PreviousSize = (USHORT)NextSize;
 
         Heap->TotalFreeSize += NextSize;
         RtlpInsertFreeBlockHelper(Heap, NextFreeEntry, NextSize, FALSE);
@@ -864,96 +867,78 @@ RtlpDeCommitFreeBlock(PHEAP Heap,
     }
 }
 
-BOOLEAN NTAPI
-RtlpInitializeHeapSegment(PHEAP Heap,
-                          PHEAP_SEGMENT Segment,
-                          UCHAR SegmentIndex,
-                          ULONG Flags,
-                          PVOID BaseAddress,
-                          PVOID UncommittedBase,
-                          PVOID LimitAddress)
+NTSTATUS
+NTAPI
+RtlpInitializeHeapSegment(IN OUT PHEAP Heap,
+                          OUT PHEAP_SEGMENT Segment,
+                          IN UCHAR SegmentIndex,
+                          IN ULONG SegmentFlags,
+                          IN SIZE_T SegmentReserve,
+                          IN SIZE_T SegmentCommit)
 {
-    ULONG Pages, CommitSize;
     PHEAP_ENTRY HeapEntry;
-    USHORT PreviousSize = 0, NewSize;
-    NTSTATUS Status;
 
-    Pages = ((PCHAR)LimitAddress - (PCHAR)BaseAddress) / PAGE_SIZE;
+    /* Preconditions */
+    ASSERT(Heap != NULL);
+    ASSERT(Segment != NULL);
+    ASSERT(SegmentCommit >= PAGE_SIZE);
+    ASSERT(ROUND_DOWN(SegmentCommit, PAGE_SIZE) == SegmentCommit);
+    ASSERT(SegmentReserve >= SegmentCommit);
+    ASSERT(ROUND_DOWN(SegmentReserve, PAGE_SIZE) == SegmentReserve);
 
-    HeapEntry = (PHEAP_ENTRY)ROUND_UP(Segment + 1, HEAP_ENTRY_SIZE);
+    DPRINT("RtlpInitializeHeapSegment(%p %p %x %x %lx %lx)\n", Heap, Segment, SegmentIndex, SegmentFlags, SegmentReserve, SegmentCommit);
 
-    DPRINT("RtlpInitializeHeapSegment(%p %p %x %x %p %p %p)\n", Heap, Segment, SegmentIndex, Flags, BaseAddress, UncommittedBase, LimitAddress);
-    DPRINT("Pages %x, HeapEntry %p, sizeof(HEAP_SEGMENT) %x\n", Pages, HeapEntry, sizeof(HEAP_SEGMENT));
-
-    /* Check if it's the first segment and remember its size */
-    if (Heap == BaseAddress)
-        PreviousSize = Heap->Entry.Size;
-
-    NewSize = ((PCHAR)HeapEntry - (PCHAR)Segment) >> HEAP_ENTRY_SHIFT;
-
-    if ((PVOID)(HeapEntry + 1) >= UncommittedBase)
+    /* Initialise the Heap Entry header if this is not the first Heap Segment */
+    if ((PHEAP_SEGMENT) (Heap) != Segment)
     {
-        /* Check if it goes beyond the limit */
-        if ((PVOID)(HeapEntry + 1) >= LimitAddress)
-            return FALSE;
-
-        /* Need to commit memory */
-        CommitSize = (PCHAR)(HeapEntry + 1) - (PCHAR)UncommittedBase;
-        Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
-                                        (PVOID)&UncommittedBase,
-                                        0,
-                                        &CommitSize,
-                                        MEM_COMMIT,
-                                        PAGE_READWRITE);
-        if (!NT_SUCCESS(Status))
-        {
-            DPRINT1("Committing page failed with status 0x%08X\n", Status);
-            return FALSE;
-        }
-
-        DPRINT("Committed %d bytes at base %p\n", CommitSize, UncommittedBase);
-
-        /* Calcule the new uncommitted base */
-        UncommittedBase = (PVOID)((PCHAR)UncommittedBase + CommitSize);
+        Segment->Entry.Size = ROUND_UP(sizeof(HEAP_SEGMENT), sizeof(HEAP_ENTRY)) >> HEAP_ENTRY_SHIFT;
+        Segment->Entry.Flags = HEAP_ENTRY_BUSY;
+        Segment->Entry.SmallTagIndex = LOBYTE(Segment->Entry.Size) ^ HIBYTE(Segment->Entry.Size) ^ Segment->Entry.Flags;
+        Segment->Entry.PreviousSize = 0;
+        Segment->Entry.SegmentOffset = SegmentIndex;
+        Segment->Entry.UnusedBytes = 0;
     }
 
-    /* Initialize the segment entry */
-    Segment->Entry.PreviousSize = PreviousSize;
-    Segment->Entry.Size = NewSize;
-    Segment->Entry.Flags = HEAP_ENTRY_BUSY;
-    Segment->Entry.SegmentOffset = SegmentIndex;
+    /* Sanity check */
+    ASSERT((Segment->Entry.Size << HEAP_ENTRY_SHIFT) <= PAGE_SIZE);
 
-    /* Initialize the segment itself */
+    /* Initialise the Heap Segment header */
     Segment->SegmentSignature = HEAP_SEGMENT_SIGNATURE;
+    Segment->SegmentFlags = SegmentFlags;
     Segment->Heap = Heap;
-    Segment->BaseAddress = BaseAddress;
-    Segment->FirstEntry = HeapEntry;
-    Segment->LastValidEntry = (PHEAP_ENTRY)((PCHAR)BaseAddress + Pages * PAGE_SIZE);
-    Segment->NumberOfPages = Pages;
-    Segment->NumberOfUnCommittedPages = ((PCHAR)LimitAddress - (PCHAR)UncommittedBase) / PAGE_SIZE;
-    InitializeListHead(&Segment->UCRSegmentList);
+    Heap->Segments[SegmentIndex] = Segment;
 
-    /* Insert uncommitted pages into UCR (uncommitted ranges) list */
-    if (Segment->NumberOfUnCommittedPages)
+    /* Initialise the Heap Segment location information */
+    Segment->BaseAddress = Segment;
+    Segment->NumberOfPages = (ULONG)(SegmentReserve >> PAGE_SHIFT);
+
+    /* Initialise the Heap Entries contained within the Heap Segment */
+    Segment->FirstEntry = &Segment->Entry + Segment->Entry.Size;
+    Segment->LastValidEntry = (PHEAP_ENTRY)((ULONG_PTR)Segment + SegmentReserve);
+
+    if (((SIZE_T)Segment->Entry.Size << HEAP_ENTRY_SHIFT) < SegmentCommit)
     {
-        RtlpInsertUnCommittedPages(Segment, (ULONG_PTR)UncommittedBase, Segment->NumberOfUnCommittedPages * PAGE_SIZE);
-    }
+        HeapEntry = Segment->FirstEntry;
 
-    /* Set the segment index pointer */
-    Heap->Segments[SegmentIndex] = Segment;
+        /* Prepare a Free Heap Entry header */
+        HeapEntry->Flags = HEAP_ENTRY_LAST_ENTRY;
+        HeapEntry->PreviousSize = Segment->Entry.Size;
+        HeapEntry->SegmentOffset = SegmentIndex;
 
-    /* Prepare a free heap entry */
-    HeapEntry->Flags = HEAP_ENTRY_LAST_ENTRY;
-    HeapEntry->PreviousSize = Segment->Entry.Size;
-    HeapEntry->SegmentOffset = SegmentIndex;
+        /* Register the Free Heap Entry */
+        RtlpInsertFreeBlock(Heap, (PHEAP_FREE_ENTRY) HeapEntry, (SegmentCommit >> HEAP_ENTRY_SHIFT) - Segment->Entry.Size);
+    }
 
-    /* Set last entry in segment */
-    Segment->LastEntryInSegment = HeapEntry;
+    /* Initialise the Heap Segment UnCommitted Range information */
+    Segment->NumberOfUnCommittedPages = (ULONG)((SegmentReserve - SegmentCommit) >> PAGE_SHIFT);
+    Segment->NumberOfUnCommittedRanges = 0;
+    InitializeListHead(&Segment->UCRSegmentList);
 
-    /* Insert it */
-    RtlpInsertFreeBlock(Heap, (PHEAP_FREE_ENTRY)HeapEntry, (PHEAP_ENTRY)UncommittedBase - HeapEntry);
+    /* Register the UnCommitted Range of the Heap Segment */
+    if (Segment->NumberOfUnCommittedPages != 0)
+        RtlpInsertUnCommittedPages(Segment, (ULONG_PTR) (Segment) + SegmentCommit, SegmentReserve - SegmentCommit);
 
-    return TRUE;
+    return STATUS_SUCCESS;
 }
 
 VOID NTAPI
@@ -991,7 +976,7 @@ RtlpAddHeapToProcessList(PHEAP Heap)
     Peb = RtlGetCurrentPeb();
 
     /* Acquire the lock */
-    RtlEnterHeapLock(&RtlpProcessHeapsListLock);
+    RtlEnterCriticalSection(&RtlpProcessHeapsListLock);
 
     //_SEH2_TRY {
     /* Check if max number of heaps reached */
@@ -1004,11 +989,11 @@ RtlpAddHeapToProcessList(PHEAP Heap)
     /* Add the heap to the process heaps */
     Peb->ProcessHeaps[Peb->NumberOfHeaps] = Heap;
     Peb->NumberOfHeaps++;
-    Heap->ProcessHeapsListIndex = Peb->NumberOfHeaps;
+    Heap->ProcessHeapsListIndex = (USHORT)Peb->NumberOfHeaps;
     // } _SEH2_FINALLY {
 
     /* Release the lock */
-    RtlLeaveHeapLock(&RtlpProcessHeapsListLock);
+    RtlLeaveCriticalSection(&RtlpProcessHeapsListLock);
 
     // } _SEH2_END
 }
@@ -1025,7 +1010,7 @@ RtlpRemoveHeapFromProcessList(PHEAP Heap)
     Peb = RtlGetCurrentPeb();
 
     /* Acquire the lock */
-    RtlEnterHeapLock(&RtlpProcessHeapsListLock);
+    RtlEnterCriticalSection(&RtlpProcessHeapsListLock);
 
     /* Check if we don't need anything to do */
     if ((Heap->ProcessHeapsListIndex == 0) ||
@@ -1033,7 +1018,7 @@ RtlpRemoveHeapFromProcessList(PHEAP Heap)
         (Peb->NumberOfHeaps == 0))
     {
         /* Release the lock */
-        RtlLeaveHeapLock(&RtlpProcessHeapsListLock);
+        RtlLeaveCriticalSection(&RtlpProcessHeapsListLock);
 
         return;
     }
@@ -1070,7 +1055,7 @@ RtlpRemoveHeapFromProcessList(PHEAP Heap)
     Heap->ProcessHeapsListIndex = 0;
 
     /* Release the lock */
-    RtlLeaveHeapLock(&RtlpProcessHeapsListLock);
+    RtlLeaveCriticalSection(&RtlpProcessHeapsListLock);
 }
 
 PHEAP_FREE_ENTRY NTAPI
@@ -1114,20 +1099,16 @@ RtlpCoalesceFreeBlocks (PHEAP Heap,
         /* Copy flags */
         CurrentEntry->Flags = FreeEntry->Flags & HEAP_ENTRY_LAST_ENTRY;
 
-        /* Update last entry in the segment */
-        if (CurrentEntry->Flags & HEAP_ENTRY_LAST_ENTRY)
-            Heap->Segments[CurrentEntry->SegmentOffset]->LastEntryInSegment = (PHEAP_ENTRY)CurrentEntry;
-
         /* Advance FreeEntry and update sizes */
         FreeEntry = CurrentEntry;
         *FreeSize = *FreeSize + CurrentEntry->Size;
         Heap->TotalFreeSize -= CurrentEntry->Size;
-        FreeEntry->Size = *FreeSize;
+        FreeEntry->Size = (USHORT)(*FreeSize);
 
         /* Also update previous size if needed */
         if (!(FreeEntry->Flags & HEAP_ENTRY_LAST_ENTRY))
         {
-            ((PHEAP_ENTRY)FreeEntry + *FreeSize)->PreviousSize = *FreeSize;
+            ((PHEAP_ENTRY)FreeEntry + *FreeSize)->PreviousSize = (USHORT)(*FreeSize);
         }
     }
 
@@ -1151,22 +1132,18 @@ RtlpCoalesceFreeBlocks (PHEAP Heap,
             /* Copy flags */
             FreeEntry->Flags = NextEntry->Flags & HEAP_ENTRY_LAST_ENTRY;
 
-            /* Update last entry in the segment */
-            if (FreeEntry->Flags & HEAP_ENTRY_LAST_ENTRY)
-                Heap->Segments[FreeEntry->SegmentOffset]->LastEntryInSegment = (PHEAP_ENTRY)FreeEntry;
-
             /* Remove next entry now */
             RtlpRemoveFreeBlock(Heap, NextEntry, FALSE, FALSE);
 
             /* Update sizes */
             *FreeSize = *FreeSize + NextEntry->Size;
             Heap->TotalFreeSize -= NextEntry->Size;
-            FreeEntry->Size = *FreeSize;
+            FreeEntry->Size = (USHORT)(*FreeSize);
 
             /* Also update previous size if needed */
             if (!(FreeEntry->Flags & HEAP_ENTRY_LAST_ENTRY))
             {
-                ((PHEAP_ENTRY)FreeEntry + *FreeSize)->PreviousSize = *FreeSize;
+                ((PHEAP_ENTRY)FreeEntry + *FreeSize)->PreviousSize = (USHORT)(*FreeSize);
             }
         }
     }
@@ -1187,7 +1164,7 @@ RtlpExtendHeap(PHEAP Heap,
     DPRINT("RtlpExtendHeap(%p %x)\n", Heap, Size);
 
     /* Calculate amount in pages */
-    Pages = (Size + PAGE_SIZE - 1) / PAGE_SIZE;
+    Pages = (ULONG)((Size + PAGE_SIZE - 1) / PAGE_SIZE);
     FreeSize = Pages * PAGE_SIZE;
     DPRINT("Pages %x, FreeSize %x. Going through segments...\n", Pages, FreeSize);
 
@@ -1283,13 +1260,7 @@ RtlpExtendHeap(PHEAP Heap,
 
             /* Initialize heap segment if commit was successful */
             if (NT_SUCCESS(Status))
-            {
-                if (!RtlpInitializeHeapSegment(Heap, Segment, EmptyIndex, 0, Segment,
-                    (PCHAR)Segment + CommitSize, (PCHAR)Segment + ReserveSize))
-                {
-                    Status = STATUS_NO_MEMORY;
-                }
-            }
+                Status = RtlpInitializeHeapSegment(Heap, Segment, EmptyIndex, 0, ReserveSize, CommitSize);
 
             /* If everything worked - cool */
             if (NT_SUCCESS(Status)) return (PHEAP_FREE_ENTRY)Segment->FirstEntry;
@@ -1353,8 +1324,7 @@ RtlCreateHeap(ULONG Flags,
     ULONG NtGlobalFlags = RtlGetNtGlobalFlags();
     ULONG HeapSegmentFlags = 0;
     NTSTATUS Status;
-    ULONG MaxBlockSize, HeaderSize;
-    BOOLEAN AllocateLock = FALSE;
+    ULONG MaxBlockSize;
 
     /* Check for a special heap */
     if (RtlpPageHeapEnabled && !Addr && !Lock)
@@ -1477,25 +1447,9 @@ RtlCreateHeap(ULONG Flags,
     if (RtlpHeapIsSpecial(Flags))
         return RtlDebugCreateHeap(Flags, Addr, TotalSize, CommitSize, Lock, Parameters);
 
-    /* Calculate header size */
-    HeaderSize = sizeof(HEAP);
-    if (!(Flags & HEAP_NO_SERIALIZE))
-    {
-        if (Lock)
-        {
-            Flags |= HEAP_LOCK_USER_ALLOCATED;
-        }
-        else
-        {
-            HeaderSize += sizeof(HEAP_LOCK);
-            AllocateLock = TRUE;
-        }
-    }
-    else if (Lock)
-    {
-        /* Invalid parameters */
+    /* Without serialization, a lock makes no sense */
+    if ((Flags & HEAP_NO_SERIALIZE) && (Lock != NULL))
         return NULL;
-    }
 
     /* See if we are already provided with an address for the heap */
     if (Addr)
@@ -1638,48 +1592,23 @@ RtlCreateHeap(ULONG Flags,
         UncommittedAddress = (PCHAR)UncommittedAddress + CommitSize;
     }
 
-    DPRINT("Created heap %p, CommitSize %x, ReserveSize %x\n", Heap, CommitSize, TotalSize);
-
     /* Initialize the heap */
-    RtlpInitializeHeap(Heap, &HeaderSize, Flags, AllocateLock, Lock);
-
-    /* Initialize heap's first segment */
-    if (!RtlpInitializeHeapSegment(Heap,
-                                   (PHEAP_SEGMENT)((PCHAR)Heap + HeaderSize),
-                                   0,
-                                   HeapSegmentFlags,
-                                   CommittedAddress,
-                                   UncommittedAddress,
-                                   (PCHAR)CommittedAddress + TotalSize))
-    {
-        DPRINT1("Failed to initialize heap segment\n");
+    Status = RtlpInitializeHeap(Heap, Flags, Lock, Parameters);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to initialize heap (%x)\n", Status);
         return NULL;
     }
 
-    /* Set other data */
-    Heap->ProcessHeapsListIndex = 0;
-    Heap->SegmentCommit = Parameters->SegmentCommit;
-    Heap->SegmentReserve = Parameters->SegmentReserve;
-    Heap->DeCommitFreeBlockThreshold = Parameters->DeCommitFreeBlockThreshold >> HEAP_ENTRY_SHIFT;
-    Heap->DeCommitTotalFreeThreshold = Parameters->DeCommitTotalFreeThreshold >> HEAP_ENTRY_SHIFT;
-    Heap->MaximumAllocationSize = Parameters->MaximumAllocationSize;
-    Heap->VirtualMemoryThreshold = ROUND_UP(Parameters->VirtualMemoryThreshold, HEAP_ENTRY_SIZE) >> HEAP_ENTRY_SHIFT;
-    Heap->CommitRoutine = Parameters->CommitRoutine;
-
-    /* Set alignment */
-    if (Flags & HEAP_CREATE_ALIGN_16)
-    {
-        Heap->AlignMask = (ULONG)~15;
-        Heap->AlignRound = 15 + sizeof(HEAP_ENTRY);
-    }
-    else
+    /* Initialize heap's first segment */
+    Status = RtlpInitializeHeapSegment(Heap, (PHEAP_SEGMENT) (Heap), 0, HeapSegmentFlags, TotalSize, CommitSize);
+    if (!NT_SUCCESS(Status))
     {
-        Heap->AlignMask = (ULONG)~(HEAP_ENTRY_SIZE - 1);
-        Heap->AlignRound = HEAP_ENTRY_SIZE - 1 + sizeof(HEAP_ENTRY);
+        DPRINT1("Failed to initialize heap segment (%x)\n", Status);
+        return NULL;
     }
 
-    if (Heap->Flags & HEAP_TAIL_CHECKING_ENABLED)
-        Heap->AlignRound += HEAP_ENTRY_SIZE;
+    DPRINT("Created heap %p, CommitSize %x, ReserveSize %x\n", Heap, CommitSize, TotalSize);
 
     /* Add heap to process list in case of usermode heap */
     if (RtlpGetMode() == UserMode)
@@ -1689,7 +1618,6 @@ RtlCreateHeap(ULONG Flags,
         // FIXME: What about lookasides?
     }
 
-    DPRINT("Heap %p, flags 0x%08x\n", Heap, Heap->Flags);
     return Heap;
 }
 
@@ -1766,7 +1694,7 @@ RtlDestroyHeap(HANDLE HeapPtr) /* [in] Handle of heap */
 
     /* Free UCR segments if any were created */
     Current = Heap->UCRSegments.Flink;
-    while(Current != &Heap->UCRSegments)
+    while (Current != &Heap->UCRSegments)
     {
         UcrSegment = CONTAINING_RECORD(Current, HEAP_UCR_SEGMENT, ListEntry);
 
@@ -1795,31 +1723,47 @@ RtlDestroyHeap(HANDLE HeapPtr) /* [in] Handle of heap */
 
 PHEAP_ENTRY NTAPI
 RtlpSplitEntry(PHEAP Heap,
+               ULONG Flags,
                PHEAP_FREE_ENTRY FreeBlock,
                SIZE_T AllocationSize,
                SIZE_T Index,
                SIZE_T Size)
 {
     PHEAP_FREE_ENTRY SplitBlock, SplitBlock2;
-    UCHAR FreeFlags;
+    UCHAR FreeFlags, EntryFlags = HEAP_ENTRY_BUSY;
     PHEAP_ENTRY InUseEntry;
     SIZE_T FreeSize;
 
+    /* Add extra flags in case of settable user value feature is requested,
+       or there is a tag (small or normal) or there is a request to
+       capture stack backtraces */
+    if ((Flags & HEAP_EXTRA_FLAGS_MASK) ||
+        Heap->PseudoTagEntries)
+    {
+        /* Add flag which means that the entry will have extra stuff attached */
+        EntryFlags |= HEAP_ENTRY_EXTRA_PRESENT;
+
+        /* NB! AllocationSize is already adjusted by RtlAllocateHeap */
+    }
+
+    /* Add settable user flags, if any */
+    EntryFlags |= (Flags & HEAP_SETTABLE_USER_FLAGS) >> 4;
+
     /* Save flags, update total free size */
     FreeFlags = FreeBlock->Flags;
     Heap->TotalFreeSize -= FreeBlock->Size;
 
     /* Make this block an in-use one */
     InUseEntry = (PHEAP_ENTRY)FreeBlock;
-    InUseEntry->Flags = HEAP_ENTRY_BUSY;
+    InUseEntry->Flags = EntryFlags;
     InUseEntry->SmallTagIndex = 0;
 
     /* Calculate the extra amount */
     FreeSize = InUseEntry->Size - Index;
 
     /* Update it's size fields (we don't need their data anymore) */
-    InUseEntry->Size = Index;
-    InUseEntry->UnusedBytes = AllocationSize - Size;
+    InUseEntry->Size = (USHORT)Index;
+    InUseEntry->UnusedBytes = (UCHAR)(AllocationSize - Size);
 
     /* If there is something to split - do the split */
     if (FreeSize != 0)
@@ -1840,8 +1784,8 @@ RtlpSplitEntry(PHEAP Heap,
             /* Initialize it */
             SplitBlock->Flags = FreeFlags;
             SplitBlock->SegmentOffset = InUseEntry->SegmentOffset;
-            SplitBlock->Size = FreeSize;
-            SplitBlock->PreviousSize = Index;
+            SplitBlock->Size = (USHORT)FreeSize;
+            SplitBlock->PreviousSize = (USHORT)Index;
 
             /* Check if it's the last entry */
             if (FreeFlags & HEAP_ENTRY_LAST_ENTRY)
@@ -1876,12 +1820,12 @@ RtlpSplitEntry(PHEAP Heap,
                     if (FreeSize <= HEAP_MAX_BLOCK_SIZE)
                     {
                         /* Insert it back */
-                        SplitBlock->Size = FreeSize;
+                        SplitBlock->Size = (USHORT)FreeSize;
 
                         /* Don't forget to update previous size of the next entry! */
                         if (!(SplitBlock->Flags & HEAP_ENTRY_LAST_ENTRY))
                         {
-                            ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize))->PreviousSize = FreeSize;
+                            ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize))->PreviousSize = (USHORT)FreeSize;
                         }
 
                         /* Actually insert it */
@@ -1900,12 +1844,6 @@ RtlpSplitEntry(PHEAP Heap,
 
             /* Reset flags of the free entry */
             FreeFlags = 0;
-
-            /* Update last entry in segment */
-            if (SplitBlock->Flags & HEAP_ENTRY_LAST_ENTRY)
-            {
-                Heap->Segments[SplitBlock->SegmentOffset]->LastEntryInSegment = (PHEAP_ENTRY)SplitBlock;
-            }
         }
     }
 
@@ -1956,7 +1894,7 @@ RtlpAllocateNonDedicated(PHEAP Heap,
                     RemoveEntryList(&FreeBlock->FreeList);
 
                     /* Split it */
-                    InUseEntry = RtlpSplitEntry(Heap, FreeBlock, AllocationSize, Index, Size);
+                    InUseEntry = RtlpSplitEntry(Heap, Flags, FreeBlock, AllocationSize, Index, Size);
 
                     /* Release the lock */
                     if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
@@ -2005,7 +1943,7 @@ RtlpAllocateNonDedicated(PHEAP Heap,
         RemoveEntryList(&FreeBlock->FreeList);
 
         /* Split it */
-        InUseEntry = RtlpSplitEntry(Heap, FreeBlock, AllocationSize, Index, Size);
+        InUseEntry = RtlpSplitEntry(Heap, Flags, FreeBlock, AllocationSize, Index, Size);
 
         /* Release the lock */
         if (HeapLocked) RtlLeaveHeapLock(Heap->LockVariable);
@@ -2078,12 +2016,11 @@ RtlAllocateHeap(IN PVOID HeapPtr,
     PULONG FreeListsInUse;
     ULONG FreeListsInUseUlong;
     SIZE_T AllocationSize;
-    SIZE_T Index;
+    SIZE_T Index, InUseIndex, i;
     PLIST_ENTRY FreeListHead;
     PHEAP_ENTRY InUseEntry;
     PHEAP_FREE_ENTRY FreeBlock;
-    ULONG InUseIndex, i;
-    UCHAR FreeFlags;
+    UCHAR FreeFlags, EntryFlags = HEAP_ENTRY_BUSY;
     EXCEPTION_RECORD ExceptionRecord;
     BOOLEAN HeapLocked = FALSE;
     PHEAP_VIRTUAL_ALLOC_ENTRY VirtualBlock = NULL;
@@ -2119,12 +2056,29 @@ RtlAllocateHeap(IN PVOID HeapPtr,
     else
         AllocationSize = 1;
     AllocationSize = (AllocationSize + Heap->AlignRound) & Heap->AlignMask;
+
+    /* Add extra flags in case of settable user value feature is requested,
+       or there is a tag (small or normal) or there is a request to
+       capture stack backtraces */
+    if ((Flags & HEAP_EXTRA_FLAGS_MASK) ||
+        Heap->PseudoTagEntries)
+    {
+        /* Add flag which means that the entry will have extra stuff attached */
+        EntryFlags |= HEAP_ENTRY_EXTRA_PRESENT;
+
+        /* Account for extra stuff size */
+        AllocationSize += sizeof(HEAP_ENTRY_EXTRA);
+    }
+
+    /* Add settable user flags, if any */
+    EntryFlags |= (Flags & HEAP_SETTABLE_USER_FLAGS) >> 4;
+
     Index = AllocationSize >>  HEAP_ENTRY_SHIFT;
 
     /* Acquire the lock if necessary */
     if (!(Flags & HEAP_NO_SERIALIZE))
     {
-        RtlEnterHeapLock(Heap->LockVariable);
+        RtlEnterHeapLock(Heap->LockVariable, TRUE);
         HeapLocked = TRUE;
     }
 
@@ -2150,8 +2104,8 @@ RtlAllocateHeap(IN PVOID HeapPtr,
 
             /* Initialize this block */
             InUseEntry = (PHEAP_ENTRY)FreeBlock;
-            InUseEntry->Flags = HEAP_ENTRY_BUSY | (FreeFlags & HEAP_ENTRY_LAST_ENTRY);
-            InUseEntry->UnusedBytes = AllocationSize - Size;
+            InUseEntry->Flags = EntryFlags | (FreeFlags & HEAP_ENTRY_LAST_ENTRY);
+            InUseEntry->UnusedBytes = (UCHAR)(AllocationSize - Size);
             InUseEntry->SmallTagIndex = 0;
         }
         else
@@ -2193,7 +2147,7 @@ RtlAllocateHeap(IN PVOID HeapPtr,
             RtlpRemoveFreeBlock(Heap, FreeBlock, TRUE, FALSE);
 
             /* Split it */
-            InUseEntry = RtlpSplitEntry(Heap, FreeBlock, AllocationSize, Index, Size);
+            InUseEntry = RtlpSplitEntry(Heap, Flags, FreeBlock, AllocationSize, Index, Size);
         }
 
         /* Release the lock */
@@ -2254,8 +2208,8 @@ RtlAllocateHeap(IN PVOID HeapPtr,
         }
 
         /* Initialize the newly allocated block */
-        VirtualBlock->BusyBlock.Size = (AllocationSize - Size);
-        VirtualBlock->BusyBlock.Flags = HEAP_ENTRY_VIRTUAL_ALLOC | HEAP_ENTRY_EXTRA_PRESENT | HEAP_ENTRY_BUSY;
+        VirtualBlock->BusyBlock.Size = (USHORT)(AllocationSize - Size);
+        VirtualBlock->BusyBlock.Flags = EntryFlags | HEAP_ENTRY_VIRTUAL_ALLOC | HEAP_ENTRY_EXTRA_PRESENT;
         VirtualBlock->CommitSize = AllocationSize;
         VirtualBlock->ReserveSize = AllocationSize;
 
@@ -2326,7 +2280,7 @@ BOOLEAN NTAPI RtlFreeHeap(
     /* Lock if necessary */
     if (!(Flags & HEAP_NO_SERIALIZE))
     {
-        RtlEnterHeapLock(Heap->LockVariable);
+        RtlEnterHeapLock(Heap->LockVariable, TRUE);
         Locked = TRUE;
     }
 
@@ -2530,8 +2484,8 @@ RtlpGrowBlockInPlace (IN PHEAP Heap,
     }
 
     /* Update sizes */
-    InUseEntry->Size = Index;
-    InUseEntry->UnusedBytes = ((Index << HEAP_ENTRY_SHIFT) - Size);
+    InUseEntry->Size = (USHORT)Index;
+    InUseEntry->UnusedBytes = (UCHAR)((Index << HEAP_ENTRY_SHIFT) - Size);
 
     /* Check if there is a free space remaining after merging those blocks */
     if (!FreeSize)
@@ -2541,9 +2495,7 @@ RtlpGrowBlockInPlace (IN PHEAP Heap,
 
         /* Either update previous size of the next entry or mark it as a last
            entry in the segment*/
-        if (RememberFlags & HEAP_ENTRY_LAST_ENTRY)
-            Heap->Segments[InUseEntry->SegmentOffset]->LastEntryInSegment = InUseEntry;
-        else
+        if (!(RememberFlags & HEAP_ENTRY_LAST_ENTRY))
             (InUseEntry + InUseEntry->Size)->PreviousSize = InUseEntry->Size;
     }
     else
@@ -2551,16 +2503,15 @@ RtlpGrowBlockInPlace (IN PHEAP Heap,
         /* Complex case, we need to split the block to give unused free space
            back to the heap */
         UnusedEntry = (PHEAP_FREE_ENTRY)(InUseEntry + Index);
-        UnusedEntry->PreviousSize = Index;
+        UnusedEntry->PreviousSize = (USHORT)Index;
         UnusedEntry->SegmentOffset = InUseEntry->SegmentOffset;
 
         /* Update the following block or set the last entry in the segment */
         if (RememberFlags & HEAP_ENTRY_LAST_ENTRY)
         {
-            /* Set last entry and set flags and size */
-            Heap->Segments[InUseEntry->SegmentOffset]->LastEntryInSegment = InUseEntry;
+            /* Set flags and size */
             UnusedEntry->Flags = RememberFlags;
-            UnusedEntry->Size = FreeSize;
+            UnusedEntry->Size = (USHORT)FreeSize;
 
             /* Insert it to the heap and update total size  */
             RtlpInsertFreeBlockHelper(Heap, UnusedEntry, FreeSize, FALSE);
@@ -2575,10 +2526,10 @@ RtlpGrowBlockInPlace (IN PHEAP Heap,
             {
                 /* Update flags and set size of the unused space entry */
                 UnusedEntry->Flags = RememberFlags & (~HEAP_ENTRY_LAST_ENTRY);
-                UnusedEntry->Size = FreeSize;
+                UnusedEntry->Size = (USHORT)FreeSize;
 
                 /* Update previous size of the following entry */
-                FollowingEntry->PreviousSize = FreeSize;
+                FollowingEntry->PreviousSize = (USHORT)FreeSize;
 
                 /* Insert it to the heap and update total free size */
                 RtlpInsertFreeBlockHelper(Heap, UnusedEntry, FreeSize, FALSE);
@@ -2601,12 +2552,10 @@ RtlpGrowBlockInPlace (IN PHEAP Heap,
                 if (FreeSize <= HEAP_MAX_BLOCK_SIZE)
                 {
                     /* Fine for a dedicated list */
-                    UnusedEntry->Size = FreeSize;
+                    UnusedEntry->Size = (USHORT)FreeSize;
 
-                    if (RememberFlags & HEAP_ENTRY_LAST_ENTRY)
-                        Heap->Segments[UnusedEntry->SegmentOffset]->LastEntryInSegment = (PHEAP_ENTRY)UnusedEntry;
-                    else
-                        ((PHEAP_ENTRY)UnusedEntry + FreeSize)->PreviousSize = FreeSize;
+                    if (!(RememberFlags & HEAP_ENTRY_LAST_ENTRY))
+                        ((PHEAP_ENTRY)UnusedEntry + FreeSize)->PreviousSize = (USHORT)FreeSize;
 
                     /* Insert it back and update total size */
                     RtlpInsertFreeBlockHelper(Heap, UnusedEntry, FreeSize, FALSE);
@@ -2621,10 +2570,6 @@ RtlpGrowBlockInPlace (IN PHEAP Heap,
         }
     }
 
-    /* Copy user settable flags */
-    InUseEntry->Flags &= ~HEAP_ENTRY_SETTABLE_FLAGS;
-    InUseEntry->Flags |= ((Flags & HEAP_SETTABLE_USER_FLAGS) >> 4);
-
     /* Properly "zero out" (and fill!) the space */
     if (Flags & HEAP_ZERO_MEMORY)
     {
@@ -2657,6 +2602,10 @@ RtlpGrowBlockInPlace (IN PHEAP Heap,
                       HEAP_TAIL_FILL);
     }
 
+    /* Copy user settable flags */
+    InUseEntry->Flags &= ~HEAP_ENTRY_SETTABLE_FLAGS;
+    InUseEntry->Flags |= ((Flags & HEAP_SETTABLE_USER_FLAGS) >> 4);
+
     /* Return success */
     return TRUE;
 }
@@ -2756,9 +2705,9 @@ RtlReAllocateHeap(HANDLE HeapPtr,
     /* Acquire the lock if necessary */
     if (!(Flags & HEAP_NO_SERIALIZE))
     {
-        RtlEnterHeapLock(Heap->LockVariable);
+        RtlEnterHeapLock(Heap->LockVariable, TRUE);
         HeapLocked = TRUE;
-        Flags ^= HEAP_NO_SERIALIZE;
+        Flags &= ~HEAP_NO_SERIALIZE;
     }
 
     /* Get the pointer to the in-use entry */
@@ -2812,7 +2761,7 @@ RtlReAllocateHeap(HANDLE HeapPtr,
         if (InUseEntry->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
         {
             /* Simple in case of a virtual alloc - just an unused size */
-            InUseEntry->Size = AllocationSize - Size;
+            InUseEntry->Size = (USHORT)((AllocationSize - Size) >> HEAP_ENTRY_SHIFT);
         }
         else if (InUseEntry->Flags & HEAP_ENTRY_EXTRA_PRESENT)
         {
@@ -2824,12 +2773,12 @@ RtlReAllocateHeap(HANDLE HeapPtr,
             // FIXME Tagging, TagIndex
 
             /* Update unused bytes count */
-            InUseEntry->UnusedBytes = AllocationSize - Size;
+            InUseEntry->UnusedBytes = (UCHAR)(AllocationSize - Size);
         }
         else
         {
             // FIXME Tagging, SmallTagIndex
-            InUseEntry->UnusedBytes = AllocationSize - Size;
+            InUseEntry->UnusedBytes = (UCHAR)(AllocationSize - Size);
         }
 
         /* If new size is bigger than the old size */
@@ -2911,22 +2860,19 @@ RtlReAllocateHeap(HANDLE HeapPtr,
 
                 /* Initialize this entry */
                 SplitBlock->Flags = FreeFlags;
-                SplitBlock->PreviousSize = Index;
+                SplitBlock->PreviousSize = (USHORT)Index;
                 SplitBlock->SegmentOffset = InUseEntry->SegmentOffset;
 
                 /* Remember free size */
                 FreeSize = InUseEntry->Size - Index;
 
                 /* Set new size */
-                InUseEntry->Size = Index;
+                InUseEntry->Size = (USHORT)Index;
                 InUseEntry->Flags &= ~HEAP_ENTRY_LAST_ENTRY;
 
                 /* Is that the last entry */
                 if (FreeFlags & HEAP_ENTRY_LAST_ENTRY)
                 {
-                    /* Update segment's last entry */
-                    Heap->Segments[SplitBlock->SegmentOffset]->LastEntryInSegment = (PHEAP_ENTRY)SplitBlock;
-
                     /* Set its size and insert it to the list */
                     SplitBlock->Size = (USHORT)FreeSize;
                     RtlpInsertFreeBlockHelper(Heap, SplitBlock, FreeSize, FALSE);
@@ -2967,16 +2913,12 @@ RtlReAllocateHeap(HANDLE HeapPtr,
 
                         if (FreeSize <= HEAP_MAX_BLOCK_SIZE)
                         {
-                            SplitBlock->Size = FreeSize;
+                            SplitBlock->Size = (USHORT)FreeSize;
 
                             if (!(SplitBlock->Flags & HEAP_ENTRY_LAST_ENTRY))
                             {
                                 /* Update previous size of the next entry */
-                                ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize))->PreviousSize = FreeSize;
-                            }
-                            else
-                            {
-                                Heap->Segments[SplitBlock->SegmentOffset]->LastEntryInSegment = (PHEAP_ENTRY)SplitBlock;
+                                ((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)SplitBlock + FreeSize))->PreviousSize = (USHORT)FreeSize;
                             }
 
                             /* Insert the new one back and update total size */
@@ -3144,7 +3086,7 @@ RtlLockHeap(IN HANDLE HeapPtr)
     /* Lock if it's lockable */
     if (!(Heap->Flags & HEAP_NO_SERIALIZE))
     {
-        RtlEnterHeapLock(Heap->LockVariable);
+        RtlEnterHeapLock(Heap->LockVariable, TRUE);
     }
 
     return TRUE;
@@ -3313,7 +3255,7 @@ RtlpValidateHeapEntry(
         HeapEntry >= Segment->LastValidEntry))
         goto invalid_entry;
 
-    if ((HeapEntry->Flags & HEAP_ENTRY_FILL_PATTERN) && 
+    if ((HeapEntry->Flags & HEAP_ENTRY_FILL_PATTERN) &&
         !RtlpCheckInUsePattern(HeapEntry))
         goto invalid_entry;
 
@@ -3482,7 +3424,7 @@ RtlpValidateHeapSegment(
                 }
                 else
                 {
-                    UnCommittedPages += (UcrDescriptor->Size / PAGE_SIZE);
+                    UnCommittedPages += (ULONG)(UcrDescriptor->Size / PAGE_SIZE);
                     UnCommittedRanges++;
 
                     CurrentEntry = (PHEAP_ENTRY)((PCHAR)UcrDescriptor->Address + UcrDescriptor->Size);
@@ -3707,7 +3649,9 @@ BOOLEAN NTAPI RtlValidateHeap(
     BOOLEAN HeapLocked = FALSE;
     BOOLEAN HeapValid;
 
-    // FIXME Check for special heap
+    /* Check for page heap */
+    if (Heap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS)
+        return RtlpDebugPageHeapValidate(HeapPtr, Flags, Block);
 
     /* Check signature */
     if (Heap->Signature != HEAP_SIGNATURE)
@@ -3722,7 +3666,7 @@ BOOLEAN NTAPI RtlValidateHeap(
     /* Acquire the lock if necessary */
     if (!(Flags & HEAP_NO_SERIALIZE))
     {
-        RtlEnterHeapLock(Heap->LockVariable);
+        RtlEnterHeapLock(Heap->LockVariable, TRUE);
         HeapLocked = TRUE;
     }
 
@@ -3753,7 +3697,7 @@ RtlInitializeHeapManager(VOID)
     Peb->NumberOfHeaps = 0;
 
     /* Initialize the process heaps list protecting lock */
-    RtlInitializeHeapLock(&RtlpProcessHeapsListLock);
+    RtlInitializeCriticalSection(&RtlpProcessHeapsListLock);
 }
 
 
@@ -3818,7 +3762,7 @@ RtlSetUserValueHeap(IN PVOID HeapHandle,
     PHEAP Heap = (PHEAP)HeapHandle;
     PHEAP_ENTRY HeapEntry;
     PHEAP_ENTRY_EXTRA Extra;
-    BOOLEAN HeapLocked = FALSE;
+    BOOLEAN HeapLocked = FALSE, ValueSet = FALSE;
 
     /* Force flags */
     Flags |= Heap->Flags;
@@ -3830,7 +3774,7 @@ RtlSetUserValueHeap(IN PVOID HeapHandle,
     /* Lock if it's lockable */
     if (!(Heap->Flags & HEAP_NO_SERIALIZE))
     {
-        RtlEnterHeapLock(Heap->LockVariable);
+        RtlEnterHeapLock(Heap->LockVariable, TRUE);
         HeapLocked = TRUE;
     }
 
@@ -3855,13 +3799,16 @@ RtlSetUserValueHeap(IN PVOID HeapHandle,
         /* Use extra to store the value */
         Extra = RtlpGetExtraStuffPointer(HeapEntry);
         Extra->Settable = (ULONG_PTR)UserValue;
+
+        /* Indicate that value was set */
+        ValueSet = TRUE;
     }
 
     /* Release the heap lock if it was acquired */
     if (HeapLocked)
         RtlLeaveHeapLock(Heap->LockVariable);
 
-    return TRUE;
+    return ValueSet;
 }
 
 /*
@@ -3889,7 +3836,7 @@ RtlSetUserFlagsHeap(IN PVOID HeapHandle,
     /* Lock if it's lockable */
     if (!(Heap->Flags & HEAP_NO_SERIALIZE))
     {
-        RtlEnterHeapLock(Heap->LockVariable);
+        RtlEnterHeapLock(Heap->LockVariable, TRUE);
         HeapLocked = TRUE;
     }
 
@@ -3945,7 +3892,7 @@ RtlGetUserInfoHeap(IN PVOID HeapHandle,
     /* Lock if it's lockable */
     if (!(Heap->Flags & HEAP_NO_SERIALIZE))
     {
-        RtlEnterHeapLock(Heap->LockVariable);
+        RtlEnterHeapLock(Heap->LockVariable, TRUE);
         HeapLocked = TRUE;
     }