SysInfo.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "CommonCorePch.h"
  6. #ifdef _WIN32
  7. #include <psapi.h>
  8. #endif
  9. #include <wincrypt.h>
  10. #include <VersionHelpers.h>
  11. #ifdef __APPLE__
  12. #include <sys/sysctl.h> // sysctl*
  13. #elif defined(__linux__)
  14. #include <unistd.h> // sysconf
  15. #endif
  16. // Initialization order
  17. // AB AutoSystemInfo
  18. // AD PerfCounter
  19. // AE PerfCounterSet
  20. // AM Output/Configuration
  21. // AN MemProtectHeap
  22. // AP DbgHelpSymbolManager
  23. // AQ CFGLogger
  24. // AR LeakReport
  25. // AS JavascriptDispatch/RecyclerObjectDumper
  26. // AT HeapAllocator/RecyclerHeuristic
  27. // AU RecyclerWriteBarrierManager
  28. #pragma warning(disable:4075) // initializers put in unrecognized initialization area on purpose
  29. #pragma init_seg(".CRT$XCAB")
  30. #if SYSINFO_IMAGE_BASE_AVAILABLE
  31. EXTERN_C IMAGE_DOS_HEADER __ImageBase;
  32. #endif
  33. AutoSystemInfo AutoSystemInfo::Data INIT_PRIORITY(300);
  34. #if DBG
  35. bool
  36. AutoSystemInfo::IsInitialized()
  37. {
  38. return AutoSystemInfo::Data.initialized;
  39. }
  40. #endif
  41. bool
  42. AutoSystemInfo::ShouldQCMoreFrequently()
  43. {
  44. return Data.shouldQCMoreFrequently;
  45. }
  46. bool
  47. AutoSystemInfo::SupportsOnlyMultiThreadedCOM()
  48. {
  49. return Data.supportsOnlyMultiThreadedCOM;
  50. }
  51. bool
  52. AutoSystemInfo::IsLowMemoryDevice()
  53. {
  54. return Data.isLowMemoryDevice;
  55. }
  56. void
  57. AutoSystemInfo::Initialize()
  58. {
  59. Assert(!initialized);
  60. #ifndef _WIN32
  61. PAL_InitializeDLL();
  62. majorVersion = CHAKRA_CORE_MAJOR_VERSION;
  63. minorVersion = CHAKRA_CORE_MINOR_VERSION;
  64. #endif
  65. processHandle = GetCurrentProcess();
  66. GetSystemInfo(this);
  67. // Make the page size constant so calculation are faster.
  68. Assert(this->dwPageSize == AutoSystemInfo::PageSize);
  69. #if defined(_M_IX86) || defined(_M_X64)
  70. get_cpuid(CPUInfo, 1);
  71. isAtom = CheckForAtom();
  72. #endif
  73. #if defined(_M_ARM32_OR_ARM64)
  74. armDivAvailable = IsProcessorFeaturePresent(PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE) ? true : false;
  75. #endif
  76. allocationGranularityPageCount = dwAllocationGranularity / dwPageSize;
  77. isWindows8OrGreater = IsWindows8OrGreater();
  78. binaryName[0] = _u('\0');
  79. #if SYSINFO_IMAGE_BASE_AVAILABLE
  80. dllLoadAddress = (UINT_PTR)&__ImageBase;
  81. dllHighAddress = (UINT_PTR)&__ImageBase +
  82. ((PIMAGE_NT_HEADERS)(((char *)&__ImageBase) + __ImageBase.e_lfanew))->OptionalHeader.SizeOfImage;
  83. #endif
  84. InitPhysicalProcessorCount();
  85. #if DBG
  86. initialized = true;
  87. #endif
  88. WCHAR DisableDebugScopeCaptureFlag[MAX_PATH];
  89. if (::GetEnvironmentVariable(_u("JS_DEBUG_SCOPE"), DisableDebugScopeCaptureFlag, _countof(DisableDebugScopeCaptureFlag)) != 0)
  90. {
  91. disableDebugScopeCapture = true;
  92. }
  93. else
  94. {
  95. disableDebugScopeCapture = false;
  96. }
  97. this->shouldQCMoreFrequently = false;
  98. this->supportsOnlyMultiThreadedCOM = false;
  99. this->isLowMemoryDevice = false;
  100. // 0 indicates we haven't retrieved the available commit. We get it lazily.
  101. this->availableCommit = 0;
  102. ChakraBinaryAutoSystemInfoInit(this);
  103. }
  104. bool
  105. AutoSystemInfo::InitPhysicalProcessorCount()
  106. {
  107. DWORD countPhysicalProcessor = 0;
  108. #ifdef _WIN32
  109. DWORD size = 0;
  110. PSYSTEM_LOGICAL_PROCESSOR_INFORMATION pBufferCurrent;
  111. PSYSTEM_LOGICAL_PROCESSOR_INFORMATION pBufferStart;
  112. BOOL bResult;
  113. #endif // _WIN32
  114. Assert(!this->initialized);
  115. // Initialize physical processor to number of logical processors.
  116. // If anything below fails, we still need an approximate value
  117. this->dwNumberOfPhysicalProcessors = this->dwNumberOfProcessors;
  118. #if defined(_WIN32)
  119. bResult = GetLogicalProcessorInformation(NULL, &size);
  120. if (bResult || GetLastError() != ERROR_INSUFFICIENT_BUFFER || !size)
  121. {
  122. return false;
  123. }
  124. DWORD count = (size) / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
  125. if (size != count * sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION))
  126. {
  127. Assert(false);
  128. return false;
  129. }
  130. pBufferCurrent = pBufferStart = NoCheckHeapNewArray(SYSTEM_LOGICAL_PROCESSOR_INFORMATION, (size_t)count);
  131. if (!pBufferCurrent)
  132. {
  133. return false;
  134. }
  135. bResult = GetLogicalProcessorInformation(pBufferCurrent, &size);
  136. if (!bResult)
  137. {
  138. return false;
  139. }
  140. while (pBufferCurrent < (pBufferStart + count))
  141. {
  142. if (pBufferCurrent->Relationship == RelationProcessorCore)
  143. {
  144. countPhysicalProcessor++;
  145. }
  146. pBufferCurrent++;
  147. }
  148. NoCheckHeapDeleteArray(count, pBufferStart);
  149. #elif defined(__APPLE__)
  150. std::size_t szCount = sizeof(countPhysicalProcessor);
  151. sysctlbyname("hw.physicalcpu", &countPhysicalProcessor, &szCount, nullptr, 0);
  152. if (countPhysicalProcessor < 1)
  153. {
  154. int nMIB[2] = {CTL_HW, HW_NCPU}; // fallback. Depracated on latest OS
  155. sysctl(nMIB, 2, &countPhysicalProcessor, &szCount, nullptr, 0);
  156. if (countPhysicalProcessor < 1)
  157. {
  158. countPhysicalProcessor = 1;
  159. }
  160. }
  161. #elif defined(__linux__)
  162. countPhysicalProcessor = sysconf(_SC_NPROCESSORS_ONLN);
  163. #else
  164. // implementation for __linux__ should work for some others.
  165. // same applies to __APPLE__ implementation
  166. // instead of reimplementing, add corresponding preprocessors above
  167. #error "NOT Implemented"
  168. #endif
  169. this->dwNumberOfPhysicalProcessors = countPhysicalProcessor;
  170. return true;
  171. }
  172. #if SYSINFO_IMAGE_BASE_AVAILABLE
  173. bool
  174. AutoSystemInfo::IsJscriptModulePointer(void * ptr)
  175. {
  176. return ((UINT_PTR)ptr >= Data.dllLoadAddress && (UINT_PTR)ptr < Data.dllHighAddress);
  177. }
  178. UINT_PTR
  179. AutoSystemInfo::GetChakraBaseAddr() const
  180. {
  181. return dllLoadAddress;
  182. }
  183. #endif
  184. uint
  185. AutoSystemInfo::GetAllocationGranularityPageCount() const
  186. {
  187. Assert(initialized);
  188. return this->allocationGranularityPageCount;
  189. }
  190. uint
  191. AutoSystemInfo::GetAllocationGranularityPageSize() const
  192. {
  193. Assert(initialized);
  194. return this->allocationGranularityPageCount * PageSize;
  195. }
  196. #if defined(_M_IX86) || defined(_M_X64)
  197. bool
  198. AutoSystemInfo::VirtualSseAvailable(const int sseLevel) const
  199. {
  200. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  201. return CONFIG_FLAG(Sse) < 0 || CONFIG_FLAG(Sse) >= sseLevel;
  202. #else
  203. return true;
  204. #endif
  205. }
  206. #endif
  207. BOOL
  208. AutoSystemInfo::SSE2Available() const
  209. {
  210. Assert(initialized);
  211. #if defined(_M_X64) || defined(_M_ARM32_OR_ARM64)
  212. return true;
  213. #elif defined(_M_IX86)
  214. #if defined(_WIN32)
  215. return VirtualSseAvailable(2) && (CPUInfo[3] & (1 << 26));
  216. #else
  217. return false; // TODO: xplat support
  218. #endif
  219. #else
  220. return false;
  221. #endif
  222. }
  223. #if defined(_M_IX86) || defined(_M_X64)
  224. BOOL
  225. AutoSystemInfo::SSE3Available() const
  226. {
  227. Assert(initialized);
  228. return VirtualSseAvailable(3) && (CPUInfo[2] & 0x1);
  229. }
  230. BOOL
  231. AutoSystemInfo::SSE4_1Available() const
  232. {
  233. Assert(initialized);
  234. return VirtualSseAvailable(4) && (CPUInfo[2] & (0x1 << 19));
  235. }
  236. BOOL
  237. AutoSystemInfo::SSE4_2Available() const
  238. {
  239. Assert(initialized);
  240. return VirtualSseAvailable(4) && (CPUInfo[2] & (0x1 << 20));
  241. }
  242. BOOL
  243. AutoSystemInfo::PopCntAvailable() const
  244. {
  245. Assert(initialized);
  246. return VirtualSseAvailable(4) && (CPUInfo[2] & (1 << 23));
  247. }
  248. BOOL
  249. AutoSystemInfo::LZCntAvailable() const
  250. {
  251. Assert(initialized);
  252. int CPUInfo[4];
  253. get_cpuid(CPUInfo, 0x80000001);
  254. return VirtualSseAvailable(4) && (CPUInfo[2] & (1 << 5));
  255. }
  256. BOOL
  257. AutoSystemInfo::TZCntAvailable() const
  258. {
  259. Assert(initialized);
  260. int CPUInfo[4];
  261. get_cpuid(CPUInfo, 7);
  262. return VirtualSseAvailable(4) && (CPUInfo[1] & (1 << 3));
  263. }
  264. bool
  265. AutoSystemInfo::IsAtomPlatform() const
  266. {
  267. return isAtom;
  268. }
  269. bool
  270. AutoSystemInfo::CheckForAtom() const
  271. {
  272. int CPUInfo[4];
  273. const int GENUINE_INTEL_0 = 0x756e6547,
  274. GENUINE_INTEL_1 = 0x49656e69,
  275. GENUINE_INTEL_2 = 0x6c65746e;
  276. const int PLATFORM_MASK = 0x0fff3ff0;
  277. const int ATOM_PLATFORM_A = 0x0106c0, /* bonnell - extended model 1c, type 0, family code 6 */
  278. ATOM_PLATFORM_B = 0x020660, /* lincroft - extended model 26, type 0, family code 6 */
  279. ATOM_PLATFORM_C = 0x020670, /* saltwell - extended model 27, type 0, family code 6 */
  280. ATOM_PLATFORM_D = 0x030650, /* tbd - extended model 35, type 0, family code 6 */
  281. ATOM_PLATFORM_E = 0x030660, /* tbd - extended model 36, type 0, family code 6 */
  282. ATOM_PLATFORM_F = 0x030670; /* tbd - extended model 37, type 0, family code 6 */
  283. int platformSignature;
  284. get_cpuid(CPUInfo, 0);
  285. // See if CPU is ATOM HW. First check if CPU is genuine Intel.
  286. if( CPUInfo[1]==GENUINE_INTEL_0 &&
  287. CPUInfo[3]==GENUINE_INTEL_1 &&
  288. CPUInfo[2]==GENUINE_INTEL_2)
  289. {
  290. get_cpuid(CPUInfo, 1);
  291. // get platform signature
  292. platformSignature = CPUInfo[0];
  293. if((( PLATFORM_MASK & platformSignature) == ATOM_PLATFORM_A) ||
  294. ((PLATFORM_MASK & platformSignature) == ATOM_PLATFORM_B) ||
  295. ((PLATFORM_MASK & platformSignature) == ATOM_PLATFORM_C) ||
  296. ((PLATFORM_MASK & platformSignature) == ATOM_PLATFORM_D) ||
  297. ((PLATFORM_MASK & platformSignature) == ATOM_PLATFORM_E) ||
  298. ((PLATFORM_MASK & platformSignature) == ATOM_PLATFORM_F))
  299. {
  300. return true;
  301. }
  302. }
  303. return false;
  304. }
  305. #endif
  306. bool
  307. AutoSystemInfo::IsCFGEnabled()
  308. {
  309. #if defined(_CONTROL_FLOW_GUARD)
  310. return true
  311. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  312. && IsWinThresholdOrLater() && !PHASE_OFF1(Js::CFGPhase)
  313. #endif //ENABLE_DEBUG_CONFIG_OPTIONS
  314. ;
  315. #else
  316. return false;
  317. #endif //_CONTROL_FLOW_GUARD
  318. }
  319. bool
  320. AutoSystemInfo::IsWin8OrLater()
  321. {
  322. return isWindows8OrGreater;
  323. }
  324. #if defined(_CONTROL_FLOW_GUARD)
  325. bool
  326. AutoSystemInfo::IsWinThresholdOrLater()
  327. {
  328. return IsWindowsThresholdOrGreater();
  329. }
  330. #endif
  331. DWORD AutoSystemInfo::SaveModuleFileName(HANDLE hMod)
  332. {
  333. return ::GetModuleFileNameW((HMODULE)hMod, Data.binaryName, MAX_PATH);
  334. }
  335. LPCWSTR AutoSystemInfo::GetJscriptDllFileName()
  336. {
  337. return (LPCWSTR)Data.binaryName;
  338. }
  339. bool AutoSystemInfo::IsLowMemoryProcess()
  340. {
  341. ULONG64 commit = ULONG64(-1);
  342. this->GetAvailableCommit(&commit);
  343. return commit <= CONFIG_FLAG(LowMemoryCap);
  344. }
  345. BOOL AutoSystemInfo::GetAvailableCommit(ULONG64 *pCommit)
  346. {
  347. Assert(initialized);
  348. // Non-zero value indicates we've been here before.
  349. if (this->availableCommit == 0)
  350. {
  351. return false;
  352. }
  353. *pCommit = this->availableCommit;
  354. return true;
  355. }
  356. void AutoSystemInfo::SetAvailableCommit(ULONG64 commit)
  357. {
  358. ::InterlockedCompareExchange64((volatile LONG64 *)&this->availableCommit, commit, 0);
  359. }
  360. //
  361. // Returns the major and minor version of the loaded binary. If the version info has been fetched once, it will be cached
  362. // and returned without any system calls to find the version number.
  363. //
  364. HRESULT AutoSystemInfo::GetJscriptFileVersion(DWORD* majorVersion, DWORD* minorVersion, DWORD *buildDateHash, DWORD *buildTimeHash)
  365. {
  366. HRESULT hr = E_FAIL;
  367. if(AutoSystemInfo::Data.majorVersion == 0 && AutoSystemInfo::Data.minorVersion == 0)
  368. {
  369. // uninitialized state - call the system API to get the version info.
  370. LPCWSTR jscriptDllName = GetJscriptDllFileName();
  371. hr = GetVersionInfo(jscriptDllName, majorVersion, minorVersion);
  372. AutoSystemInfo::Data.majorVersion = *majorVersion;
  373. AutoSystemInfo::Data.minorVersion = *minorVersion;
  374. }
  375. else if(AutoSystemInfo::Data.majorVersion != INVALID_VERSION)
  376. {
  377. // if the cached copy is valid, use it and return S_OK.
  378. *majorVersion = AutoSystemInfo::Data.majorVersion;
  379. *minorVersion = AutoSystemInfo::Data.minorVersion;
  380. hr = S_OK;
  381. }
  382. if (buildDateHash)
  383. {
  384. *buildDateHash = AutoSystemInfo::Data.buildDateHash;
  385. }
  386. if (buildTimeHash)
  387. {
  388. *buildTimeHash = AutoSystemInfo::Data.buildTimeHash;
  389. }
  390. return hr;
  391. }
  392. //
  393. // Returns the major and minor version of the binary passed as argument.
  394. //
  395. HRESULT AutoSystemInfo::GetVersionInfo(__in LPCWSTR pszPath, DWORD* majorVersion, DWORD* minorVersion)
  396. {
  397. #ifdef _WIN32
  398. DWORD dwTemp;
  399. DWORD cbVersionSz;
  400. HRESULT hr = E_FAIL;
  401. BYTE* pVerBuffer = NULL;
  402. VS_FIXEDFILEINFO* pFileInfo = NULL;
  403. cbVersionSz = GetFileVersionInfoSizeEx(FILE_VER_GET_LOCALISED, pszPath, &dwTemp);
  404. if(cbVersionSz > 0)
  405. {
  406. pVerBuffer = NoCheckHeapNewArray(BYTE, cbVersionSz);
  407. if(pVerBuffer)
  408. {
  409. if(GetFileVersionInfoEx(FILE_VER_GET_LOCALISED|FILE_VER_GET_NEUTRAL, pszPath, 0, cbVersionSz, pVerBuffer))
  410. {
  411. UINT uiSz = sizeof(VS_FIXEDFILEINFO);
  412. if(!VerQueryValue(pVerBuffer, _u("\\"), (LPVOID*)&pFileInfo, &uiSz))
  413. {
  414. hr = HRESULT_FROM_WIN32(GetLastError());
  415. }
  416. else
  417. {
  418. hr = S_OK;
  419. }
  420. }
  421. else
  422. {
  423. hr = HRESULT_FROM_WIN32(GetLastError());
  424. }
  425. }
  426. else
  427. {
  428. hr = E_OUTOFMEMORY;
  429. }
  430. }
  431. if(SUCCEEDED(hr))
  432. {
  433. *majorVersion = pFileInfo->dwFileVersionMS;
  434. *minorVersion = pFileInfo->dwFileVersionLS;
  435. }
  436. else
  437. {
  438. *majorVersion = INVALID_VERSION;
  439. *minorVersion = INVALID_VERSION;
  440. }
  441. if(pVerBuffer)
  442. {
  443. NoCheckHeapDeleteArray(cbVersionSz, pVerBuffer);
  444. }
  445. return hr;
  446. #else // !_WIN32
  447. // xplat-todo: how to handle version resource?
  448. *majorVersion = INVALID_VERSION;
  449. *minorVersion = INVALID_VERSION;
  450. return NOERROR;
  451. #endif
  452. }