windows-nt/Source/XPSP1/NT/base/wow64/mscpu/compiler/compile.c

383 lines
9.8 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
compile.c
Abstract:
This module contains code to put the fragments into the translation
cache.
Author:
Dave Hastings (daveh) creation-date 27-Jun-1995
Revision History:
Dave Hastings (daveh) 16-Jan-1996
Move operand handling into fragment library
Notes:
We don't yet have any code to handle processor errata
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#define _WX86CPUAPI_
#include <wx86.h>
#include <wx86nt.h>
#include <wx86cpu.h>
#include <cpuassrt.h>
#include <config.h>
#include <instr.h>
#include <threadst.h>
#include <frag.h>
#include <analysis.h>
#include <entrypt.h>
#include <compilep.h>
#include <compiler.h>
#include <tc.h>
#include <mrsw.h>
#include <stdio.h>
#include <stdlib.h>
ASSERTNAME;
#if _ALPHA_
#define MAX_RISC_COUNT 32768
#else
#define MAX_RISC_COUNT 16384
#endif
DWORD TranslationCacheFlags; // indicates what kind of code is in the TC
#ifdef CODEGEN_PROFILE
DWORD EPSequence;
#endif
//
// This is guaranteed only to be accessed by a single thread at a time.
//
INSTRUCTION InstructionStream[MAX_INSTR_COUNT];
ULONG NumberOfInstructions;
PENTRYPOINT
CreateEntryPoints(
PENTRYPOINT ContainingEntrypoint,
PBYTE EntryPointMemory
)
/*++
Routine Description:
This function takes the InstructionStream and creates entrypoints
from the information computed by LocateEntrypoints().
Entrypoints are then added into the Red/Black tree.
Arguments:
ContainingEntrypoint -- entrypoint which describes this range of intel
code already
EntryPointMemory -- pre-allocated Entrypoint memory
Return Value:
The Entry Point corresponding to the first instruction
--*/
{
ULONG i, j, intelDest;
PEPNODE EP;
PENTRYPOINT EntryPoint;
PENTRYPOINT PrevEntryPoint;
#ifdef CODEGEN_PROFILE
ULONG CreateTime;
CreateTime = GetCurrentTime();
EPSequence++;
#endif
//
// Performance is O(n) always.
//
i=0;
PrevEntryPoint = InstructionStream[0].EntryPoint;
while (i<NumberOfInstructions) {
//
// This loop skips from entrypoint to entrypoint.
//
CPUASSERT(i == 0 || InstructionStream[i-1].EntryPoint != PrevEntryPoint);
//
// Get an entrypoint node from the EntryPointMemory allocated by
// our caller.
//
if (ContainingEntrypoint) {
EntryPoint = (PENTRYPOINT)EntryPointMemory;
EntryPointMemory+=sizeof(ENTRYPOINT);
} else {
EP = (PEPNODE)EntryPointMemory;
EntryPoint = &EP->ep;
EntryPointMemory+=sizeof(EPNODE);
}
//
// Find the next entrypoint and the RISC address of the next
// instruction which begins an entrypoint. Each instruction
// in that range contains a pointer to the containing Entrypoint.
//
for (j=i+1; j<NumberOfInstructions; ++j) {
if (InstructionStream[j].EntryPoint != PrevEntryPoint) {
PrevEntryPoint = InstructionStream[j].EntryPoint;
break;
}
InstructionStream[j].EntryPoint = EntryPoint;
}
//
// Fill in the Entrypoint structure
//
#ifdef CODEGEN_PROFILE
EntryPoint->SequenceNumber = EPSequence;
EntryPoint->CreationTime = CreateTime;
#endif
EntryPoint->intelStart = (PVOID)InstructionStream[i].IntelAddress;
if (j < NumberOfInstructions) {
EntryPoint->intelEnd = (PVOID)(InstructionStream[j].IntelAddress-1);
} else {
ULONG Prev;
for (Prev=j-1; InstructionStream[Prev].Size == 0; Prev--)
;
EntryPoint->intelEnd = (PVOID)(InstructionStream[Prev].IntelAddress +
InstructionStream[Prev].Size - 1);
}
InstructionStream[i].EntryPoint = EntryPoint;
if (ContainingEntrypoint) {
//
// Link this sub-entrypoint into the containing entrypoint
//
EntryPoint->SubEP = ContainingEntrypoint->SubEP;
ContainingEntrypoint->SubEP = EntryPoint;
} else {
INT RetVal;
//
// Insert it into the EP tree
//
EntryPoint->SubEP = NULL;
RetVal = insertEntryPoint(EP);
CPUASSERT(RetVal==1);
}
//
// Advance to the next instruction which contains an
// Entrypoint.
//
i=j;
}
if (ContainingEntrypoint) {
// Indicate that the Entrypoints are present
EntrypointTimestamp++;
}
return InstructionStream[0].EntryPoint;
}
PENTRYPOINT
Compile(
PENTRYPOINT ContainingEntrypoint,
PVOID Eip
)
/*++
Routine Description:
This function puts together code fragments to execute the Intel
code stream at Eip. It gets a stream of pre-decoded instructions
from the code analysis module.
Arguments:
ContaingingEntrypoint -- If NULL, there is no entrypoint which already
describes the Intel address to be compiled.
Otherwise, this entrypoint describes the
Intel address. The caller ensures that the
Entrypoint->intelStart != Eip.
Eip -- Supplies the location to compile from
Return Value:
pointer to the entrypoint for the compiled code
--*/
{
ULONG NativeSize, InstructionSize, IntelSize, OperationSize;
PCHAR CodeLocation, CurrentCodeLocation;
ULONG i;
PENTRYPOINT Entrypoint;
INT RetVal;
PVOID StopEip;
DWORD cEntryPoints;
PBYTE EntryPointMemory;
DWORD EPSize;
#if defined(_ALPHA_)
ULONG ECUSize, ECUOffset;
#endif
#if DBG
DWORD OldEPTimestamp;
#endif
DECLARE_CPU;
if (ContainingEntrypoint) {
//
// See if the entrypoint exactly describes the x86 address
//
if (ContainingEntrypoint->intelStart == Eip) {
return ContainingEntrypoint;
}
//
// No need to compile past the end of the current entrypoint
//
StopEip = ContainingEntrypoint->intelEnd;
//
// Assert that the ContainingEntrypoint is actually an EPNODE.
//
CPUASSERTMSG( ((PEPNODE)ContainingEntrypoint)->intelColor == RED ||
((PEPNODE)ContainingEntrypoint)->intelColor == BLACK,
"ContainingEntrypoint is not an EPNODE!");
} else {
//
// Find out if there is a compiled block following this one
//
Entrypoint = GetNextEPFromIntelAddr(Eip);
if (Entrypoint == NULL) {
StopEip = (PVOID)0xffffffff;
} else {
StopEip = Entrypoint->intelStart;
}
}
//
// Get the stream of instructions to compile.
// If the Trap Flag is set, then compile only one instruction
//
if (cpu->flag_tf) {
NumberOfInstructions = 1;
} else {
NumberOfInstructions = CpuInstructionLookahead;
}
cEntryPoints = GetInstructionStream(InstructionStream,
&NumberOfInstructions,
Eip,
StopEip
);
//
// Pre-allocate enough space from the Translation Cache to store
// the compiled code.
//
CodeLocation = AllocateTranslationCache(MAX_RISC_COUNT);
//
// Allocate memory for all of the Entrypoints. This must be done
// after the Translation Cache allocation, in case that allocation
// caused a cache flush.
//
if (ContainingEntrypoint) {
EPSize = cEntryPoints * sizeof(ENTRYPOINT);
} else {
EPSize = cEntryPoints * sizeof(EPNODE);
}
EntryPointMemory = (PBYTE)EPAlloc(EPSize);
if (!EntryPointMemory) {
//
// Either failed to commit extra pages of memory to grow Entrypoint
// memory, or there are so many entrypoints that the the reserved
// size has been exceeded. Flush the Translation Cache, which will
// free up memory, then try the allocation again.
//
FlushTranslationCache(0, 0xffffffff);
EntryPointMemory = (PBYTE)EPAlloc(EPSize);
if (!EntryPointMemory) {
//
// We've tried our hardest, but there simply isn't any
// memory available. Time to give up.
//
RtlRaiseStatus(STATUS_NO_MEMORY);
}
//
// Now that the cache has been flushed, CodeLocation is invalid.
// re-allocate from the Translation Cache. We know that
// the cache was just flushed, so it is impossible for the cache
// to flush again, which would invalidate EntryPointMemory.
//
#if DBG
OldEPTimestamp = EntrypointTimestamp;
#endif
CodeLocation = AllocateTranslationCache(MAX_RISC_COUNT);
CPUASSERTMSG(EntrypointTimestamp == OldEPTimestamp,
"Unexpected Translation Cache flush!");
}
//
// Fill in the IntelStart, IntelEnd, and update
// InstructionStream[]->EntryPoint
//
CreateEntryPoints(ContainingEntrypoint, EntryPointMemory);
//
// Generate RISC code from the x86 code
//
NativeSize = PlaceInstructions(CodeLocation, cEntryPoints);
//
// Give back the unused part of the Translation Cache
//
FreeUnusedTranslationCache(CodeLocation + NativeSize);
//
// Flush the information to the instruction cache
//
NtFlushInstructionCache(NtCurrentProcess(), CodeLocation, NativeSize);
//
// Update the flags indicating what kind of code is in the TC
//
TranslationCacheFlags |= CompilerFlags;
return (PENTRYPOINT)EntryPointMemory;
}