src/hotspot/share/runtime/signature.cpp
author lfoltan
Mon, 21 Oct 2019 13:13:16 -0400
changeset 58722 cba8afa5cfed
parent 54847 59ea39bb2809
permissions -rw-r--r--
8231844: Enhance type signature characters in classfile_constants.h and improve the JVM to use type signature characters more consistently Summary: Increase the use of type signature constants instead of hard coded characters within the JVM. Reviewed-by: coleenp, dholmes, fparain Contributed-by: lois.foltan@oracle.com, john.r.rose@oracle.com

/*
 * Copyright (c) 1997, 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 "precompiled.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
#include "oops/typeArrayKlass.hpp"
#include "runtime/signature.hpp"

// Implementation of SignatureIterator

// Signature syntax:
//
// Signature  = "(" {Parameter} ")" ReturnType.
// Parameter  = FieldType.
// ReturnType = FieldType | "V".
// FieldType  = "B" | "C" | "D" | "F" | "I" | "J" | "S" | "Z" | "L" ClassName ";" | "[" FieldType.
// ClassName  = string.


SignatureIterator::SignatureIterator(Symbol* signature) {
  _signature       = signature;
  _parameter_index = 0;
}

void SignatureIterator::expect(char c) {
  if (_signature->char_at(_index) != c) fatal("expecting %c", c);
  _index++;
}

int SignatureIterator::parse_type() {
  // Note: This function could be simplified by using "return T_XXX_size;"
  //       instead of the assignment and the break statements. However, it
  //       seems that the product build for win32_i486 with MS VC++ 6.0 doesn't
  //       work (stack underflow for some tests) - this seems to be a VC++ 6.0
  //       compiler bug (was problem - gri 4/27/2000).
  int size = -1;
  switch(_signature->char_at(_index)) {
    case JVM_SIGNATURE_BYTE:    do_byte(); if (_parameter_index < 0 ) _return_type = T_BYTE;
                                  _index++; size = T_BYTE_size; break;
    case JVM_SIGNATURE_CHAR:    do_char(); if (_parameter_index < 0 ) _return_type = T_CHAR;
                                  _index++; size = T_CHAR_size; break;
    case JVM_SIGNATURE_DOUBLE:  do_double(); if (_parameter_index < 0 ) _return_type = T_DOUBLE;
                                  _index++; size = T_DOUBLE_size; break;
    case JVM_SIGNATURE_FLOAT:   do_float(); if (_parameter_index < 0 ) _return_type = T_FLOAT;
                                  _index++; size = T_FLOAT_size; break;
    case JVM_SIGNATURE_INT:     do_int(); if (_parameter_index < 0 ) _return_type = T_INT;
                                  _index++; size = T_INT_size; break;
    case JVM_SIGNATURE_LONG:    do_long(); if (_parameter_index < 0 ) _return_type = T_LONG;
                                  _index++; size = T_LONG_size; break;
    case JVM_SIGNATURE_SHORT:   do_short(); if (_parameter_index < 0 ) _return_type = T_SHORT;
                                  _index++; size = T_SHORT_size; break;
    case JVM_SIGNATURE_BOOLEAN: do_bool(); if (_parameter_index < 0 ) _return_type = T_BOOLEAN;
                                  _index++; size = T_BOOLEAN_size; break;
    case JVM_SIGNATURE_VOID:    do_void(); if (_parameter_index < 0 ) _return_type = T_VOID;
                                  _index++; size = T_VOID_size; break;
    case JVM_SIGNATURE_CLASS:
      { int begin = ++_index;
        Symbol* sig = _signature;
        while (sig->char_at(_index++) != JVM_SIGNATURE_ENDCLASS) ;
        do_object(begin, _index);
      }
      if (_parameter_index < 0 ) _return_type = T_OBJECT;
      size = T_OBJECT_size;
      break;
    case JVM_SIGNATURE_ARRAY:
      { int begin = ++_index;
        Symbol* sig = _signature;
        while (sig->char_at(_index) == JVM_SIGNATURE_ARRAY) {
          _index++;
        }
        if (sig->char_at(_index) == JVM_SIGNATURE_CLASS) {
          while (sig->char_at(_index++) != JVM_SIGNATURE_ENDCLASS) ;
        } else {
          _index++;
        }
        do_array(begin, _index);
       if (_parameter_index < 0 ) _return_type = T_ARRAY;
      }
      size = T_ARRAY_size;
      break;
    default:
      ShouldNotReachHere();
      break;
  }
  assert(size >= 0, "size must be set");
  return size;
}


void SignatureIterator::check_signature_end() {
  if (_index < _signature->utf8_length()) {
    tty->print_cr("too many chars in signature");
    _signature->print_value_on(tty);
    tty->print_cr(" @ %d", _index);
  }
}


void SignatureIterator::iterate_parameters() {
  // Parse parameters
  _index = 0;
  _parameter_index = 0;
  expect(JVM_SIGNATURE_FUNC);
  while (_signature->char_at(_index) != JVM_SIGNATURE_ENDFUNC) _parameter_index += parse_type();
  expect(JVM_SIGNATURE_ENDFUNC);
  _parameter_index = 0;
}

// Optimized version of iterate_parameters when fingerprint is known
void SignatureIterator::iterate_parameters( uint64_t fingerprint ) {
  uint64_t saved_fingerprint = fingerprint;

  // Check for too many arguments
  if (fingerprint == (uint64_t)CONST64(-1)) {
    SignatureIterator::iterate_parameters();
    return;
  }

  assert(fingerprint, "Fingerprint should not be 0");

  _parameter_index = 0;
  fingerprint = fingerprint >> (static_feature_size + result_feature_size);
  while ( 1 ) {
    switch ( fingerprint & parameter_feature_mask ) {
      case bool_parm:
        do_bool();
        _parameter_index += T_BOOLEAN_size;
        break;
      case byte_parm:
        do_byte();
        _parameter_index += T_BYTE_size;
        break;
      case char_parm:
        do_char();
        _parameter_index += T_CHAR_size;
        break;
      case short_parm:
        do_short();
        _parameter_index += T_SHORT_size;
        break;
      case int_parm:
        do_int();
        _parameter_index += T_INT_size;
        break;
      case obj_parm:
        do_object(0, 0);
        _parameter_index += T_OBJECT_size;
        break;
      case long_parm:
        do_long();
        _parameter_index += T_LONG_size;
        break;
      case float_parm:
        do_float();
        _parameter_index += T_FLOAT_size;
        break;
      case double_parm:
        do_double();
        _parameter_index += T_DOUBLE_size;
        break;
      case done_parm:
        return;
      default:
        tty->print_cr("*** parameter is " UINT64_FORMAT, fingerprint & parameter_feature_mask);
        tty->print_cr("*** fingerprint is " PTR64_FORMAT, saved_fingerprint);
        ShouldNotReachHere();
        break;
    }
    fingerprint >>= parameter_feature_size;
  }
}


void SignatureIterator::iterate_returntype() {
  // Ignore parameters
  _index = 0;
  expect(JVM_SIGNATURE_FUNC);
  Symbol* sig = _signature;
  // Need to skip over each type in the signature's argument list until a
  // closing ')' is found., then get the return type.  We cannot just scan
  // for the first ')' because ')' is a legal character in a type name.
  while (sig->char_at(_index) != JVM_SIGNATURE_ENDFUNC) {
    switch(sig->char_at(_index)) {
      case JVM_SIGNATURE_BYTE:
      case JVM_SIGNATURE_CHAR:
      case JVM_SIGNATURE_DOUBLE:
      case JVM_SIGNATURE_FLOAT:
      case JVM_SIGNATURE_INT:
      case JVM_SIGNATURE_LONG:
      case JVM_SIGNATURE_SHORT:
      case JVM_SIGNATURE_BOOLEAN:
      case JVM_SIGNATURE_VOID:
        {
          _index++;
        }
        break;
      case JVM_SIGNATURE_CLASS:
        {
          while (sig->char_at(_index++) != JVM_SIGNATURE_ENDCLASS) ;
        }
        break;
      case JVM_SIGNATURE_ARRAY:
        {
          while (sig->char_at(++_index) == JVM_SIGNATURE_ARRAY) ;
          if (sig->char_at(_index) == JVM_SIGNATURE_CLASS) {
            while (sig->char_at(_index++) != JVM_SIGNATURE_ENDCLASS) ;
          } else {
            _index++;
          }
        }
        break;
      default:
        ShouldNotReachHere();
        break;
    }
  }
  expect(JVM_SIGNATURE_ENDFUNC);
  // Parse return type
  _parameter_index = -1;
  parse_type();
  check_signature_end();
  _parameter_index = 0;
}


void SignatureIterator::iterate() {
  // Parse parameters
  _parameter_index = 0;
  _index = 0;
  expect(JVM_SIGNATURE_FUNC);
  while (_signature->char_at(_index) != JVM_SIGNATURE_ENDFUNC) _parameter_index += parse_type();
  expect(JVM_SIGNATURE_ENDFUNC);
  // Parse return type
  _parameter_index = -1;
  parse_type();
  check_signature_end();
  _parameter_index = 0;
}


// Implementation of SignatureStream
SignatureStream::SignatureStream(Symbol* signature, bool is_method) :
                   _signature(signature), _at_return_type(false), _previous_name(NULL), _names(NULL) {
  _begin = _end = (is_method ? 1 : 0);  // skip first '(' in method signatures
  next();
}

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

bool SignatureStream::is_done() const {
  return _end > _signature->utf8_length();
}


void SignatureStream::next_non_primitive(int t) {
  switch (t) {
    case JVM_SIGNATURE_CLASS: {
      _type = T_OBJECT;
      Symbol* sig = _signature;
      while (sig->char_at(_end++) != JVM_SIGNATURE_ENDCLASS);
      break;
    }
    case JVM_SIGNATURE_ARRAY: {
      _type = T_ARRAY;
      Symbol* sig = _signature;
      char c = sig->char_at(_end);
      while ('0' <= c && c <= '9') c = sig->char_at(_end++);
      while (sig->char_at(_end) == JVM_SIGNATURE_ARRAY) {
        _end++;
        c = sig->char_at(_end);
        while ('0' <= c && c <= '9') c = sig->char_at(_end++);
      }
      switch(sig->char_at(_end)) {
        case JVM_SIGNATURE_BYTE:
        case JVM_SIGNATURE_CHAR:
        case JVM_SIGNATURE_DOUBLE:
        case JVM_SIGNATURE_FLOAT:
        case JVM_SIGNATURE_INT:
        case JVM_SIGNATURE_LONG:
        case JVM_SIGNATURE_SHORT:
        case JVM_SIGNATURE_BOOLEAN:_end++; break;
        default: {
          while (sig->char_at(_end++) != JVM_SIGNATURE_ENDCLASS);
          break;
        }
      }
      break;
    }
    case JVM_SIGNATURE_ENDFUNC: _end++; next(); _at_return_type = true; break;
    default : ShouldNotReachHere();
  }
}


bool SignatureStream::is_object() const {
  return _type == T_OBJECT
      || _type == T_ARRAY;
}

bool SignatureStream::is_array() const {
  return _type == T_ARRAY;
}

Symbol* SignatureStream::as_symbol() {
  // Create a symbol from for string _begin _end
  int begin = _begin;
  int end   = _end;

  if (   _signature->char_at(_begin) == JVM_SIGNATURE_CLASS
      && _signature->char_at(_end-1) == JVM_SIGNATURE_ENDCLASS) {
    begin++;
    end--;
  }

  const char* symbol_chars = (const char*)_signature->base() + begin;
  int len = end - begin;

  // Quick check for common symbols in signatures
  assert((vmSymbols::java_lang_String()->utf8_length() == 16 && vmSymbols::java_lang_Object()->utf8_length() == 16), "sanity");
  if (len == 16 &&
      strncmp(symbol_chars, "java/lang/", 10) == 0) {
    if (strncmp("String", symbol_chars + 10, 6) == 0) {
      return vmSymbols::java_lang_String();
    } else if (strncmp("Object", symbol_chars + 10, 6) == 0) {
      return vmSymbols::java_lang_Object();
    }
  }

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

  // Save names for cleaning up reference count at the end of
  // SignatureStream scope.
  name = SymbolTable::new_symbol(symbol_chars, len);
  if (!name->is_permanent()) {
    if (_names == NULL) {
      _names = new GrowableArray<Symbol*>(10);
    }
    _names->push(name);  // save new symbol for decrementing later
  }
  _previous_name = name;
  return name;
}

Klass* SignatureStream::as_klass(Handle class_loader, Handle protection_domain,
                                 FailureMode failure_mode, TRAPS) {
  if (!is_object())  return NULL;
  Symbol* name = as_symbol();
  if (failure_mode == ReturnNull) {
    return SystemDictionary::resolve_or_null(name, class_loader, protection_domain, THREAD);
  } else {
    bool throw_error = (failure_mode == NCDFError);
    return SystemDictionary::resolve_or_fail(name, class_loader, protection_domain, throw_error, THREAD);
  }
}

oop SignatureStream::as_java_mirror(Handle class_loader, Handle protection_domain,
                                    FailureMode failure_mode, TRAPS) {
  if (!is_object())
    return Universe::java_mirror(type());
  Klass* klass = as_klass(class_loader, protection_domain, failure_mode, CHECK_NULL);
  if (klass == NULL)  return NULL;
  return klass->java_mirror();
}

Symbol* SignatureStream::as_symbol_or_null() {
  // Create a symbol from for string _begin _end
  ResourceMark rm;

  int begin = _begin;
  int end   = _end;

  if (   _signature->char_at(_begin) == JVM_SIGNATURE_CLASS
      && _signature->char_at(_end-1) == JVM_SIGNATURE_ENDCLASS) {
    begin++;
    end--;
  }

  char* buffer = NEW_RESOURCE_ARRAY(char, end - begin);
  for (int index = begin; index < end; index++) {
    buffer[index - begin] = _signature->char_at(index);
  }
  Symbol* result = SymbolTable::probe(buffer, end - begin);
  return result;
}

int SignatureStream::reference_parameter_count() {
  int args_count = 0;
  for ( ; !at_return_type(); next()) {
    if (is_object()) {
      args_count++;
    }
  }
  return args_count;
}

#ifdef ASSERT
bool SignatureVerifier::is_valid_method_signature(Symbol* sig) {
  const char* method_sig = (const char*)sig->bytes();
  ssize_t len = sig->utf8_length();
  ssize_t index = 0;
  if (method_sig != NULL && len > 1 && method_sig[index] == JVM_SIGNATURE_FUNC) {
    ++index;
    while (index < len && method_sig[index] != JVM_SIGNATURE_ENDFUNC) {
      ssize_t res = is_valid_type(&method_sig[index], len - index);
      if (res == -1) {
        return false;
      } else {
        index += res;
      }
    }
    if (index < len && method_sig[index] == JVM_SIGNATURE_ENDFUNC) {
      // check the return type
      ++index;
      return (is_valid_type(&method_sig[index], len - index) == (len - index));
    }
  }
  return false;
}

bool SignatureVerifier::is_valid_type_signature(Symbol* sig) {
  const char* type_sig = (const char*)sig->bytes();
  ssize_t len = sig->utf8_length();
  return (type_sig != NULL && len >= 1 &&
          (is_valid_type(type_sig, len) == len));
}

// Checks to see if the type (not to go beyond 'limit') refers to a valid type.
// Returns -1 if it is not, or the index of the next character that is not part
// of the type.  The type encoding may end before 'limit' and that's ok.
ssize_t SignatureVerifier::is_valid_type(const char* type, ssize_t limit) {
  ssize_t index = 0;

  // Iterate over any number of array dimensions
  while (index < limit && type[index] == JVM_SIGNATURE_ARRAY) ++index;
  if (index >= limit) {
    return -1;
  }
  switch (type[index]) {
    case JVM_SIGNATURE_BYTE:
    case JVM_SIGNATURE_CHAR:
    case JVM_SIGNATURE_DOUBLE:
    case JVM_SIGNATURE_FLOAT:
    case JVM_SIGNATURE_INT:
    case JVM_SIGNATURE_LONG:
    case JVM_SIGNATURE_SHORT:
    case JVM_SIGNATURE_BOOLEAN:
    case JVM_SIGNATURE_VOID:
      return index + 1;
    case JVM_SIGNATURE_CLASS:
      for (index = index + 1; index < limit; ++index) {
        char c = type[index];
        switch (c) {
          case JVM_SIGNATURE_ENDCLASS:
            return index + 1;
          case '\0': case JVM_SIGNATURE_DOT: case JVM_SIGNATURE_ARRAY:
            return -1;
          default: ; // fall through
        }
      }
      // fall through
    default: ; // fall through
  }
  return -1;
}
#endif // ASSERT