| // Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file | 
 | // for details. All rights reserved. Use of this source code is governed by a | 
 | // BSD-style license that can be found in the LICENSE file. | 
 |  | 
 | #include "vm/globals.h" | 
 | #if !defined(HOST_OS_MACOS) | 
 | #include "vm/cpuid.h" | 
 |  | 
 | #if defined(HOST_ARCH_IA32) || defined(HOST_ARCH_X64) | 
 | // GetCpuId() on Windows, __get_cpuid() on Linux | 
 | #if defined(HOST_OS_WINDOWS) | 
 | #include <intrin.h>  // NOLINT | 
 | #else | 
 | #include <cpuid.h>  // NOLINT | 
 | #endif | 
 | #endif | 
 |  | 
 | namespace dart { | 
 |  | 
 | bool CpuId::sse2_ = false; | 
 | bool CpuId::sse41_ = false; | 
 | bool CpuId::popcnt_ = false; | 
 | bool CpuId::abm_ = false; | 
 |  | 
 | const char* CpuId::id_string_ = nullptr; | 
 | const char* CpuId::brand_string_ = nullptr; | 
 |  | 
 | #if defined(HOST_ARCH_IA32) || defined(HOST_ARCH_X64) | 
 |  | 
 | void CpuId::GetCpuId(int32_t level, uint32_t info[4]) { | 
 | #if defined(HOST_OS_WINDOWS) | 
 |   // The documentation for __cpuid is at: | 
 |   // http://msdn.microsoft.com/en-us/library/hskdteyh(v=vs.90).aspx | 
 |   __cpuid(reinterpret_cast<int*>(info), level); | 
 | #else | 
 |   __get_cpuid(level, &info[0], &info[1], &info[2], &info[3]); | 
 | #endif | 
 | } | 
 |  | 
 | void CpuId::Init() { | 
 |   uint32_t info[4] = {static_cast<uint32_t>(-1)}; | 
 |  | 
 |   GetCpuId(0, info); | 
 |   char* id_string = reinterpret_cast<char*>(malloc(3 * sizeof(int32_t))); | 
 |  | 
 |   // Yes, these are supposed to be out of order. | 
 |   *reinterpret_cast<uint32_t*>(id_string) = info[1]; | 
 |   *reinterpret_cast<uint32_t*>(id_string + 4) = info[3]; | 
 |   *reinterpret_cast<uint32_t*>(id_string + 8) = info[2]; | 
 |   CpuId::id_string_ = id_string; | 
 |  | 
 |   GetCpuId(1, info); | 
 |   CpuId::sse41_ = (info[2] & (1 << 19)) != 0; | 
 |   CpuId::sse2_ = (info[3] & (1 << 26)) != 0; | 
 |   CpuId::popcnt_ = (info[2] & (1 << 23)) != 0; | 
 |  | 
 |   GetCpuId(0x80000001, info); | 
 |   CpuId::abm_ = (info[2] & (1 << 5)) != 0; | 
 |  | 
 |   char* brand_string = | 
 |       reinterpret_cast<char*>(malloc(3 * 4 * sizeof(uint32_t))); | 
 |   for (uint32_t i = 0x80000002; i <= 0x80000004; i++) { | 
 |     uint32_t off = (i - 0x80000002U) * 4 * sizeof(uint32_t); | 
 |     GetCpuId(i, info); | 
 |     *reinterpret_cast<int32_t*>(brand_string + off) = info[0]; | 
 |     *reinterpret_cast<int32_t*>(brand_string + off + 4) = info[1]; | 
 |     *reinterpret_cast<int32_t*>(brand_string + off + 8) = info[2]; | 
 |     *reinterpret_cast<int32_t*>(brand_string + off + 12) = info[3]; | 
 |   } | 
 |   CpuId::brand_string_ = brand_string; | 
 | } | 
 |  | 
 | void CpuId::Cleanup() { | 
 |   ASSERT(id_string_ != NULL); | 
 |   free(const_cast<char*>(id_string_)); | 
 |   id_string_ = NULL; | 
 |  | 
 |   ASSERT(brand_string_ != NULL); | 
 |   free(const_cast<char*>(brand_string_)); | 
 |   brand_string_ = NULL; | 
 | } | 
 |  | 
 | const char* CpuId::id_string() { | 
 |   return Utils::StrDup(id_string_); | 
 | } | 
 |  | 
 | const char* CpuId::brand_string() { | 
 |   return Utils::StrDup(brand_string_); | 
 | } | 
 |  | 
 | const char* CpuId::field(CpuInfoIndices idx) { | 
 |   switch (idx) { | 
 |     case kCpuInfoProcessor: | 
 |       return id_string(); | 
 |     case kCpuInfoModel: | 
 |       return brand_string(); | 
 |     case kCpuInfoHardware: | 
 |       return brand_string(); | 
 |     case kCpuInfoFeatures: { | 
 |       char buffer[100]; | 
 |       char* p = buffer; | 
 |       const char* q = p + 100; | 
 |       *p = '\0'; | 
 |       if (sse2()) { | 
 |         p += snprintf(p, q - p, "sse2 "); | 
 |       } | 
 |       if (sse41()) { | 
 |         p += snprintf(p, q - p, "sse4.1 "); | 
 |       } | 
 |       if (popcnt()) { | 
 |         p += snprintf(p, q - p, "popcnt "); | 
 |       } | 
 |       if (abm()) { | 
 |         p += snprintf(p, q - p, "abm "); | 
 |       } | 
 |       // Remove last space before returning string. | 
 |       if (p != buffer) *(p - 1) = '\0'; | 
 |       return Utils::StrDup(buffer); | 
 |     } | 
 |     default: { | 
 |       UNREACHABLE(); | 
 |       return NULL; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | #endif  // defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) | 
 | }  // namespace dart | 
 |  | 
 | #endif  // !defined(HOST_OS_MACOS) |