--- old/src/hotspot/os_cpu/linux_sparc/vm_version_linux_sparc.cpp 2020-05-01 02:29:49.280530535 -0700 +++ /dev/null 2020-03-09 18:57:19.455001459 -0700 @@ -1,352 +0,0 @@ -/* - * Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "logging/log.hpp" -#include "precompiled.hpp" -#include "runtime/os.hpp" -#include "runtime/vm_version.hpp" - - -#define CPUINFO_LINE_SIZE 1024 - - -class CPUinfo { -public: - CPUinfo(const char* field) : _string(NULL) { - - char line[CPUINFO_LINE_SIZE]; - FILE* fp = fopen("/proc/cpuinfo", "r"); - - if (fp != NULL) { - while (fgets(line, sizeof(line), fp) != NULL) { - assert(strlen(line) < sizeof(line) - 1, - "buffer too small (%d)", CPUINFO_LINE_SIZE); - - const char* vstr = match_field(line, field); - - if (vstr != NULL) { - // We have a matching line and a valid starting point to the value of - // the field, copy the string for keeps. - _string = strdup(vstr); - break; - } - } - fclose(fp); - } - } - - ~CPUinfo() { free((void*)_string); } - - const char* value() const { return _string; } - - bool valid() const { return _string != NULL; } - - bool match(const char* s) const { - return valid() ? strcmp(_string, s) == 0 : false; - } - -private: - const char* _string; - - const char* match_field(char line[CPUINFO_LINE_SIZE], const char* field); - const char* match_alo(const char* text, const char* exp); - const char* match_seq(const char* text, const char* seq); -}; - -/* Given a line of text read from /proc/cpuinfo, determine if the property header - * matches the field specified, according to the following regexp: ""\W+:\W+ - * - * If we have a matching expression, return a pointer to the first character after - * the matching pattern, i.e. the "value", otherwise return NULL. - */ -const char* CPUinfo::match_field(char line[CPUINFO_LINE_SIZE], const char* field) { - return match_alo(match_seq(match_alo(match_seq(line, field), "\t "), ":"), "\t "); -} - -/* Match a sequence of at-least-one character in the string expression (exp) to - * the text input. - */ -const char* CPUinfo::match_alo(const char* text, const char* exp) { - if (text == NULL) return NULL; - - const char* chp; - - for (chp = &text[0]; *chp != '\0'; chp++) { - if (strchr(exp, *chp) == NULL) break; - } - - return text < chp ? chp : NULL; -} - -/* Match an exact sequence of characters as specified by the string expression - * (seq) to the text input. - */ -const char* CPUinfo::match_seq(const char* text, const char* seq) { - if (text == NULL) return NULL; - - while (*seq != '\0') { - if (*seq != *text++) break; else seq++; - } - - return *seq == '\0' ? text : NULL; -} - - -typedef struct { - const uint32_t hash; - bool seen; - const char* const name; - const uint64_t mask; -} FeatureEntry; - - -static uint64_t parse_features(FeatureEntry feature_tbl[], const char input[]); - - -void VM_Version::platform_features() { - - // Some of the features reported via "cpucaps", such as; 'flush', 'stbar', - // 'swap', 'muldiv', 'ultra3', 'blkinit', 'n2', 'mul32', 'div32', 'fsmuld' - // and 'v8plus', are either SPARC V8, supported by all HW or simply nonsense - // (the 'ultra3' "property"). - // - // Entries marked as 'NYI' are not yet supported via "cpucaps" but are - // expected to have the names used in the table below (these are SPARC M7 - // features or more recent). - // - // NOTE: Table sorted on lookup/hash ID. - - static FeatureEntry s_feature_tbl[] = { - { 0x006f, false, "v9", ISA_v9_msk }, // Mandatory - { 0x00a6, false, "md5", ISA_md5_msk }, - { 0x00ce, false, "adi", ISA_adi_msk }, // NYI - { 0x00d7, false, "ima", ISA_ima_msk }, - { 0x00d9, false, "aes", ISA_aes_msk }, - { 0x00db, false, "hpc", ISA_hpc_msk }, - { 0x00dc, false, "des", ISA_des_msk }, - { 0x00ed, false, "sha1", ISA_sha1_msk }, - { 0x00f2, false, "vis", ISA_vis1_msk }, - { 0x0104, false, "vis2", ISA_vis2_msk }, - { 0x0105, false, "vis3", ISA_vis3_msk }, - { 0x0114, false, "sha512", ISA_sha512_msk }, - { 0x0119, false, "sha256", ISA_sha256_msk }, - { 0x011a, false, "fmaf", ISA_fmaf_msk }, - { 0x0132, false, "popc", ISA_popc_msk }, - { 0x0140, false, "crc32c", ISA_crc32c_msk }, - { 0x0147, false, "vis3b", ISA_vis3b_msk }, // NYI - { 0x017e, false, "pause", ISA_pause_msk }, - { 0x0182, false, "mwait", ISA_mwait_msk }, // NYI - { 0x018b, false, "mpmul", ISA_mpmul_msk }, - { 0x018e, false, "sparc5", ISA_sparc5_msk }, // NYI - { 0x01a9, false, "cbcond", ISA_cbcond_msk }, - { 0x01c3, false, "vamask", ISA_vamask_msk }, // NYI - { 0x01ca, false, "kasumi", ISA_kasumi_msk }, - { 0x01e3, false, "xmpmul", ISA_xmpmul_msk }, // NYI - { 0x022c, false, "montmul", ISA_mont_msk }, - { 0x0234, false, "montsqr", ISA_mont_msk }, - { 0x0238, false, "camellia", ISA_camellia_msk }, - { 0x024a, false, "ASIBlkInit", ISA_blk_init_msk }, - { 0x0284, false, "xmontmul", ISA_xmont_msk }, // NYI - { 0x02e6, false, "pause_nsec", ISA_pause_nsec_msk }, // NYI - - { 0x0000, false, NULL, 0 } - }; - - CPUinfo caps("cpucaps"); // Read "cpucaps" from /proc/cpuinfo. - - assert(caps.valid(), "must be"); - - _features = parse_features(s_feature_tbl, caps.value()); - - assert(has_v9(), "must be"); // Basic SPARC-V9 required (V8 not supported). - - CPUinfo type("type"); - - bool is_sun4v = type.match("sun4v"); // All Oracle SPARC + Fujitsu Athena+ - bool is_sun4u = type.match("sun4u"); // All other Fujitsu - - uint64_t synthetic = 0; - - if (is_sun4v) { - // Indirect and direct branches are equally fast. - synthetic = CPU_fast_ind_br_msk; - // Fast IDIV, BIS and LD available on Niagara Plus. - if (has_vis2()) { - synthetic |= (CPU_fast_idiv_msk | CPU_fast_ld_msk); - // ...on Core C4 however, we prefer not to use BIS. - if (!has_sparc5()) { - synthetic |= CPU_fast_bis_msk; - } - } - // Niagara Core C3 supports fast RDPC and block zeroing. - if (has_ima()) { - synthetic |= (CPU_fast_rdpc_msk | CPU_blk_zeroing_msk); - } - // Niagara Core C3 and C4 have slow CMOVE. - if (!has_ima()) { - synthetic |= CPU_fast_cmove_msk; - } - } else if (is_sun4u) { - // SPARC64 only have fast IDIV and RDPC. - synthetic |= (CPU_fast_idiv_msk | CPU_fast_rdpc_msk); - } else { - log_info(os, cpu)("Unable to derive CPU features: %s", type.value()); - } - - _features += synthetic; // Including CPU derived/synthetic features. -} - - -//////////////////////////////////////////////////////////////////////////////// - -static uint32_t uhash32(const char name[]); - -static void update_table(FeatureEntry feature_tbl[], uint32_t hv, - const char* ch1p, - const char* endp); - -/* Given a feature table, parse the input text holding the string value of - * 'cpucaps' as reported by '/proc/cpuinfo', in order to complete the table - * with information on each admissible feature (whether present or not). - * - * Return the composite bit-mask representing the features found. - */ -static uint64_t parse_features(FeatureEntry feature_tbl[], const char input[]) { - log_info(os, cpu)("Parse CPU features: %s\n", input); - -#ifdef ASSERT - // Verify that hash value entries in the table are unique and ordered. - - uint32_t prev = 0; - - for (uint k = 0; feature_tbl[k].name != NULL; k++) { - feature_tbl[k].seen = false; - - assert(feature_tbl[k].hash == uhash32(feature_tbl[k].name), - "feature '%s' has mismatching hash 0x%08x (expected 0x%08x).\n", - feature_tbl[k].name, - feature_tbl[k].hash, - uhash32(feature_tbl[k].name)); - - assert(prev < feature_tbl[k].hash, - "feature '%s' has invalid hash 0x%08x (previous is 0x%08x).\n", - feature_tbl[k].name, - feature_tbl[k].hash, - prev); - - prev = feature_tbl[k].hash; - } -#endif - // Identify features from the input, consisting of a string with features - // separated by commas (or whitespace), e.g. "flush,muldiv,v9,mul32,div32, - // v8plus,popc,vis". - - uint32_t hv = 0; - const char* ch1p = &input[0]; - uint i = 0; - - do { - char ch = input[i]; - - if (isalnum(ch) || ch == '_') { - hv += (ch - 32u); - } - else if (isspace(ch) || ch == ',' || ch == '\0') { // end-of-token - if (ch1p < &input[i]) { - update_table(feature_tbl, hv, ch1p, &input[i]); - } - ch1p = &input[i + 1]; hv = 0; - } else { - // Handle non-accepted input robustly. - log_info(os, cpu)("Bad token in feature string: '%c' (0x%02x).\n", ch, ch); - ch1p = &input[i + 1]; hv = 0; - } - } - while (input[i++] != '\0'); - - // Compute actual bit-mask representation. - - uint64_t mask = 0; - - for (uint k = 0; feature_tbl[k].name != NULL; k++) { - mask |= feature_tbl[k].seen ? feature_tbl[k].mask : 0; - } - - return mask; -} - -static uint32_t uhash32(const char name[]) { - uint32_t hv = 0; - - for (uint i = 0; name[i] != '\0'; i++) { - hv += (name[i] - 32u); - } - - return hv; -} - -static bool verify_match(const char name[], const char* ch1p, const char* endp); - -static void update_table(FeatureEntry feature_tbl[], uint32_t hv, const char* ch1p, const char* endp) { - assert(ch1p < endp, "at least one character"); - - // Look for a hash value in the table. Since this table is a small one (and - // is expected to stay small), we use a simple linear search (iff the table - // grows large, we may consider to adopt a binary ditto, or a perfect hash). - - for (uint k = 0; feature_tbl[k].name != NULL; k++) { - uint32_t hash = feature_tbl[k].hash; - - if (hash < hv) continue; - - if (hash == hv) { - const char* name = feature_tbl[k].name; - - if (verify_match(name, ch1p, endp)) { - feature_tbl[k].seen = true; - break; - } - } - - // Either a non-matching feature (when hash == hv) or hash > hv. In either - // case we break out of the loop and terminate the search (note that the - // table is assumed to be uniquely sorted on the hash). - - break; - } -} - -static bool verify_match(const char name[], const char* ch1p, const char* endp) { - size_t len = strlen(name); - - if (len != static_cast(endp - ch1p)) { - return false; - } - - for (uint i = 0; ch1p + i < endp; i++) { - if (name[i] != ch1p[i]) return false; - } - - return true; -}