aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: * aoqi@0: */ aoqi@0: aoqi@0: #include "precompiled.hpp" aoqi@0: #include "classfile/symbolTable.hpp" aoqi@0: #include "classfile/systemDictionary.hpp" aoqi@0: #include "memory/oopFactory.hpp" aoqi@0: #include "oops/instanceKlass.hpp" aoqi@0: #include "oops/oop.inline.hpp" aoqi@0: #include "oops/symbol.hpp" aoqi@0: #include "oops/typeArrayKlass.hpp" aoqi@0: #include "runtime/signature.hpp" aoqi@0: aoqi@0: PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC aoqi@0: aoqi@0: // Implementation of SignatureIterator aoqi@0: aoqi@0: // Signature syntax: aoqi@0: // aoqi@0: // Signature = "(" {Parameter} ")" ReturnType. aoqi@0: // Parameter = FieldType. aoqi@0: // ReturnType = FieldType | "V". aoqi@0: // FieldType = "B" | "C" | "D" | "F" | "I" | "J" | "S" | "Z" | "L" ClassName ";" | "[" FieldType. aoqi@0: // ClassName = string. aoqi@0: aoqi@0: aoqi@0: SignatureIterator::SignatureIterator(Symbol* signature) { aoqi@0: _signature = signature; aoqi@0: _parameter_index = 0; aoqi@0: } aoqi@0: aoqi@0: void SignatureIterator::expect(char c) { aoqi@0: if (_signature->byte_at(_index) != c) fatal(err_msg("expecting %c", c)); aoqi@0: _index++; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void SignatureIterator::skip_optional_size() { aoqi@0: Symbol* sig = _signature; aoqi@0: char c = sig->byte_at(_index); aoqi@0: while ('0' <= c && c <= '9') c = sig->byte_at(++_index); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: int SignatureIterator::parse_type() { aoqi@0: // Note: This function could be simplified by using "return T_XXX_size;" aoqi@0: // instead of the assignment and the break statements. However, it aoqi@0: // seems that the product build for win32_i486 with MS VC++ 6.0 doesn't aoqi@0: // work (stack underflow for some tests) - this seems to be a VC++ 6.0 aoqi@0: // compiler bug (was problem - gri 4/27/2000). aoqi@0: int size = -1; aoqi@0: switch(_signature->byte_at(_index)) { aoqi@0: case 'B': do_byte (); if (_parameter_index < 0 ) _return_type = T_BYTE; aoqi@0: _index++; size = T_BYTE_size ; break; aoqi@0: case 'C': do_char (); if (_parameter_index < 0 ) _return_type = T_CHAR; aoqi@0: _index++; size = T_CHAR_size ; break; aoqi@0: case 'D': do_double(); if (_parameter_index < 0 ) _return_type = T_DOUBLE; aoqi@0: _index++; size = T_DOUBLE_size ; break; aoqi@0: case 'F': do_float (); if (_parameter_index < 0 ) _return_type = T_FLOAT; aoqi@0: _index++; size = T_FLOAT_size ; break; aoqi@0: case 'I': do_int (); if (_parameter_index < 0 ) _return_type = T_INT; aoqi@0: _index++; size = T_INT_size ; break; aoqi@0: case 'J': do_long (); if (_parameter_index < 0 ) _return_type = T_LONG; aoqi@0: _index++; size = T_LONG_size ; break; aoqi@0: case 'S': do_short (); if (_parameter_index < 0 ) _return_type = T_SHORT; aoqi@0: _index++; size = T_SHORT_size ; break; aoqi@0: case 'Z': do_bool (); if (_parameter_index < 0 ) _return_type = T_BOOLEAN; aoqi@0: _index++; size = T_BOOLEAN_size; break; aoqi@0: case 'V': do_void (); if (_parameter_index < 0 ) _return_type = T_VOID; aoqi@0: _index++; size = T_VOID_size; ; break; aoqi@0: case 'L': aoqi@0: { int begin = ++_index; aoqi@0: Symbol* sig = _signature; aoqi@0: while (sig->byte_at(_index++) != ';') ; aoqi@0: do_object(begin, _index); aoqi@0: } aoqi@0: if (_parameter_index < 0 ) _return_type = T_OBJECT; aoqi@0: size = T_OBJECT_size; aoqi@0: break; aoqi@0: case '[': aoqi@0: { int begin = ++_index; aoqi@0: skip_optional_size(); aoqi@0: Symbol* sig = _signature; aoqi@0: while (sig->byte_at(_index) == '[') { aoqi@0: _index++; aoqi@0: skip_optional_size(); aoqi@0: } aoqi@0: if (sig->byte_at(_index) == 'L') { aoqi@0: while (sig->byte_at(_index++) != ';') ; aoqi@0: } else { aoqi@0: _index++; aoqi@0: } aoqi@0: do_array(begin, _index); aoqi@0: if (_parameter_index < 0 ) _return_type = T_ARRAY; aoqi@0: } aoqi@0: size = T_ARRAY_size; aoqi@0: break; aoqi@0: default: aoqi@0: ShouldNotReachHere(); aoqi@0: break; aoqi@0: } aoqi@0: assert(size >= 0, "size must be set"); aoqi@0: return size; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void SignatureIterator::check_signature_end() { aoqi@0: if (_index < _signature->utf8_length()) { aoqi@0: tty->print_cr("too many chars in signature"); aoqi@0: _signature->print_value_on(tty); aoqi@0: tty->print_cr(" @ %d", _index); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void SignatureIterator::dispatch_field() { aoqi@0: // no '(', just one (field) type aoqi@0: _index = 0; aoqi@0: _parameter_index = 0; aoqi@0: parse_type(); aoqi@0: check_signature_end(); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void SignatureIterator::iterate_parameters() { aoqi@0: // Parse parameters aoqi@0: _index = 0; aoqi@0: _parameter_index = 0; aoqi@0: expect('('); aoqi@0: while (_signature->byte_at(_index) != ')') _parameter_index += parse_type(); aoqi@0: expect(')'); aoqi@0: _parameter_index = 0; aoqi@0: } aoqi@0: aoqi@0: // Optimized version of iterat_parameters when fingerprint is known aoqi@0: void SignatureIterator::iterate_parameters( uint64_t fingerprint ) { aoqi@0: uint64_t saved_fingerprint = fingerprint; aoqi@0: aoqi@0: // Check for too many arguments aoqi@0: if ( fingerprint == UCONST64(-1) ) { aoqi@0: SignatureIterator::iterate_parameters(); aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: assert(fingerprint, "Fingerprint should not be 0"); aoqi@0: aoqi@0: _parameter_index = 0; aoqi@0: fingerprint = fingerprint >> (static_feature_size + result_feature_size); aoqi@0: while ( 1 ) { aoqi@0: switch ( fingerprint & parameter_feature_mask ) { aoqi@0: case bool_parm: aoqi@0: do_bool(); aoqi@0: _parameter_index += T_BOOLEAN_size; aoqi@0: break; aoqi@0: case byte_parm: aoqi@0: do_byte(); aoqi@0: _parameter_index += T_BYTE_size; aoqi@0: break; aoqi@0: case char_parm: aoqi@0: do_char(); aoqi@0: _parameter_index += T_CHAR_size; aoqi@0: break; aoqi@0: case short_parm: aoqi@0: do_short(); aoqi@0: _parameter_index += T_SHORT_size; aoqi@0: break; aoqi@0: case int_parm: aoqi@0: do_int(); aoqi@0: _parameter_index += T_INT_size; aoqi@0: break; aoqi@0: case obj_parm: aoqi@0: do_object(0, 0); aoqi@0: _parameter_index += T_OBJECT_size; aoqi@0: break; aoqi@0: case long_parm: aoqi@0: do_long(); aoqi@0: _parameter_index += T_LONG_size; aoqi@0: break; aoqi@0: case float_parm: aoqi@0: do_float(); aoqi@0: _parameter_index += T_FLOAT_size; aoqi@0: break; aoqi@0: case double_parm: aoqi@0: do_double(); aoqi@0: _parameter_index += T_DOUBLE_size; aoqi@0: break; aoqi@0: case done_parm: aoqi@0: return; aoqi@0: break; aoqi@0: default: aoqi@0: tty->print_cr("*** parameter is %d", fingerprint & parameter_feature_mask); aoqi@0: tty->print_cr("*** fingerprint is " PTR64_FORMAT, saved_fingerprint); aoqi@0: ShouldNotReachHere(); aoqi@0: break; aoqi@0: } aoqi@0: fingerprint >>= parameter_feature_size; aoqi@0: } aoqi@0: _parameter_index = 0; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void SignatureIterator::iterate_returntype() { aoqi@0: // Ignore parameters aoqi@0: _index = 0; aoqi@0: expect('('); aoqi@0: Symbol* sig = _signature; aoqi@0: while (sig->byte_at(_index) != ')') _index++; aoqi@0: expect(')'); aoqi@0: // Parse return type aoqi@0: _parameter_index = -1; aoqi@0: parse_type(); aoqi@0: check_signature_end(); aoqi@0: _parameter_index = 0; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void SignatureIterator::iterate() { aoqi@0: // Parse parameters aoqi@0: _parameter_index = 0; aoqi@0: _index = 0; aoqi@0: expect('('); aoqi@0: while (_signature->byte_at(_index) != ')') _parameter_index += parse_type(); aoqi@0: expect(')'); aoqi@0: // Parse return type aoqi@0: _parameter_index = -1; aoqi@0: parse_type(); aoqi@0: check_signature_end(); aoqi@0: _parameter_index = 0; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // Implementation of SignatureStream aoqi@0: SignatureStream::SignatureStream(Symbol* signature, bool is_method) : aoqi@0: _signature(signature), _at_return_type(false) { aoqi@0: _begin = _end = (is_method ? 1 : 0); // skip first '(' in method signatures aoqi@0: _names = new GrowableArray(10); aoqi@0: next(); aoqi@0: } aoqi@0: aoqi@0: SignatureStream::~SignatureStream() { aoqi@0: // decrement refcount for names created during signature parsing aoqi@0: for (int i = 0; i < _names->length(); i++) { aoqi@0: _names->at(i)->decrement_refcount(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: bool SignatureStream::is_done() const { aoqi@0: return _end > _signature->utf8_length(); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void SignatureStream::next_non_primitive(int t) { aoqi@0: switch (t) { aoqi@0: case 'L': { aoqi@0: _type = T_OBJECT; aoqi@0: Symbol* sig = _signature; aoqi@0: while (sig->byte_at(_end++) != ';'); aoqi@0: break; aoqi@0: } aoqi@0: case '[': { aoqi@0: _type = T_ARRAY; aoqi@0: Symbol* sig = _signature; aoqi@0: char c = sig->byte_at(_end); aoqi@0: while ('0' <= c && c <= '9') c = sig->byte_at(_end++); aoqi@0: while (sig->byte_at(_end) == '[') { aoqi@0: _end++; aoqi@0: c = sig->byte_at(_end); aoqi@0: while ('0' <= c && c <= '9') c = sig->byte_at(_end++); aoqi@0: } aoqi@0: switch(sig->byte_at(_end)) { aoqi@0: case 'B': aoqi@0: case 'C': aoqi@0: case 'D': aoqi@0: case 'F': aoqi@0: case 'I': aoqi@0: case 'J': aoqi@0: case 'S': aoqi@0: case 'Z':_end++; break; aoqi@0: default: { aoqi@0: while (sig->byte_at(_end++) != ';'); aoqi@0: break; aoqi@0: } aoqi@0: } aoqi@0: break; aoqi@0: } aoqi@0: case ')': _end++; next(); _at_return_type = true; break; aoqi@0: default : ShouldNotReachHere(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: bool SignatureStream::is_object() const { aoqi@0: return _type == T_OBJECT aoqi@0: || _type == T_ARRAY; aoqi@0: } aoqi@0: aoqi@0: bool SignatureStream::is_array() const { aoqi@0: return _type == T_ARRAY; aoqi@0: } aoqi@0: aoqi@0: Symbol* SignatureStream::as_symbol(TRAPS) { aoqi@0: // Create a symbol from for string _begin _end aoqi@0: int begin = _begin; aoqi@0: int end = _end; aoqi@0: aoqi@0: if ( _signature->byte_at(_begin) == 'L' aoqi@0: && _signature->byte_at(_end-1) == ';') { aoqi@0: begin++; aoqi@0: end--; aoqi@0: } aoqi@0: aoqi@0: // Save names for cleaning up reference count at the end of aoqi@0: // SignatureStream scope. aoqi@0: Symbol* name = SymbolTable::new_symbol(_signature, begin, end, CHECK_NULL); aoqi@0: _names->push(name); // save new symbol for decrementing later aoqi@0: return name; aoqi@0: } aoqi@0: aoqi@0: Klass* SignatureStream::as_klass(Handle class_loader, Handle protection_domain, aoqi@0: FailureMode failure_mode, TRAPS) { aoqi@0: if (!is_object()) return NULL; aoqi@0: Symbol* name = as_symbol(CHECK_NULL); aoqi@0: if (failure_mode == ReturnNull) { aoqi@0: return SystemDictionary::resolve_or_null(name, class_loader, protection_domain, THREAD); aoqi@0: } else { aoqi@0: bool throw_error = (failure_mode == NCDFError); aoqi@0: return SystemDictionary::resolve_or_fail(name, class_loader, protection_domain, throw_error, THREAD); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: oop SignatureStream::as_java_mirror(Handle class_loader, Handle protection_domain, aoqi@0: FailureMode failure_mode, TRAPS) { aoqi@0: if (!is_object()) aoqi@0: return Universe::java_mirror(type()); aoqi@0: Klass* klass = as_klass(class_loader, protection_domain, failure_mode, CHECK_NULL); aoqi@0: if (klass == NULL) return NULL; aoqi@0: return klass->java_mirror(); aoqi@0: } aoqi@0: aoqi@0: Symbol* SignatureStream::as_symbol_or_null() { aoqi@0: // Create a symbol from for string _begin _end aoqi@0: ResourceMark rm; aoqi@0: aoqi@0: int begin = _begin; aoqi@0: int end = _end; aoqi@0: aoqi@0: if ( _signature->byte_at(_begin) == 'L' aoqi@0: && _signature->byte_at(_end-1) == ';') { aoqi@0: begin++; aoqi@0: end--; aoqi@0: } aoqi@0: aoqi@0: char* buffer = NEW_RESOURCE_ARRAY(char, end - begin); aoqi@0: for (int index = begin; index < end; index++) { aoqi@0: buffer[index - begin] = _signature->byte_at(index); aoqi@0: } aoqi@0: Symbol* result = SymbolTable::probe(buffer, end - begin); aoqi@0: return result; aoqi@0: } aoqi@0: aoqi@0: int SignatureStream::reference_parameter_count() { aoqi@0: int args_count = 0; aoqi@0: for ( ; !at_return_type(); next()) { aoqi@0: if (is_object()) { aoqi@0: args_count++; aoqi@0: } aoqi@0: } aoqi@0: return args_count; aoqi@0: } aoqi@0: aoqi@0: bool SignatureVerifier::is_valid_signature(Symbol* sig) { aoqi@0: const char* signature = (const char*)sig->bytes(); aoqi@0: ssize_t len = sig->utf8_length(); aoqi@0: if (signature == NULL || signature[0] == '\0' || len < 1) { aoqi@0: return false; aoqi@0: } else if (signature[0] == '(') { aoqi@0: return is_valid_method_signature(sig); aoqi@0: } else { aoqi@0: return is_valid_type_signature(sig); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: bool SignatureVerifier::is_valid_method_signature(Symbol* sig) { aoqi@0: const char* method_sig = (const char*)sig->bytes(); aoqi@0: ssize_t len = sig->utf8_length(); aoqi@0: ssize_t index = 0; aoqi@0: if (method_sig != NULL && len > 1 && method_sig[index] == '(') { aoqi@0: ++index; aoqi@0: while (index < len && method_sig[index] != ')') { aoqi@0: ssize_t res = is_valid_type(&method_sig[index], len - index); aoqi@0: if (res == -1) { aoqi@0: return false; aoqi@0: } else { aoqi@0: index += res; aoqi@0: } aoqi@0: } aoqi@0: if (index < len && method_sig[index] == ')') { aoqi@0: // check the return type aoqi@0: ++index; aoqi@0: return (is_valid_type(&method_sig[index], len - index) == (len - index)); aoqi@0: } aoqi@0: } aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: bool SignatureVerifier::is_valid_type_signature(Symbol* sig) { aoqi@0: const char* type_sig = (const char*)sig->bytes(); aoqi@0: ssize_t len = sig->utf8_length(); aoqi@0: return (type_sig != NULL && len >= 1 && aoqi@0: (is_valid_type(type_sig, len) == len)); aoqi@0: } aoqi@0: aoqi@0: // Checks to see if the type (not to go beyond 'limit') refers to a valid type. aoqi@0: // Returns -1 if it is not, or the index of the next character that is not part aoqi@0: // of the type. The type encoding may end before 'limit' and that's ok. aoqi@0: ssize_t SignatureVerifier::is_valid_type(const char* type, ssize_t limit) { aoqi@0: ssize_t index = 0; aoqi@0: aoqi@0: // Iterate over any number of array dimensions aoqi@0: while (index < limit && type[index] == '[') ++index; aoqi@0: if (index >= limit) { aoqi@0: return -1; aoqi@0: } aoqi@0: switch (type[index]) { aoqi@0: case 'B': case 'C': case 'D': case 'F': case 'I': aoqi@0: case 'J': case 'S': case 'Z': case 'V': aoqi@0: return index + 1; aoqi@0: case 'L': aoqi@0: for (index = index + 1; index < limit; ++index) { aoqi@0: char c = type[index]; aoqi@0: if (c == ';') { aoqi@0: return index + 1; aoqi@0: } aoqi@0: if (invalid_name_char(c)) { aoqi@0: return -1; aoqi@0: } aoqi@0: } aoqi@0: // fall through aoqi@0: default: ; // fall through aoqi@0: } aoqi@0: return -1; aoqi@0: } aoqi@0: aoqi@0: bool SignatureVerifier::invalid_name_char(char c) { aoqi@0: switch (c) { aoqi@0: case '\0': case '.': case ';': case '[': aoqi@0: return true; aoqi@0: default: aoqi@0: return false; aoqi@0: } aoqi@0: }