view src/share/vm/runtime/signature.cpp @ 1091:6aa7255741f3

6906727: UseCompressedOops: some card-marking fixes related to object arrays Summary: Introduced a new write_ref_array(HeapWords* start, size_t count) method that does the requisite MemRegion range calculation so (some of the) clients of the erstwhile write_ref_array(MemRegion mr) do not need to worry. This removed all external uses of array_size(), which was also simplified and made private. Asserts were added to catch other possible issues. Further, less essential, fixes stemming from this investigation are deferred to CR 6904516 (to follow shortly in hs17). Reviewed-by: kvn, coleenp, jmasa
author ysr
date Thu, 03 Dec 2009 15:01:57 -0800
parents a61af66fc99e
children f03d0a26bf83 2ffde6cfe049
line wrap: on
line source

/*
 * Copyright 1997-2006 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 *
 */

# include "incls/_precompiled.incl"
# include "incls/_signature.cpp.incl"


// 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(symbolHandle signature) {
  assert(signature->is_symbol(), "not a symbol");
  _signature       = signature;
  _parameter_index = 0;
}

// Overloaded version called without handle
SignatureIterator::SignatureIterator(symbolOop signature) {
  symbolHandle sh(Thread::current(), signature);
  _signature       = sh;
  _parameter_index = 0;
}

SignatureIterator::SignatureIterator(Thread *thread, symbolOop signature) {
  symbolHandle sh(thread, signature);
  _signature       = sh;
  _parameter_index = 0;
}

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


