Skip to content
Permalink
Browse files

8239235: Examine SignatureStream performance after consolidation

Reviewed-by: lfoltan, coleenp
  • Loading branch information
cl4es committed Feb 24, 2020
1 parent 3f140fa commit 289513cc2b2138b32010cb8ece3fe13c43dc2d6f
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2020, 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
@@ -106,7 +106,7 @@ VerificationType StackMapFrame::set_locals_from_arg(
// Create another symbol to save as signature stream unreferences
// this symbol.
Symbol *sig_copy =
verifier()->create_temporary_symbol(sig, 0, sig->utf8_length());
verifier()->create_temporary_symbol(sig);
assert(sig_copy == sig, "symbols don't match");
sig = sig_copy;
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, 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
@@ -56,7 +56,7 @@ const size_t ON_STACK_BUFFER_LENGTH = 128;

inline bool symbol_equals_compact_hashtable_entry(Symbol* value, const char* key, int len) {
if (value->equals(key, len)) {
assert(value->refcount() == PERM_REFCOUNT, "must be shared");
assert(value->is_permanent(), "must be shared");
return true;
} else {
return false;
@@ -139,10 +139,10 @@ class SymbolTableConfig : public AllStatic {
static void free_node(void* memory, Value const& value) {
// We get here because #1 some threads lost a race to insert a newly created Symbol
// or #2 we're cleaning up unused symbol.
// If #1, then the symbol can be either permanent (refcount==PERM_REFCOUNT),
// If #1, then the symbol can be either permanent,
// or regular newly created one (refcount==1)
// If #2, then the symbol is dead (refcount==0)
assert((value->refcount() == PERM_REFCOUNT) || (value->refcount() == 1) || (value->refcount() == 0),
assert(value->is_permanent() || (value->refcount() == 1) || (value->refcount() == 0),
"refcount %d", value->refcount());
if (value->refcount() == 1) {
value->decrement_refcount();
@@ -176,7 +176,7 @@ void SymbolTable::create_table () {
}

void SymbolTable::delete_symbol(Symbol* sym) {
if (sym->refcount() == PERM_REFCOUNT) {
if (sym->is_permanent()) {
MutexLocker ml(SymbolArena_lock, Mutex::_no_safepoint_check_flag); // Protect arena
// Deleting permanent symbol should not occur very often (insert race condition),
// so log it.
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2020, 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
@@ -3153,13 +3153,6 @@ void ClassVerifier::verify_return_value(
// The verifier creates symbols which are substrings of Symbols.
// These are stored in the verifier until the end of verification so that
// they can be reference counted.
Symbol* ClassVerifier::create_temporary_symbol(const Symbol *s, int begin,
int end) {
const char* name = (const char*)s->base() + begin;
int length = end - begin;
return create_temporary_symbol(name, length);
}

Symbol* ClassVerifier::create_temporary_symbol(const char *name, int length) {
// Quick deduplication check
if (_previous_symbol != NULL && _previous_symbol->equals(name, length)) {
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2020, 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
@@ -456,7 +456,6 @@ class ClassVerifier : public StackObj {
// their reference counts need to be decremented when the verifier object
// goes out of scope. Since these symbols escape the scope in which they're
// created, we can't use a TempNewSymbol.
Symbol* create_temporary_symbol(const Symbol* s, int begin, int end);
Symbol* create_temporary_symbol(const char *s, int length);
Symbol* create_temporary_symbol(Symbol* s) {
if (s == _previous_symbol) {
@@ -78,34 +78,6 @@ void Symbol::set_permanent() {
_hash_and_refcount = pack_hash_and_refcount(extract_hash(_hash_and_refcount), PERM_REFCOUNT);
}


// ------------------------------------------------------------------
// Symbol::contains_byte_at
//
// Tests if the symbol contains the given byte at the given position.
bool Symbol::contains_byte_at(int position, char code_byte) const {
if (position < 0) return false; // can happen with ends_with
if (position >= utf8_length()) return false;
return code_byte == char_at(position);
}

// ------------------------------------------------------------------
// Symbol::contains_utf8_at
//
// Tests if the symbol contains the given utf8 substring
// at the given byte position.
bool Symbol::contains_utf8_at(int position, const char* substring, int len) const {
assert(len >= 0 && substring != NULL, "substring must be valid");
if (len <= 1)
return len == 0 || contains_byte_at(position, substring[0]);
if (position < 0) return false; // can happen with ends_with
if (position + len > utf8_length()) return false;
if (memcmp((char*)base() + position, substring, len) == 0)
return true;
else
return false;
}

// ------------------------------------------------------------------
// Symbol::index_of
//
@@ -97,7 +97,7 @@ class ClassLoaderData;

// Set _refcount to PERM_REFCOUNT to prevent the Symbol from being freed.
#ifndef PERM_REFCOUNT
#define PERM_REFCOUNT ((1 << 16) - 1)
#define PERM_REFCOUNT 0xffff
#endif

class Symbol : public MetaspaceObj {
@@ -113,7 +113,7 @@ class Symbol : public MetaspaceObj {
u1 _body[2];

enum {
max_symbol_length = (1 << 16) -1
max_symbol_length = 0xffff
};

static int byte_size(int length) {
@@ -165,7 +165,7 @@ class Symbol : public MetaspaceObj {
bool try_increment_refcount();
void increment_refcount();
void decrement_refcount();
bool is_permanent() {
bool is_permanent() const {
return (refcount() == PERM_REFCOUNT);
}
void set_permanent();
@@ -210,12 +210,24 @@ class Symbol : public MetaspaceObj {
return ends_with(suffix, (int) strlen(suffix));
}
bool ends_with(int suffix_char) const {
return contains_byte_at(utf8_length()-1, suffix_char);
return contains_byte_at(utf8_length() - 1, suffix_char);
}

// Tests if the symbol contains the given utf8 substring
// or byte at the given byte position.
bool contains_utf8_at(int position, const char* substring, int len) const;
bool contains_byte_at(int position, char code_byte) const;
// at the given byte position.
bool contains_utf8_at(int position, const char* substring, int len) const {
assert(len >= 0 && substring != NULL, "substring must be valid");
if (position < 0) return false; // can happen with ends_with
if (position + len > utf8_length()) return false;
return (memcmp((char*)base() + position, substring, len) == 0);
}

// Tests if the symbol contains the given byte at the given position.
bool contains_byte_at(int position, char code_byte) const {
if (position < 0) return false; // can happen with ends_with
if (position >= utf8_length()) return false;
return code_byte == char_at(position);
}

// Tests if the symbol starts with the given prefix.
int index_of_at(int i, const char* str, int len) const;
@@ -172,14 +172,14 @@ void Fingerprinter::compute_fingerprint_and_return_type(bool static_flag) {

// Implementation of SignatureStream

static inline int decode_signature_char(int ch) {
static inline BasicType decode_signature_char(int ch) {
switch (ch) {
#define EACH_SIG(ch, bt, ignore) \
case ch: return bt;
SIGNATURE_TYPES_DO(EACH_SIG, ignore)
#undef EACH_SIG
}
return 0;
return (BasicType)0;
}

SignatureStream::SignatureStream(const Symbol* signature,
@@ -188,51 +188,54 @@ SignatureStream::SignatureStream(const Symbol* signature,
"method signature required");
_signature = signature;
_limit = signature->utf8_length();
int oz = (is_method ? 1 : 0);
int oz = (is_method ? _s_method : _s_field);
_state = oz;
assert(_state == (int)(is_method ? _s_method : _s_field), "signature state incorrectly set");
_begin = _end = oz; // skip first '(' in method signatures
_array_prefix = 0; // just for definiteness
_previous_name = NULL;

// assigning java/lang/Object to _previous_name means we can
// avoid a number of NULL checks in the parser
_previous_name = vmSymbols::java_lang_Object();
_names = NULL;
next();
}

SignatureStream::~SignatureStream() {
// decrement refcount for names created during signature parsing
_previous_name->decrement_refcount();
if (_names != NULL) {
for (int i = 0; i < _names->length(); i++) {
_names->at(i)->decrement_refcount();
}
} else if (_previous_name != NULL && !_previous_name->is_permanent()) {
_previous_name->decrement_refcount();
}
}

inline int SignatureStream::scan_non_primitive(BasicType type) {
inline int SignatureStream::scan_type(BasicType type) {
const u1* base = _signature->bytes();
int end = _end;
int limit = _limit;
const u1* tem;
switch (type) {
case T_OBJECT:
tem = (const u1*) memchr(&base[end], JVM_SIGNATURE_ENDCLASS, limit - end);
end = (tem == NULL ? limit : tem+1 - base);
break;
return (tem == NULL ? limit : tem + 1 - base);

case T_ARRAY:
while ((end < limit) && ((char)base[end] == JVM_SIGNATURE_ARRAY)) { end++; }
_array_prefix = end - _end; // number of '[' chars just skipped
if (Signature::has_envelope(base[end++])) {
tem = (const u1*) memchr(&base[end], JVM_SIGNATURE_ENDCLASS, limit - end);
end = (tem == NULL ? limit : tem+1 - base);
break;
if (Signature::has_envelope(base[end])) {
tem = (const u1 *) memchr(&base[end], JVM_SIGNATURE_ENDCLASS, limit - end);
return (tem == NULL ? limit : tem + 1 - base);
}
break;

default : ShouldNotReachHere();
// Skipping over a single character for a primitive type.
assert(is_java_primitive(decode_signature_char(base[end])), "only primitives expected");
return end + 1;

default:
// Skipping over a single character for a primitive type (or void).
assert(!is_reference_type(type), "only primitives or void expected");
return end + 1;
}
return end;
}

void SignatureStream::next() {
@@ -241,50 +244,33 @@ void SignatureStream::next() {
if (_end >= len) { set_done(); return; }
_begin = _end;
int ch = sig->char_at(_begin);
int btcode = decode_signature_char(ch);
if (btcode == 0) {
guarantee(ch == JVM_SIGNATURE_ENDFUNC, "bad signature char %c/%d", ch, ch);
if (ch == JVM_SIGNATURE_ENDFUNC) {
assert(_state == _s_method, "must be in method");
_state = _s_method_return;
_begin = ++_end;
if (_end >= len) { set_done(); return; }
ch = sig->char_at(_begin);
btcode = decode_signature_char(ch);
}
BasicType bt = (BasicType) btcode;
BasicType bt = decode_signature_char(ch);
assert(ch == type2char(bt), "bad signature char %c/%d", ch, ch);
_type = bt;
if (!is_reference_type(bt)) {
// Skip over a single character for a primitive type (or void).
_end++;
return;
}
_end = scan_non_primitive(bt);
_end = scan_type(bt);
}

int SignatureStream::skip_array_prefix(int max_skip_length) {
if (_type != T_ARRAY) {
return 0;
}
if (_array_prefix > max_skip_length) {
// strip some but not all levels of T_ARRAY
_array_prefix -= max_skip_length;
_begin += max_skip_length;
return max_skip_length;
}
int SignatureStream::skip_whole_array_prefix() {
assert(_type == T_ARRAY, "must be");

// we are stripping all levels of T_ARRAY,
// so we must decode the next character
int whole_array_prefix = _array_prefix;
int new_begin = _begin + whole_array_prefix;
_begin = new_begin;
int ch = _signature->char_at(new_begin);
int btcode = decode_signature_char(ch);
BasicType bt = (BasicType) btcode;
BasicType bt = decode_signature_char(ch);
assert(ch == type2char(bt), "bad signature char %c/%d", ch, ch);
_type = bt;
assert(bt != T_VOID && bt != T_ARRAY, "bad signature type");
// Don't bother to call scan_non_primitive, since it won't
// change the value of _end.
// Don't bother to re-scan, since it won't change the value of _end.
return whole_array_prefix;
}

@@ -317,9 +303,9 @@ bool Signature::is_valid_array_signature(const Symbol* sig) {
}

BasicType Signature::basic_type(int ch) {
int btcode = decode_signature_char(ch);
BasicType btcode = decode_signature_char(ch);
if (btcode == 0) return T_ILLEGAL;
return (BasicType) btcode;
return btcode;
}

static const int jl_len = 10, object_len = 6, jl_object_len = jl_len + object_len;
@@ -365,7 +351,7 @@ Symbol* SignatureStream::find_symbol() {
}

Symbol* name = _previous_name;
if (name != NULL && name->equals(symbol_chars, len)) {
if (name->equals(symbol_chars, len)) {
return name;
}

@@ -375,18 +361,11 @@ Symbol* SignatureStream::find_symbol() {

// Only allocate the GrowableArray for the _names buffer if more than
// one name is being processed in the signature.
if (_previous_name != NULL &&
!_previous_name->is_permanent() &&
!name->is_permanent() &&
_names == NULL) {
_names = new GrowableArray<Symbol*>(10);
_names->push(_previous_name);
}
if (!name->is_permanent() && _previous_name != NULL) {
if (!_previous_name->is_permanent()) {
if (_names == NULL) {
_names = new GrowableArray<Symbol*>(10);
}
_names->push(name); // save new symbol for decrementing later
_names->push(_previous_name);
}
_previous_name = name;
return name;

0 comments on commit 289513c

Please sign in to comment.