/* * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, Azul Systems, 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *
*/
// Static routines and parsing loops for processing field and method // descriptors. In the HotSpot sources we call them "signatures". // // A SignatureStream iterates over a Java descriptor (or parts of it). // The syntax is documented in the Java Virtual Machine Specification, // section 4.3. // // The syntax may be summarized as follows: // // MethodType: '(' {FieldType}* ')' (FieldType | 'V') // FieldType: PrimitiveType | ObjectType | ArrayType // PrimitiveType: 'B' | 'C' | 'D' | 'F' | 'I' | 'J' | 'S' | 'Z' // ObjectType: 'L' ClassName ';' | ArrayType // ArrayType: '[' FieldType // ClassName: {UnqualifiedName '/'}* UnqualifiedName // UnqualifiedName: NameChar {NameChar}* // NameChar: ANY_CHAR_EXCEPT('/' | '.' | ';' | '[') // // All of the concrete characters in the above grammar are given // standard manifest constant names of the form JVM_SIGNATURE_x. // Executable code uses these constant names in preference to raw // character constants. Comments and assertion code sometimes use // the raw character constants for brevity. // // The primitive field types (like 'I') correspond 1-1 with type codes // (like T_INT) which form part of the specification of the 'newarray' // instruction (JVMS 6.5, section on newarray). These type codes are // widely used in the HotSpot code. They are joined by ad hoc codes // like T_OBJECT and T_ARRAY (defined in HotSpot but not in the JVMS) // so that each "basic type" of field descriptor (or void return type) // has a corresponding T_x code. Thus, while T_x codes play a very // minor role in the JVMS, they play a major role in the HotSpot // sources. There are fewer than 16 such "basic types", so they fit // nicely into bitfields. // // The syntax of ClassName overlaps slightly with the descriptor // syntaxes. The strings "I" and "(I)V" are both class names // *and* descriptors. If a class name contains any character other // than "BCDFIJSZ()V" it cannot be confused with a descriptor. // Class names inside of descriptors are always contained in an // "envelope" syntax which starts with 'L' and ends with ';'. // // As a confounding factor, array types report their type name strings // in descriptor format. These name strings are easy to recognize, // since they begin with '['. For this reason some API points on // HotSpot look for array descriptors as well as proper class names. // // For historical reasons some API points that accept class names and // array names also look for class names wrapped inside an envelope // (like "LFoo;") and unwrap them on the fly (to a name like "Foo").
class Signature : AllStatic { private: staticbool is_valid_array_signature(const Symbol* sig);
public:
// Returns the basic type of a field signature (or T_VOID for "V"). // Assumes the signature is a valid field descriptor. // Do not apply this function to class names or method signatures. static BasicType basic_type(const Symbol* signature) { return basic_type(signature->char_at(0));
}
// Returns T_ILLEGAL for an illegal signature char. static BasicType basic_type(int ch);
// Assuming it is either a class name or signature, // determine if it in fact is an array descriptor. staticbool is_array(const Symbol* signature) { return (signature->utf8_length() > 1 &&
signature->char_at(0) == JVM_SIGNATURE_ARRAY &&
is_valid_array_signature(signature));
}
// Assuming it is either a class name or signature, // determine if it contains a class name plus ';'. staticbool has_envelope(const Symbol* signature) { return ((signature->utf8_length() > 0) &&
signature->ends_with(JVM_SIGNATURE_ENDCLASS) &&
has_envelope(signature->char_at(0)));
}
// Determine if this signature char introduces an // envelope, which is a class name plus ';'. staticbool has_envelope(char signature_char) { return (signature_char == JVM_SIGNATURE_CLASS);
}
// Assuming has_envelope is true, return the symbol // inside the envelope, by stripping 'L' and ';'. // Caller is responsible for decrementing the newly created // Symbol's refcount, use TempNewSymbol. static Symbol* strip_envelope(const Symbol* signature);
// Assuming it's either a field or method descriptor, determine // whether it is in fact a method descriptor: staticbool is_method(const Symbol* signature) { return signature->starts_with(JVM_SIGNATURE_FUNC);
}
// Assuming it's a method signature, determine if it must // return void. staticbool is_void_method(const Symbol* signature) {
assert(is_method(signature), "signature is not for a method"); return signature->ends_with(JVM_SIGNATURE_VOID);
}
};
// A SignatureIterator uses a SignatureStream to produce BasicType // results, discarding class names. This means it can be accelerated // using a fingerprint mechanism, in many cases, without loss of type // information. The FingerPrinter class computes and caches this // reduced information for faster iteration.
class SignatureIterator: public ResourceObj { public: typedef uint64_t fingerprint_t;
protected:
Symbol* _signature; // the signature to iterate over
BasicType _return_type;
fingerprint_t _fingerprint;
public: // Definitions used in generating and iterating the // bit field form of the signature generated by the // Fingerprinter. enum {
fp_static_feature_size = 1,
fp_is_static_bit = 1,
fp_parameters_done = 0, // marker for end of parameters (must be zero)
// Parameters take up full wordsize, minus the result and static bit fields. // Since fp_parameters_done is zero, termination field arises from shifting // in zero bits, and therefore occupies no extra space. // The sentinel value is all-zero-bits, which is impossible for a true // fingerprint, since at least the result field will be non-zero.
fp_max_size_of_parameters = ((BitsPerLong
- (fp_result_feature_size + fp_static_feature_size))
/ fp_parameter_feature_size)
};
// Sentinel values are zero and not-zero (-1). // No need to protect the sign bit, since every valid return type is non-zero // (even T_VOID), and there are no valid parameter fields which are 0xF (T_VOID). static fingerprint_t zero_fingerprint() { return (fingerprint_t)0; } static fingerprint_t overflow_fingerprint() { return ~(fingerprint_t)0; } staticbool fp_is_valid(fingerprint_t fingerprint) { return (fingerprint != zero_fingerprint()) && (fingerprint != overflow_fingerprint());
}
// If the fingerprint is present, we can use an accelerated loop. void set_fingerprint(fingerprint_t fingerprint);
// Returns the set fingerprint, or zero_fingerprint() // if none has been set already.
fingerprint_t fingerprint() const { return _fingerprint; }
// Iteration // Hey look: There are no virtual methods in this class. // So how is it customized? By calling do_parameters_on // an object which answers to "do_type(BasicType)". // By convention, this object is in the subclass // itself, so the call is "do_parameters_on(this)". // The effect of this is to inline the parsing loop // everywhere "do_parameters_on" is called. // If there is a valid fingerprint in the object, // an improved loop is called which just unpacks the // bitfields from the fingerprint. Otherwise, the // symbol is parsed. template<typename T> inlinevoid do_parameters_on(T* callback); // iterates over parameters only
BasicType return_type(); // computes the value on the fly if necessary
// Specialized SignatureIterator: Used to compute the argument size.
class ArgumentSizeComputer: public SignatureIterator { private: int _size; friendclass SignatureIterator; // so do_parameters_on can call do_type void do_type(BasicType type) { _size += parameter_type_word_count(type); } public:
ArgumentSizeComputer(Symbol* signature); int size() { return _size; }
};
class ArgumentCount: public SignatureIterator { private: int _size; friendclass SignatureIterator; // so do_parameters_on can call do_type void do_type(BasicType type) { _size++; } public:
ArgumentCount(Symbol* signature); int size() { return _size; }
};
class ReferenceArgumentCount: public SignatureIterator { private: int _refs; friendclass SignatureIterator; // so do_parameters_on can call do_type void do_type(BasicType type) { if (is_reference_type(type)) _refs++; } public:
ReferenceArgumentCount(Symbol* signature); int count() { return _refs; }
};
// Specialized SignatureIterator: Used to compute the result type.
class ResultTypeFinder: public SignatureIterator { public:
BasicType type() { return return_type(); }
ResultTypeFinder(Symbol* signature) : SignatureIterator(signature) { }
};
// Fingerprinter computes a unique ID for a given method. The ID // is a bitvector characterizing the methods signature (incl. the receiver). class Fingerprinter: public SignatureIterator { private:
fingerprint_t _accumulator; int _param_size; int _stack_arg_slots; int _shift_count; const Method* _method;
// Specialized SignatureIterator: Used for native call purposes
class NativeSignatureIterator: public SignatureIterator { private:
methodHandle _method; // We need separate JNI and Java offset values because in 64 bit mode, // the argument offsets are not in sync with the Java stack. // For example a long takes up 1 "C" stack entry but 2 Java stack entries. int _offset; // The java stack offset int _prepended; // number of prepended JNI parameters (1 JNIEnv, plus 1 mirror if static) int _jni_offset; // the current parameter offset, starting with 0
friendclass SignatureIterator; // so do_parameters_on can call do_type void do_type(BasicType type) { switch (type) { case T_BYTE: case T_BOOLEAN:
pass_byte(); _jni_offset++; _offset++; break; case T_CHAR: case T_SHORT:
pass_short(); _jni_offset++; _offset++; break; case T_INT:
pass_int(); _jni_offset++; _offset++; break; case T_FLOAT:
pass_float(); _jni_offset++; _offset++; break; case T_DOUBLE: { int jni_offset = LP64_ONLY(1) NOT_LP64(2);
pass_double(); _jni_offset += jni_offset; _offset += 2; break;
} case T_LONG: { int jni_offset = LP64_ONLY(1) NOT_LP64(2);
pass_long(); _jni_offset += jni_offset; _offset += 2; break;
} case T_ARRAY: case T_OBJECT:
pass_object(); _jni_offset++; _offset++; break; default:
ShouldNotReachHere();
}
}
// iterate() calls the 3 virtual methods according to the following invocation syntax: // // {pass_int | pass_long | pass_object} // // Arguments are handled from left to right (receiver first, if any). // The offset() values refer to the Java stack offsets but are 0 based and increasing. // The java_offset() values count down to 0, and refer to the Java TOS. // The jni_offset() values increase from 1 or 2, and refer to C arguments. // The method's return type is ignored.
void iterate(fingerprint_t fingerprint) {
set_fingerprint(fingerprint); if (!is_static()) { // handle receiver (not handled by iterate because not in signature)
pass_object(); _jni_offset++; _offset++;
}
do_parameters_on(this);
}
};
// This is the core parsing logic for iterating over signatures. // All of the previous classes use this for doing their work.
class SignatureStream : public StackObj { private: const Symbol* _signature; int _begin; int _end; int _limit; int _array_prefix; // count of '[' before the array element descr
BasicType _type; int _state;
Symbol* _previous_name; // cache the previously looked up symbol to avoid lookups
GrowableArray<Symbol*>* _names; // symbols created while parsing that need to be dereferenced
Symbol* find_symbol();
enum { _s_field = 0, _s_method = 1, _s_method_return = 3 }; void set_done() {
_state |= -2; // preserve s_method bit
assert(is_done(), "Unable to set state to done");
} int scan_type(BasicType bt);
const u1* raw_bytes() const { return _signature->bytes() + _begin; } int raw_length() const { return _end - _begin; } int raw_symbol_begin() const { return _begin + (has_envelope() ? 1 : 0); } int raw_symbol_end() const { return _end - (has_envelope() ? 1 : 0); } char raw_char_at(int i) const {
assert(i < _limit, "index for raw_char_at is over the limit"); return _signature->char_at(i);
}
// True if there is an embedded class name in this type, // followed by ';'. bool has_envelope() const { if (!Signature::has_envelope(_signature->char_at(_begin))) returnfalse; // this should always be true, but let's test it:
assert(_signature->char_at(_end-1) == JVM_SIGNATURE_ENDCLASS, "signature envelope has no semi-colon at end"); returntrue;
}
// return the symbol for chars in symbol_begin()..symbol_end()
Symbol* as_symbol() { return find_symbol();
}
// in case you want only the return type: void skip_to_return_type();
// number of '[' in array prefix int array_prefix_length() { return _type == T_ARRAY ? _array_prefix : 0;
}
// In case you want only the array base type, // reset the stream after skipping some brackets '['. // (The argument is clipped to array_prefix_length(), // and if it ends up as zero this call is a nop. // The default is value skips all brackets '['.) private: int skip_whole_array_prefix(); public: int 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;
} return skip_whole_array_prefix();
} int skip_array_prefix() { if (_type != T_ARRAY) { return 0;
} return skip_whole_array_prefix();
}
// Specialized SignatureStream: used for invoking SystemDictionary to either find // or resolve the underlying type when iterating over a // Java descriptor (or parts of it). class ResolvingSignatureStream : public SignatureStream {
Klass* _load_origin; bool _handles_cached;
Handle _class_loader; // cached when needed
Handle _protection_domain; // cached when needed
// Here is how all the SignatureIterator classes invoke the // SignatureStream engine to do their parsing. template<typename T> inline void SignatureIterator::do_parameters_on(T* callback) {
fingerprint_t unaccumulator = _fingerprint;
// Check for too many arguments, or missing fingerprint: if (!fp_is_valid(unaccumulator)) {
SignatureStream ss(_signature); for (; !ss.at_return_type(); ss.next()) {
callback->do_type(ss.type());
} // while we are here, capture the return type
_return_type = ss.type();
} else { // Optimized version of do_parameters when fingerprint is known
assert(_return_type != T_ILLEGAL, "return type already captured from fp");
unaccumulator = fp_start_parameters(unaccumulator); for (BasicType type; (type = fp_next_parameter(unaccumulator)) != (BasicType)fp_parameters_done; ) {
assert(fp_is_valid_type(type), "garbled fingerprint");
callback->do_type(type);
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.