Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

382 lines
10 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. compile.c
  5. Abstract:
  6. This module contains code to put the fragments into the translation
  7. cache.
  8. Author:
  9. Dave Hastings (daveh) creation-date 27-Jun-1995
  10. Revision History:
  11. Dave Hastings (daveh) 16-Jan-1996
  12. Move operand handling into fragment library
  13. Notes:
  14. We don't yet have any code to handle processor errata
  15. --*/
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <windows.h>
  20. #define _WX86CPUAPI_
  21. #include <wx86.h>
  22. #include <wx86nt.h>
  23. #include <wx86cpu.h>
  24. #include <cpuassrt.h>
  25. #include <config.h>
  26. #include <instr.h>
  27. #include <threadst.h>
  28. #include <frag.h>
  29. #include <analysis.h>
  30. #include <entrypt.h>
  31. #include <compilep.h>
  32. #include <compiler.h>
  33. #include <tc.h>
  34. #include <mrsw.h>
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37. ASSERTNAME;
  38. #if _ALPHA_
  39. #define MAX_RISC_COUNT 32768
  40. #else
  41. #define MAX_RISC_COUNT 16384
  42. #endif
  43. DWORD TranslationCacheFlags; // indicates what kind of code is in the TC
  44. #ifdef CODEGEN_PROFILE
  45. DWORD EPSequence;
  46. #endif
  47. //
  48. // This is guaranteed only to be accessed by a single thread at a time.
  49. //
  50. INSTRUCTION InstructionStream[MAX_INSTR_COUNT];
  51. ULONG NumberOfInstructions;
  52. PENTRYPOINT
  53. CreateEntryPoints(
  54. PENTRYPOINT ContainingEntrypoint,
  55. PBYTE EntryPointMemory
  56. )
  57. /*++
  58. Routine Description:
  59. This function takes the InstructionStream and creates entrypoints
  60. from the information computed by LocateEntrypoints().
  61. Entrypoints are then added into the Red/Black tree.
  62. Arguments:
  63. ContainingEntrypoint -- entrypoint which describes this range of intel
  64. code already
  65. EntryPointMemory -- pre-allocated Entrypoint memory
  66. Return Value:
  67. The Entry Point corresponding to the first instruction
  68. --*/
  69. {
  70. ULONG i, j, intelDest;
  71. PEPNODE EP;
  72. PENTRYPOINT EntryPoint;
  73. PENTRYPOINT PrevEntryPoint;
  74. #ifdef CODEGEN_PROFILE
  75. ULONG CreateTime;
  76. CreateTime = GetCurrentTime();
  77. EPSequence++;
  78. #endif
  79. //
  80. // Performance is O(n) always.
  81. //
  82. i=0;
  83. PrevEntryPoint = InstructionStream[0].EntryPoint;
  84. while (i<NumberOfInstructions) {
  85. //
  86. // This loop skips from entrypoint to entrypoint.
  87. //
  88. CPUASSERT(i == 0 || InstructionStream[i-1].EntryPoint != PrevEntryPoint);
  89. //
  90. // Get an entrypoint node from the EntryPointMemory allocated by
  91. // our caller.
  92. //
  93. if (ContainingEntrypoint) {
  94. EntryPoint = (PENTRYPOINT)EntryPointMemory;
  95. EntryPointMemory+=sizeof(ENTRYPOINT);
  96. } else {
  97. EP = (PEPNODE)EntryPointMemory;
  98. EntryPoint = &EP->ep;
  99. EntryPointMemory+=sizeof(EPNODE);
  100. }
  101. //
  102. // Find the next entrypoint and the RISC address of the next
  103. // instruction which begins an entrypoint. Each instruction
  104. // in that range contains a pointer to the containing Entrypoint.
  105. //
  106. for (j=i+1; j<NumberOfInstructions; ++j) {
  107. if (InstructionStream[j].EntryPoint != PrevEntryPoint) {
  108. PrevEntryPoint = InstructionStream[j].EntryPoint;
  109. break;
  110. }
  111. InstructionStream[j].EntryPoint = EntryPoint;
  112. }
  113. //
  114. // Fill in the Entrypoint structure
  115. //
  116. #ifdef CODEGEN_PROFILE
  117. EntryPoint->SequenceNumber = EPSequence;
  118. EntryPoint->CreationTime = CreateTime;
  119. #endif
  120. EntryPoint->intelStart = (PVOID)InstructionStream[i].IntelAddress;
  121. if (j < NumberOfInstructions) {
  122. EntryPoint->intelEnd = (PVOID)(InstructionStream[j].IntelAddress-1);
  123. } else {
  124. ULONG Prev;
  125. for (Prev=j-1; InstructionStream[Prev].Size == 0; Prev--)
  126. ;
  127. EntryPoint->intelEnd = (PVOID)(InstructionStream[Prev].IntelAddress +
  128. InstructionStream[Prev].Size - 1);
  129. }
  130. InstructionStream[i].EntryPoint = EntryPoint;
  131. if (ContainingEntrypoint) {
  132. //
  133. // Link this sub-entrypoint into the containing entrypoint
  134. //
  135. EntryPoint->SubEP = ContainingEntrypoint->SubEP;
  136. ContainingEntrypoint->SubEP = EntryPoint;
  137. } else {
  138. INT RetVal;
  139. //
  140. // Insert it into the EP tree
  141. //
  142. EntryPoint->SubEP = NULL;
  143. RetVal = insertEntryPoint(EP);
  144. CPUASSERT(RetVal==1);
  145. }
  146. //
  147. // Advance to the next instruction which contains an
  148. // Entrypoint.
  149. //
  150. i=j;
  151. }
  152. if (ContainingEntrypoint) {
  153. // Indicate that the Entrypoints are present
  154. EntrypointTimestamp++;
  155. }
  156. return InstructionStream[0].EntryPoint;
  157. }
  158. PENTRYPOINT
  159. Compile(
  160. PENTRYPOINT ContainingEntrypoint,
  161. PVOID Eip
  162. )
  163. /*++
  164. Routine Description:
  165. This function puts together code fragments to execute the Intel
  166. code stream at Eip. It gets a stream of pre-decoded instructions
  167. from the code analysis module.
  168. Arguments:
  169. ContaingingEntrypoint -- If NULL, there is no entrypoint which already
  170. describes the Intel address to be compiled.
  171. Otherwise, this entrypoint describes the
  172. Intel address. The caller ensures that the
  173. Entrypoint->intelStart != Eip.
  174. Eip -- Supplies the location to compile from
  175. Return Value:
  176. pointer to the entrypoint for the compiled code
  177. --*/
  178. {
  179. ULONG NativeSize, InstructionSize, IntelSize, OperationSize;
  180. PCHAR CodeLocation, CurrentCodeLocation;
  181. ULONG i;
  182. PENTRYPOINT Entrypoint;
  183. INT RetVal;
  184. PVOID StopEip;
  185. DWORD cEntryPoints;
  186. PBYTE EntryPointMemory;
  187. DWORD EPSize;
  188. #if defined(_ALPHA_)
  189. ULONG ECUSize, ECUOffset;
  190. #endif
  191. #if DBG
  192. DWORD OldEPTimestamp;
  193. #endif
  194. DECLARE_CPU;
  195. if (ContainingEntrypoint) {
  196. //
  197. // See if the entrypoint exactly describes the x86 address
  198. //
  199. if (ContainingEntrypoint->intelStart == Eip) {
  200. return ContainingEntrypoint;
  201. }
  202. //
  203. // No need to compile past the end of the current entrypoint
  204. //
  205. StopEip = ContainingEntrypoint->intelEnd;
  206. //
  207. // Assert that the ContainingEntrypoint is actually an EPNODE.
  208. //
  209. CPUASSERTMSG( ((PEPNODE)ContainingEntrypoint)->intelColor == RED ||
  210. ((PEPNODE)ContainingEntrypoint)->intelColor == BLACK,
  211. "ContainingEntrypoint is not an EPNODE!");
  212. } else {
  213. //
  214. // Find out if there is a compiled block following this one
  215. //
  216. Entrypoint = GetNextEPFromIntelAddr(Eip);
  217. if (Entrypoint == NULL) {
  218. StopEip = (PVOID)0xffffffff;
  219. } else {
  220. StopEip = Entrypoint->intelStart;
  221. }
  222. }
  223. //
  224. // Get the stream of instructions to compile.
  225. // If the Trap Flag is set, then compile only one instruction
  226. //
  227. if (cpu->flag_tf) {
  228. NumberOfInstructions = 1;
  229. } else {
  230. NumberOfInstructions = CpuInstructionLookahead;
  231. }
  232. cEntryPoints = GetInstructionStream(InstructionStream,
  233. &NumberOfInstructions,
  234. Eip,
  235. StopEip
  236. );
  237. //
  238. // Pre-allocate enough space from the Translation Cache to store
  239. // the compiled code.
  240. //
  241. CodeLocation = AllocateTranslationCache(MAX_RISC_COUNT);
  242. //
  243. // Allocate memory for all of the Entrypoints. This must be done
  244. // after the Translation Cache allocation, in case that allocation
  245. // caused a cache flush.
  246. //
  247. if (ContainingEntrypoint) {
  248. EPSize = cEntryPoints * sizeof(ENTRYPOINT);
  249. } else {
  250. EPSize = cEntryPoints * sizeof(EPNODE);
  251. }
  252. EntryPointMemory = (PBYTE)EPAlloc(EPSize);
  253. if (!EntryPointMemory) {
  254. //
  255. // Either failed to commit extra pages of memory to grow Entrypoint
  256. // memory, or there are so many entrypoints that the the reserved
  257. // size has been exceeded. Flush the Translation Cache, which will
  258. // free up memory, then try the allocation again.
  259. //
  260. FlushTranslationCache(0, 0xffffffff);
  261. EntryPointMemory = (PBYTE)EPAlloc(EPSize);
  262. if (!EntryPointMemory) {
  263. //
  264. // We've tried our hardest, but there simply isn't any
  265. // memory available. Time to give up.
  266. //
  267. RtlRaiseStatus(STATUS_NO_MEMORY);
  268. }
  269. //
  270. // Now that the cache has been flushed, CodeLocation is invalid.
  271. // re-allocate from the Translation Cache. We know that
  272. // the cache was just flushed, so it is impossible for the cache
  273. // to flush again, which would invalidate EntryPointMemory.
  274. //
  275. #if DBG
  276. OldEPTimestamp = EntrypointTimestamp;
  277. #endif
  278. CodeLocation = AllocateTranslationCache(MAX_RISC_COUNT);
  279. CPUASSERTMSG(EntrypointTimestamp == OldEPTimestamp,
  280. "Unexpected Translation Cache flush!");
  281. }
  282. //
  283. // Fill in the IntelStart, IntelEnd, and update
  284. // InstructionStream[]->EntryPoint
  285. //
  286. CreateEntryPoints(ContainingEntrypoint, EntryPointMemory);
  287. //
  288. // Generate RISC code from the x86 code
  289. //
  290. NativeSize = PlaceInstructions(CodeLocation, cEntryPoints);
  291. //
  292. // Give back the unused part of the Translation Cache
  293. //
  294. FreeUnusedTranslationCache(CodeLocation + NativeSize);
  295. //
  296. // Flush the information to the instruction cache
  297. //
  298. NtFlushInstructionCache(NtCurrentProcess(), CodeLocation, NativeSize);
  299. //
  300. // Update the flags indicating what kind of code is in the TC
  301. //
  302. TranslationCacheFlags |= CompilerFlags;
  303. return (PENTRYPOINT)EntryPointMemory;
  304. }