void SignatureIterator::skip_optional_size() {
  symbolOop sig = _signature();
  char c = sig->byte_at(_index);
  while ('0' <= c && c <= '9') c = sig->byte_at(++_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->byte_at(_index)) {
    case 'B': do_byte  (); if (_parameter_index < 0 ) _return_type = T_BYTE;
              _index++; size = T_BYTE_size   ; break;
    case 'C': do_char  (); if (_parameter_index < 0 ) _return_type = T_CHAR;
              _index++; size = T_CHAR_size   ; break;
    case 'D': do_double(); if (_parameter_index < 0 ) _return_type = T_DOUBLE;
              _index++; size = T_DOUBLE_size ; break;
    case 'F': do_float (); if (_parameter_index < 0 ) _return_type = T_FLOAT;
              _index++; size = T_FLOAT_size  ; break;
    case 'I': do_int   (); if (_parameter_index < 0 ) _return_type = T_INT;
              _index++; size = T_INT_size    ; break;
    case 'J': do_long  (); if (_parameter_index < 0 ) _return_type = T_LONG;
              _index++; size = T_LONG_size   ; break;
    case 'S': do_short (); if (_parameter_index < 0 ) _return_type = T_SHORT;
              _index++; size = T_SHORT_size  ; break;
    case 'Z': do_bool  (); if (_parameter_index < 0 ) _return_type = T_BOOLEAN;
              _index++; size = T_BOOLEAN_size; break;
    case 'V': do_void  (); if (_parameter_index < 0 ) _return_type = T_VOID;
              _index++; size = T_VOID_size;  ; break;
    case 'L':
      { int begin = ++_index;
        symbolOop sig = _signature();
        while (sig->byte_at(_index++) != ';') ;
        do_object(begin, _index);
      }
      if (_parameter_index < 0 ) _return_type = T_OBJECT;
      size = T_OBJECT_size;
      break;
    case '[':
      { int begin = ++_index;
        skip_optional_size();
        symbolOop sig = _signature();
        while (sig->byte_at(_index) == '[') {
          _index++;
          skip_optional_size();
        }
        if (sig->byte_at(_index) == 'L') {
          while (sig->byte_at(_index++) != ';') ;
        } 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::dispatch_field() {
  // no '(', just one (field) type
  _index = 0;
  _parameter_index = 0;
  parse_type();
  check_signature_end();
}


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

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

  // Check for too many arguments
  if ( fingerprint == UCONST64(-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;
        break;
      default:
        tty->print_cr("*** parameter is %d", fingerprint & parameter_feature_mask);
        tty->print_cr("*** fingerprint is " PTR64_FORMAT, saved_fingerprint);
        ShouldNotReachHere();
        break;
    }
    fingerprint >>= parameter_feature_size;
  }
  _parameter_index = 0;
}


void SignatureIterator::iterate_returntype() {
  // Ignore parameters
  _index = 0;
  expect('(');
  symbolOop sig = _signature();
  while (sig->byte_at(_index) != ')') _index++;
  expect(')');
  // 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('(');
  while (_signature->byte_at(_index) != ')') _parameter_index += parse_type();
  expect(')');
  // Parse return type
  _parameter_index = -1;
  parse_type();
  check_signature_end();
  _parameter_index = 0;
}


// Implementation of SignatureStream

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


void SignatureStream::next_non_primitive(int t) {
  switch (t) {
    case 'L': {
      _type = T_OBJECT;
      symbolOop sig = _signature();
      while (sig->byte_at(_end++) != ';');
      break;
    }
    case '[': {
      _type = T_ARRAY;
      symbolOop sig = _signature();
      char c = sig->byte_at(_end);
      while ('0' <= c && c <= '9') c = sig->byte_at(_end++);
      while (sig->byte_at(_end) == '[') {
        _end++;
        c = sig->byte_at(_end);
        while ('0' <= c && c <= '9') c = sig->byte_at(_end++);
      }
      switch(sig->byte_at(_end)) {
        case 'B':
        case 'C':
        case 'D':
        case 'F':
        case 'I':
        case 'J':
        case 'S':
        case 'Z':_end++; break;
        default: {
          while (sig->byte_at(_end++) != ';');
          break;
        }
      }
      break;
    }
    case ')': _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;
}

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

  if (   _signature()->byte_at(_begin) == 'L'
      && _signature()->byte_at(_end-1) == ';') {
    begin++;
    end--;
  }

  symbolOop result = oopFactory::new_symbol(_signature, begin, end, CHECK_NULL);
  return result;
}


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

  int begin = _begin;
  int end   = _end;

  if (   _signature()->byte_at(_begin) == 'L'
      && _signature()->byte_at(_end-1) == ';') {
    begin++;
    end--;
  }

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

bool SignatureVerifier::is_valid_signature(symbolHandle sig) {
  const char* signature = (const char*)sig->bytes();
  ssize_t len = sig->utf8_length();
  if (signature == NULL || signature[0] == '\0' || len < 1) {
    return false;
  } else if (signature[0] == '(') {
    return is_valid_method_signature(sig);
  } else {
    return is_valid_type_signature(sig);
  }
}

bool SignatureVerifier::is_valid_method_signature(symbolHandle 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] == '(') {
    ++index;
    while (index < len && method_sig[index] != ')') {
      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] == ')') {
      // check the return type
      ++index;
      return (is_valid_type(&method_sig[index], len - index) == (len - index));
    }
  }
  return false;
}

bool SignatureVerifier::is_valid_type_signature(symbolHandle 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] == '[') ++index;
  if (index >= limit) {
    return -1;
  }
  switch (type[index]) {
    case 'B': case 'C': case 'D': case 'F': case 'I':
    case 'J': case 'S': case 'Z': case 'V':
      return index + 1;
    case 'L':
      for (index = index + 1; index < limit; ++index) {
        char c = type[index];
        if (c == ';') {
          return index + 1;
        }
        if (invalid_name_char(c)) {
          return -1;
        }
      }
      // fall through
    default: ; // fall through
  }
  return -1;
}

bool SignatureVerifier::invalid_name_char(char c) {
  switch (c) {
    case '\0': case '.': case ';': case '[':
      return true;
    default:
      return false;
  }
}