SysInfo.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  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_InitializeChakraCore();
  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->supportsOnlyMultiThreadedCOM = false;
  98. #if defined(__ANDROID__) || defined(__IOS__)
  99. this->isLowMemoryDevice = true;
  100. this->shouldQCMoreFrequently = true;
  101. #else
  102. this->shouldQCMoreFrequently = false;
  103. this->isLowMemoryDevice = false;
  104. #endif
  105. // 0 indicates we haven't retrieved the available commit. We get it lazily.
  106. this->availableCommit = 0;
  107. ChakraBinaryAutoSystemInfoInit(this);
  108. }
  109. bool
  110. AutoSystemInfo::InitPhysicalProcessorCount()
  111. {
  112. DWORD countPhysicalProcessor = 0;
  113. #ifdef _WIN32
  114. DWORD size = 0;
  115. PSYSTEM_LOGICAL_PROCESSOR_INFORMATION pBufferCurrent;
  116. PSYSTEM_LOGICAL_PROCESSOR_INFORMATION pBufferStart;
  117. BOOL bResult;
  118. #endif // _WIN32
  119. Assert(!this->initialized);
  120. // Initialize physical processor to number of logical processors.
  121. // If anything below fails, we still need an approximate value
  122. this->dwNumberOfPhysicalProcessors = this->dwNumberOfProcessors;
  123. #if defined(_WIN32)
  124. bResult = GetLogicalProcessorInformation(NULL, &size);
  125. if (bResult || GetLastError() != ERROR_INSUFFICIENT_BUFFER || !size)
  126. {
  127. return false;
  128. }
  129. DWORD count = (size) / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
  130. if (size != count * sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION))
  131. {
  132. Assert(false);
  133. return false;
  134. }
  135. pBufferCurrent = pBufferStart = NoCheckHeapNewArray(SYSTEM_LOGICAL_PROCESSOR_INFORMATION, (size_t)count);
  136. if (!pBufferCurrent)
  137. {
  138. return false;
  139. }
  140. bResult = GetLogicalProcessorInformation(pBufferCurrent, &size);
  141. if (!bResult)
  142. {
  143. NoCheckHeapDeleteArray(count, pBufferStart);
  144. return false;
  145. }
  146. while (pBufferCurrent < (pBufferStart + count))
  147. {
  148. if (pBufferCurrent->Relationship == RelationProcessorCore)
  149. {
  150. countPhysicalProcessor++;
  151. }
  152. pBufferCurrent++;
  153. }
  154. NoCheckHeapDeleteArray(count, pBufferStart);
  155. #elif defined(__APPLE__)
  156. std::size_t szCount = sizeof(countPhysicalProcessor);
  157. sysctlbyname("hw.physicalcpu", &countPhysicalProcessor, &szCount, nullptr, 0);
  158. if (countPhysicalProcessor < 1)
  159. {
  160. int nMIB[2] = {CTL_HW, HW_NCPU}; // fallback. Depracated on latest OS
  161. sysctl(nMIB, 2, &countPhysicalProcessor, &szCount, nullptr, 0);
  162. if (countPhysicalProcessor < 1)
  163. {
  164. countPhysicalProcessor = 1;
  165. }
  166. }
  167. #elif defined(__linux__)
  168. countPhysicalProcessor = sysconf(_SC_NPROCESSORS_ONLN);
  169. #else
  170. // implementation for __linux__ should work for some others.
  171. // same applies to __APPLE__ implementation
  172. // instead of reimplementing, add corresponding preprocessors above
  173. #error "NOT Implemented"
  174. #endif
  175. this->dwNumberOfPhysicalProcessors = countPhysicalProcessor;
  176. return true;
  177. }
  178. #if SYSINFO_IMAGE_BASE_AVAILABLE
  179. bool
  180. AutoSystemInfo::IsJscriptModulePointer(void * ptr)
  181. {
  182. return ((UINT_PTR)ptr >= Data.dllLoadAddress && (UINT_PTR)ptr < Data.dllHighAddress);
  183. }
  184. UINT_PTR
  185. AutoSystemInfo::GetChakraBaseAddr() const
  186. {
  187. return dllLoadAddress;
  188. }
  189. #endif
  190. uint
  191. AutoSystemInfo::GetAllocationGranularityPageCount() const
  192. {
  193. Assert(initialized);
  194. return this->allocationGranularityPageCount;
  195. }
  196. uint
  197. AutoSystemInfo::GetAllocationGranularityPageSize() const
  198. {
  199. Assert(initialized);
  200. return this->allocationGranularityPageCount * PageSize;
  201. }
  202. #if defined(_M_IX86) || defined(_M_X64)
  203. bool
  204. AutoSystemInfo::VirtualSseAvailable(const int sseLevel) const
  205. {
  206. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  207. return CONFIG_FLAG(Sse) < 0 || CONFIG_FLAG(Sse) >= sseLevel;
  208. #else
  209. return true;
  210. #endif
  211. }
  212. #endif
  213. BOOL
  214. AutoSystemInfo::SSE2Available() const
  215. {
  216. Assert(initialized);
  217. #if defined(_M_X64) || defined(_M_ARM32_OR_ARM64)
  218. return true;
  219. #elif defined(_M_IX86)
  220. #if defined(_WIN32)
  221. return VirtualSseAvailable(2) && (CPUInfo[3] & (1 << 26));
  222. #else
  223. return false; // TODO: xplat support
  224. #endif
  225. #else
  226. return false;
  227. #endif
  228. }
  229. #if defined(_M_IX86) || defined(_M_X64)
  230. BOOL
  231. AutoSystemInfo::SSE3Available() const
  232. {
  233. Assert(initialized);
  234. return VirtualSseAvailable(3) && (CPUInfo[2] & 0x1);
  235. }
  236. BOOL
  237. AutoSystemInfo::SSE4_1Available() const
  238. {
  239. Assert(initialized);
  240. return VirtualSseAvailable(4) && (CPUInfo[2] & (0x1 << 19));
  241. }
  242. BOOL
  243. AutoSystemInfo::SSE4_2Available() const
  244. {
  245. Assert(initialized);
  246. return VirtualSseAvailable(4) && (CPUInfo[2] & (0x1 << 20));
  247. }
  248. BOOL
  249. AutoSystemInfo::PopCntAvailable() const
  250. {
  251. Assert(initialized);
  252. return VirtualSseAvailable(4) && (CPUInfo[2] & (1 << 23));
  253. }
  254. BOOL
  255. AutoSystemInfo::LZCntAvailable() const
  256. {
  257. Assert(initialized);
  258. int CPUInfo[4];
  259. get_cpuid(CPUInfo, 0x80000001);
  260. return VirtualSseAvailable(4) && (CPUInfo[2] & (1 << 5));
  261. }
  262. BOOL
  263. AutoSystemInfo::TZCntAvailable() const
  264. {
  265. Assert(initialized);
  266. int CPUInfo[4];
  267. get_cpuid(CPUInfo, 7);
  268. return VirtualSseAvailable(4) && (CPUInfo[1] & (1 << 3));
  269. }
  270. bool
  271. AutoSystemInfo::IsAtomPlatform() const
  272. {
  273. return isAtom;
  274. }
  275. bool
  276. AutoSystemInfo::CheckForAtom() const
  277. {
  278. int CPUInfo[4];
  279. const int GENUINE_INTEL_0 = 0x756e6547,
  280. GENUINE_INTEL_1 = 0x49656e69,
  281. GENUINE_INTEL_2 = 0x6c65746e;
  282. const int PLATFORM_MASK = 0x0fff3ff0;
  283. const int ATOM_PLATFORM_A = 0x0106c0, /* bonnell - extended model 1c, type 0, family code 6 */
  284. ATOM_PLATFORM_B = 0x020660, /* lincroft - extended model 26, type 0, family code 6 */
  285. ATOM_PLATFORM_C = 0x020670, /* saltwell - extended model 27, type 0, family code 6 */
  286. ATOM_PLATFORM_D = 0x030650, /* tbd - extended model 35, type 0, family code 6 */
  287. ATOM_PLATFORM_E = 0x030660, /* tbd - extended model 36, type 0, family code 6 */
  288. ATOM_PLATFORM_F = 0x030670; /* tbd - extended model 37, type 0, family code 6 */
  289. int platformSignature;
  290. get_cpuid(CPUInfo, 0);
  291. // See if CPU is ATOM HW. First check if CPU is genuine Intel.
  292. if( CPUInfo[1]==GENUINE_INTEL_0 &&
  293. CPUInfo[3]==GENUINE_INTEL_1 &&
  294. CPUInfo[2]==GENUINE_INTEL_2)
  295. {
  296. get_cpuid(CPUInfo, 1);
  297. // get platform signature
  298. platformSignature = CPUInfo[0];
  299. if((( PLATFORM_MASK & platformSignature) == ATOM_PLATFORM_A) ||
  300. ((PLATFORM_MASK & platformSignature) == ATOM_PLATFORM_B) ||
  301. ((PLATFORM_MASK & platformSignature) == ATOM_PLATFORM_C) ||
  302. ((PLATFORM_MASK & platformSignature) == ATOM_PLATFORM_D) ||
  303. ((PLATFORM_MASK & platformSignature) == ATOM_PLATFORM_E) ||
  304. ((PLATFORM_MASK & platformSignature) == ATOM_PLATFORM_F))
  305. {
  306. return true;
  307. }
  308. }
  309. return false;
  310. }
  311. #endif
  312. bool
  313. AutoSystemInfo::IsWin8OrLater()
  314. {
  315. return isWindows8OrGreater;
  316. }
  317. #if defined(_CONTROL_FLOW_GUARD)
  318. bool
  319. AutoSystemInfo::IsWinThresholdOrLater()
  320. {
  321. #if defined(_M_ARM64)
  322. return true;
  323. #else
  324. return IsWindowsThresholdOrGreater();
  325. #endif
  326. }
  327. #endif
  328. DWORD AutoSystemInfo::SaveModuleFileName(HANDLE hMod)
  329. {
  330. return ::GetModuleFileNameW((HMODULE)hMod, Data.binaryName, MAX_PATH);
  331. }
  332. LPCWSTR AutoSystemInfo::GetJscriptDllFileName()
  333. {
  334. return (LPCWSTR)Data.binaryName;
  335. }
  336. #ifdef _WIN32
  337. /* static */
  338. HMODULE AutoSystemInfo::GetCRTHandle()
  339. {
  340. return GetModuleHandle(_u("msvcrt.dll"));
  341. }
  342. bool
  343. AutoSystemInfo::IsCRTModulePointer(uintptr_t ptr)
  344. {
  345. HMODULE base = GetCRTHandle();
  346. if (Data.crtSize == 0)
  347. {
  348. MODULEINFO info;
  349. if (!GetModuleInformation(GetCurrentProcess(), base, &info, sizeof(MODULEINFO)))
  350. {
  351. AssertOrFailFast(UNREACHED);
  352. }
  353. Data.crtSize = info.SizeOfImage;
  354. Assert(base == info.lpBaseOfDll);
  355. }
  356. return (ptr >= (uintptr_t)base && ptr < (uintptr_t)base + Data.crtSize);
  357. }
  358. #endif
  359. bool AutoSystemInfo::IsLowMemoryProcess()
  360. {
  361. ULONG64 commit = ULONG64(-1);
  362. this->GetAvailableCommit(&commit);
  363. return commit <= CONFIG_FLAG(LowMemoryCap);
  364. }
  365. BOOL AutoSystemInfo::GetAvailableCommit(ULONG64 *pCommit)
  366. {
  367. Assert(initialized);
  368. // Non-zero value indicates we've been here before.
  369. if (this->availableCommit == 0)
  370. {
  371. return false;
  372. }
  373. *pCommit = this->availableCommit;
  374. return true;
  375. }
  376. void AutoSystemInfo::SetAvailableCommit(ULONG64 commit)
  377. {
  378. ::InterlockedCompareExchange64((volatile LONG64 *)&this->availableCommit, commit, 0);
  379. }
  380. //
  381. // Returns the major and minor version of the loaded binary. If the version info has been fetched once, it will be cached
  382. // and returned without any system calls to find the version number.
  383. //
  384. HRESULT AutoSystemInfo::GetJscriptFileVersion(DWORD* majorVersion, DWORD* minorVersion, DWORD *buildDateHash, DWORD *buildTimeHash)
  385. {
  386. HRESULT hr = E_FAIL;
  387. if(AutoSystemInfo::Data.majorVersion == 0 && AutoSystemInfo::Data.minorVersion == 0)
  388. {
  389. // uninitialized state - call the system API to get the version info.
  390. LPCWSTR jscriptDllName = GetJscriptDllFileName();
  391. hr = GetVersionInfo(jscriptDllName, majorVersion, minorVersion);
  392. AutoSystemInfo::Data.majorVersion = *majorVersion;
  393. AutoSystemInfo::Data.minorVersion = *minorVersion;
  394. }
  395. else if(AutoSystemInfo::Data.majorVersion != INVALID_VERSION)
  396. {
  397. // if the cached copy is valid, use it and return S_OK.
  398. *majorVersion = AutoSystemInfo::Data.majorVersion;
  399. *minorVersion = AutoSystemInfo::Data.minorVersion;
  400. hr = S_OK;
  401. }
  402. if (buildDateHash)
  403. {
  404. *buildDateHash = AutoSystemInfo::Data.buildDateHash;
  405. }
  406. if (buildTimeHash)
  407. {
  408. *buildTimeHash = AutoSystemInfo::Data.buildTimeHash;
  409. }
  410. return hr;
  411. }
  412. //
  413. // Returns the major and minor version of the binary passed as argument.
  414. //
  415. HRESULT AutoSystemInfo::GetVersionInfo(__in LPCWSTR pszPath, DWORD* majorVersion, DWORD* minorVersion)
  416. {
  417. #ifdef _WIN32
  418. DWORD dwTemp;
  419. DWORD cbVersionSz;
  420. HRESULT hr = E_FAIL;
  421. BYTE* pVerBuffer = NULL;
  422. VS_FIXEDFILEINFO* pFileInfo = NULL;
  423. cbVersionSz = GetFileVersionInfoSizeEx(FILE_VER_GET_LOCALISED, pszPath, &dwTemp);
  424. if(cbVersionSz > 0)
  425. {
  426. pVerBuffer = NoCheckHeapNewArray(BYTE, cbVersionSz);
  427. if(pVerBuffer)
  428. {
  429. if(GetFileVersionInfoEx(FILE_VER_GET_LOCALISED|FILE_VER_GET_NEUTRAL, pszPath, 0, cbVersionSz, pVerBuffer))
  430. {
  431. UINT uiSz = sizeof(VS_FIXEDFILEINFO);
  432. if(!VerQueryValue(pVerBuffer, _u("\\"), (LPVOID*)&pFileInfo, &uiSz))
  433. {
  434. hr = HRESULT_FROM_WIN32(GetLastError());
  435. }
  436. else
  437. {
  438. hr = S_OK;
  439. }
  440. }
  441. else
  442. {
  443. hr = HRESULT_FROM_WIN32(GetLastError());
  444. }
  445. }
  446. else
  447. {
  448. hr = E_OUTOFMEMORY;
  449. }
  450. }
  451. if(SUCCEEDED(hr))
  452. {
  453. *majorVersion = pFileInfo->dwFileVersionMS;
  454. *minorVersion = pFileInfo->dwFileVersionLS;
  455. }
  456. else
  457. {
  458. *majorVersion = INVALID_VERSION;
  459. *minorVersion = INVALID_VERSION;
  460. }
  461. if(pVerBuffer)
  462. {
  463. NoCheckHeapDeleteArray(cbVersionSz, pVerBuffer);
  464. }
  465. return hr;
  466. #else // !_WIN32
  467. // xplat-todo: how to handle version resource?
  468. *majorVersion = INVALID_VERSION;
  469. *minorVersion = INVALID_VERSION;
  470. return NOERROR;
  471. #endif
  472. }