aoqi@0: /* aoqi@0: * Copyright (c) 2005, 2012, 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: #ifndef SHARE_VM_CODE_DEPENDENCIES_HPP aoqi@0: #define SHARE_VM_CODE_DEPENDENCIES_HPP aoqi@0: aoqi@0: #include "ci/ciCallSite.hpp" aoqi@0: #include "ci/ciKlass.hpp" aoqi@0: #include "ci/ciMethodHandle.hpp" aoqi@0: #include "classfile/systemDictionary.hpp" aoqi@0: #include "code/compressedStream.hpp" aoqi@0: #include "code/nmethod.hpp" aoqi@0: #include "utilities/growableArray.hpp" aoqi@0: aoqi@0: //** Dependencies represent assertions (approximate invariants) within aoqi@0: // the runtime system, e.g. class hierarchy changes. An example is an aoqi@0: // assertion that a given method is not overridden; another example is aoqi@0: // that a type has only one concrete subtype. Compiled code which aoqi@0: // relies on such assertions must be discarded if they are overturned aoqi@0: // by changes in the runtime system. We can think of these assertions aoqi@0: // as approximate invariants, because we expect them to be overturned aoqi@0: // very infrequently. We are willing to perform expensive recovery aoqi@0: // operations when they are overturned. The benefit, of course, is aoqi@0: // performing optimistic optimizations (!) on the object code. aoqi@0: // aoqi@0: // Changes in the class hierarchy due to dynamic linking or aoqi@0: // class evolution can violate dependencies. There is enough aoqi@0: // indexing between classes and nmethods to make dependency aoqi@0: // checking reasonably efficient. aoqi@0: aoqi@0: class ciEnv; aoqi@0: class nmethod; aoqi@0: class OopRecorder; aoqi@0: class xmlStream; aoqi@0: class CompileLog; aoqi@0: class DepChange; aoqi@0: class KlassDepChange; aoqi@0: class CallSiteDepChange; aoqi@0: class No_Safepoint_Verifier; aoqi@0: aoqi@0: class Dependencies: public ResourceObj { aoqi@0: public: aoqi@0: // Note: In the comments on dependency types, most uses of the terms aoqi@0: // subtype and supertype are used in a "non-strict" or "inclusive" aoqi@0: // sense, and are starred to remind the reader of this fact. aoqi@0: // Strict uses of the terms use the word "proper". aoqi@0: // aoqi@0: // Specifically, every class is its own subtype* and supertype*. aoqi@0: // (This trick is easier than continually saying things like "Y is a aoqi@0: // subtype of X or X itself".) aoqi@0: // aoqi@0: // Sometimes we write X > Y to mean X is a proper supertype of Y. aoqi@0: // The notation X > {Y, Z} means X has proper subtypes Y, Z. aoqi@0: // The notation X.m > Y means that Y inherits m from X, while aoqi@0: // X.m > Y.m means Y overrides X.m. A star denotes abstractness, aoqi@0: // as *I > A, meaning (abstract) interface I is a super type of A, aoqi@0: // or A.*m > B.m, meaning B.m implements abstract method A.m. aoqi@0: // aoqi@0: // In this module, the terms "subtype" and "supertype" refer to aoqi@0: // Java-level reference type conversions, as detected by aoqi@0: // "instanceof" and performed by "checkcast" operations. The method aoqi@0: // Klass::is_subtype_of tests these relations. Note that "subtype" aoqi@0: // is richer than "subclass" (as tested by Klass::is_subclass_of), aoqi@0: // since it takes account of relations involving interface and array aoqi@0: // types. aoqi@0: // aoqi@0: // To avoid needless complexity, dependencies involving array types aoqi@0: // are not accepted. If you need to make an assertion about an aoqi@0: // array type, make the assertion about its corresponding element aoqi@0: // types. Any assertion that might change about an array type can aoqi@0: // be converted to an assertion about its element type. aoqi@0: // aoqi@0: // Most dependencies are evaluated over a "context type" CX, which aoqi@0: // stands for the set Subtypes(CX) of every Java type that is a subtype* aoqi@0: // of CX. When the system loads a new class or interface N, it is aoqi@0: // responsible for re-evaluating changed dependencies whose context aoqi@0: // type now includes N, that is, all super types of N. aoqi@0: // aoqi@0: enum DepType { aoqi@0: end_marker = 0, aoqi@0: aoqi@0: // An 'evol' dependency simply notes that the contents of the aoqi@0: // method were used. If it evolves (is replaced), the nmethod aoqi@0: // must be recompiled. No other dependencies are implied. aoqi@0: evol_method, aoqi@0: FIRST_TYPE = evol_method, aoqi@0: aoqi@0: // A context type CX is a leaf it if has no proper subtype. aoqi@0: leaf_type, aoqi@0: aoqi@0: // An abstract class CX has exactly one concrete subtype CC. aoqi@0: abstract_with_unique_concrete_subtype, aoqi@0: aoqi@0: // The type CX is purely abstract, with no concrete subtype* at all. aoqi@0: abstract_with_no_concrete_subtype, aoqi@0: aoqi@0: // The concrete CX is free of concrete proper subtypes. aoqi@0: concrete_with_no_concrete_subtype, aoqi@0: aoqi@0: // Given a method M1 and a context class CX, the set MM(CX, M1) of aoqi@0: // "concrete matching methods" in CX of M1 is the set of every aoqi@0: // concrete M2 for which it is possible to create an invokevirtual aoqi@0: // or invokeinterface call site that can reach either M1 or M2. aoqi@0: // That is, M1 and M2 share a name, signature, and vtable index. aoqi@0: // We wish to notice when the set MM(CX, M1) is just {M1}, or aoqi@0: // perhaps a set of two {M1,M2}, and issue dependencies on this. aoqi@0: aoqi@0: // The set MM(CX, M1) can be computed by starting with any matching aoqi@0: // concrete M2 that is inherited into CX, and then walking the aoqi@0: // subtypes* of CX looking for concrete definitions. aoqi@0: aoqi@0: // The parameters to this dependency are the method M1 and the aoqi@0: // context class CX. M1 must be either inherited in CX or defined aoqi@0: // in a subtype* of CX. It asserts that MM(CX, M1) is no greater aoqi@0: // than {M1}. aoqi@0: unique_concrete_method, // one unique concrete method under CX aoqi@0: aoqi@0: // An "exclusive" assertion concerns two methods or subtypes, and aoqi@0: // declares that there are at most two (or perhaps later N>2) aoqi@0: // specific items that jointly satisfy the restriction. aoqi@0: // We list all items explicitly rather than just giving their aoqi@0: // count, for robustness in the face of complex schema changes. aoqi@0: aoqi@0: // A context class CX (which may be either abstract or concrete) aoqi@0: // has two exclusive concrete subtypes* C1, C2 if every concrete aoqi@0: // subtype* of CX is either C1 or C2. Note that if neither C1 or C2 aoqi@0: // are equal to CX, then CX itself must be abstract. But it is aoqi@0: // also possible (for example) that C1 is CX (a concrete class) aoqi@0: // and C2 is a proper subtype of C1. aoqi@0: abstract_with_exclusive_concrete_subtypes_2, aoqi@0: aoqi@0: // This dependency asserts that MM(CX, M1) is no greater than {M1,M2}. aoqi@0: exclusive_concrete_methods_2, aoqi@0: aoqi@0: // This dependency asserts that no instances of class or it's aoqi@0: // subclasses require finalization registration. aoqi@0: no_finalizable_subclasses, aoqi@0: aoqi@0: // This dependency asserts when the CallSite.target value changed. aoqi@0: call_site_target_value, aoqi@0: aoqi@0: TYPE_LIMIT aoqi@0: }; aoqi@0: enum { aoqi@0: LG2_TYPE_LIMIT = 4, // assert(TYPE_LIMIT <= (1<* _dep_seen; // (seen[h->ident] & (1<* _deps[TYPE_LIMIT]; aoqi@0: aoqi@0: static const char* _dep_name[TYPE_LIMIT]; aoqi@0: static int _dep_args[TYPE_LIMIT]; aoqi@0: aoqi@0: static bool dept_in_mask(DepType dept, int mask) { aoqi@0: return (int)dept >= 0 && dept < TYPE_LIMIT && ((1<ident(); aoqi@0: assert(_dep_seen != NULL, "deps must be writable"); aoqi@0: int seen = _dep_seen->at_grow(x_id, 0); aoqi@0: _dep_seen->at_put(x_id, seen | (1<* deps, aoqi@0: int ctxk_i, ciKlass* ctxk); aoqi@0: aoqi@0: void sort_all_deps(); aoqi@0: size_t estimate_size_in_bytes(); aoqi@0: aoqi@0: // Initialize _deps, etc. aoqi@0: void initialize(ciEnv* env); aoqi@0: aoqi@0: // State for making a new set of dependencies: aoqi@0: OopRecorder* _oop_recorder; aoqi@0: aoqi@0: // Logging support aoqi@0: CompileLog* _log; aoqi@0: aoqi@0: address _content_bytes; // everything but the oop references, encoded aoqi@0: size_t _size_in_bytes; aoqi@0: aoqi@0: public: aoqi@0: // Make a new empty dependencies set. aoqi@0: Dependencies(ciEnv* env) { aoqi@0: initialize(env); aoqi@0: } aoqi@0: aoqi@0: private: aoqi@0: // Check for a valid context type. aoqi@0: // Enforce the restriction against array types. aoqi@0: static void check_ctxk(ciKlass* ctxk) { aoqi@0: assert(ctxk->is_instance_klass(), "java types only"); aoqi@0: } aoqi@0: static void check_ctxk_concrete(ciKlass* ctxk) { aoqi@0: assert(is_concrete_klass(ctxk->as_instance_klass()), "must be concrete"); aoqi@0: } aoqi@0: static void check_ctxk_abstract(ciKlass* ctxk) { aoqi@0: check_ctxk(ctxk); aoqi@0: assert(!is_concrete_klass(ctxk->as_instance_klass()), "must be abstract"); aoqi@0: } aoqi@0: aoqi@0: void assert_common_1(DepType dept, ciBaseObject* x); aoqi@0: void assert_common_2(DepType dept, ciBaseObject* x0, ciBaseObject* x1); aoqi@0: void assert_common_3(DepType dept, ciKlass* ctxk, ciBaseObject* x1, ciBaseObject* x2); aoqi@0: aoqi@0: public: aoqi@0: // Adding assertions to a new dependency set at compile time: aoqi@0: void assert_evol_method(ciMethod* m); aoqi@0: void assert_leaf_type(ciKlass* ctxk); aoqi@0: void assert_abstract_with_unique_concrete_subtype(ciKlass* ctxk, ciKlass* conck); aoqi@0: void assert_abstract_with_no_concrete_subtype(ciKlass* ctxk); aoqi@0: void assert_concrete_with_no_concrete_subtype(ciKlass* ctxk); aoqi@0: void assert_unique_concrete_method(ciKlass* ctxk, ciMethod* uniqm); aoqi@0: void assert_abstract_with_exclusive_concrete_subtypes(ciKlass* ctxk, ciKlass* k1, ciKlass* k2); aoqi@0: void assert_exclusive_concrete_methods(ciKlass* ctxk, ciMethod* m1, ciMethod* m2); aoqi@0: void assert_has_no_finalizable_subclasses(ciKlass* ctxk); aoqi@0: void assert_call_site_target_value(ciCallSite* call_site, ciMethodHandle* method_handle); aoqi@0: aoqi@0: // Define whether a given method or type is concrete. aoqi@0: // These methods define the term "concrete" as used in this module. aoqi@0: // For this module, an "abstract" class is one which is non-concrete. aoqi@0: // aoqi@0: // Future optimizations may allow some classes to remain aoqi@0: // non-concrete until their first instantiation, and allow some aoqi@0: // methods to remain non-concrete until their first invocation. aoqi@0: // In that case, there would be a middle ground between concrete aoqi@0: // and abstract (as defined by the Java language and VM). aoqi@0: static bool is_concrete_klass(Klass* k); // k is instantiable aoqi@0: static bool is_concrete_method(Method* m); // m is invocable aoqi@0: static Klass* find_finalizable_subclass(Klass* k); aoqi@0: aoqi@0: // These versions of the concreteness queries work through the CI. aoqi@0: // The CI versions are allowed to skew sometimes from the VM aoqi@0: // (oop-based) versions. The cost of such a difference is a aoqi@0: // (safely) aborted compilation, or a deoptimization, or a missed aoqi@0: // optimization opportunity. aoqi@0: // aoqi@0: // In order to prevent spurious assertions, query results must aoqi@0: // remain stable within any single ciEnv instance. (I.e., they must aoqi@0: // not go back into the VM to get their value; they must cache the aoqi@0: // bit in the CI, either eagerly or lazily.) aoqi@0: static bool is_concrete_klass(ciInstanceKlass* k); // k appears instantiable aoqi@0: static bool is_concrete_method(ciMethod* m); // m appears invocable aoqi@0: static bool has_finalizable_subclass(ciInstanceKlass* k); aoqi@0: aoqi@0: // As a general rule, it is OK to compile under the assumption that aoqi@0: // a given type or method is concrete, even if it at some future aoqi@0: // point becomes abstract. So dependency checking is one-sided, in aoqi@0: // that it permits supposedly concrete classes or methods to turn up aoqi@0: // as really abstract. (This shouldn't happen, except during class aoqi@0: // evolution, but that's the logic of the checking.) However, if a aoqi@0: // supposedly abstract class or method suddenly becomes concrete, a aoqi@0: // dependency on it must fail. aoqi@0: aoqi@0: // Checking old assertions at run-time (in the VM only): aoqi@0: static Klass* check_evol_method(Method* m); aoqi@0: static Klass* check_leaf_type(Klass* ctxk); aoqi@0: static Klass* check_abstract_with_unique_concrete_subtype(Klass* ctxk, Klass* conck, aoqi@0: KlassDepChange* changes = NULL); aoqi@0: static Klass* check_abstract_with_no_concrete_subtype(Klass* ctxk, aoqi@0: KlassDepChange* changes = NULL); aoqi@0: static Klass* check_concrete_with_no_concrete_subtype(Klass* ctxk, aoqi@0: KlassDepChange* changes = NULL); aoqi@0: static Klass* check_unique_concrete_method(Klass* ctxk, Method* uniqm, aoqi@0: KlassDepChange* changes = NULL); aoqi@0: static Klass* check_abstract_with_exclusive_concrete_subtypes(Klass* ctxk, Klass* k1, Klass* k2, aoqi@0: KlassDepChange* changes = NULL); aoqi@0: static Klass* check_exclusive_concrete_methods(Klass* ctxk, Method* m1, Method* m2, aoqi@0: KlassDepChange* changes = NULL); aoqi@0: static Klass* check_has_no_finalizable_subclasses(Klass* ctxk, KlassDepChange* changes = NULL); aoqi@0: static Klass* check_call_site_target_value(oop call_site, oop method_handle, CallSiteDepChange* changes = NULL); aoqi@0: // A returned Klass* is NULL if the dependency assertion is still aoqi@0: // valid. A non-NULL Klass* is a 'witness' to the assertion aoqi@0: // failure, a point in the class hierarchy where the assertion has aoqi@0: // been proven false. For example, if check_leaf_type returns aoqi@0: // non-NULL, the value is a subtype of the supposed leaf type. This aoqi@0: // witness value may be useful for logging the dependency failure. aoqi@0: // Note that, when a dependency fails, there may be several possible aoqi@0: // witnesses to the failure. The value returned from the check_foo aoqi@0: // method is chosen arbitrarily. aoqi@0: aoqi@0: // The 'changes' value, if non-null, requests a limited spot-check aoqi@0: // near the indicated recent changes in the class hierarchy. aoqi@0: // It is used by DepStream::spot_check_dependency_at. aoqi@0: aoqi@0: // Detecting possible new assertions: aoqi@0: static Klass* find_unique_concrete_subtype(Klass* ctxk); aoqi@0: static Method* find_unique_concrete_method(Klass* ctxk, Method* m); aoqi@0: static int find_exclusive_concrete_subtypes(Klass* ctxk, int klen, Klass* k[]); aoqi@0: static int find_exclusive_concrete_methods(Klass* ctxk, int mlen, Method* m[]); aoqi@0: aoqi@0: // Create the encoding which will be stored in an nmethod. aoqi@0: void encode_content_bytes(); aoqi@0: aoqi@0: address content_bytes() { aoqi@0: assert(_content_bytes != NULL, "encode it first"); aoqi@0: return _content_bytes; aoqi@0: } aoqi@0: size_t size_in_bytes() { aoqi@0: assert(_content_bytes != NULL, "encode it first"); aoqi@0: return _size_in_bytes; aoqi@0: } aoqi@0: aoqi@0: OopRecorder* oop_recorder() { return _oop_recorder; } aoqi@0: CompileLog* log() { return _log; } aoqi@0: aoqi@0: void copy_to(nmethod* nm); aoqi@0: aoqi@0: void log_all_dependencies(); aoqi@0: void log_dependency(DepType dept, int nargs, ciBaseObject* args[]) { aoqi@0: write_dependency_to(log(), dept, nargs, args); aoqi@0: } aoqi@0: void log_dependency(DepType dept, aoqi@0: ciBaseObject* x0, aoqi@0: ciBaseObject* x1 = NULL, aoqi@0: ciBaseObject* x2 = NULL) { aoqi@0: if (log() == NULL) return; aoqi@0: ciBaseObject* args[max_arg_count]; aoqi@0: args[0] = x0; aoqi@0: args[1] = x1; aoqi@0: args[2] = x2; aoqi@0: assert(2 < max_arg_count, ""); aoqi@0: log_dependency(dept, dep_args(dept), args); aoqi@0: } aoqi@0: aoqi@0: class DepArgument : public ResourceObj { aoqi@0: private: aoqi@0: bool _is_oop; aoqi@0: bool _valid; aoqi@0: void* _value; aoqi@0: public: aoqi@0: DepArgument() : _is_oop(false), _value(NULL), _valid(false) {} aoqi@0: DepArgument(oop v): _is_oop(true), _value(v), _valid(true) {} aoqi@0: DepArgument(Metadata* v): _is_oop(false), _value(v), _valid(true) {} aoqi@0: aoqi@0: bool is_null() const { return _value == NULL; } aoqi@0: bool is_oop() const { return _is_oop; } aoqi@0: bool is_metadata() const { return !_is_oop; } aoqi@0: bool is_klass() const { return is_metadata() && metadata_value()->is_klass(); } aoqi@0: bool is_method() const { return is_metadata() && metadata_value()->is_method(); } aoqi@0: aoqi@0: oop oop_value() const { assert(_is_oop && _valid, "must be"); return (oop) _value; } aoqi@0: Metadata* metadata_value() const { assert(!_is_oop && _valid, "must be"); return (Metadata*) _value; } aoqi@0: }; aoqi@0: aoqi@0: static void write_dependency_to(CompileLog* log, aoqi@0: DepType dept, aoqi@0: int nargs, ciBaseObject* args[], aoqi@0: Klass* witness = NULL); aoqi@0: static void write_dependency_to(CompileLog* log, aoqi@0: DepType dept, aoqi@0: int nargs, DepArgument args[], aoqi@0: Klass* witness = NULL); aoqi@0: static void write_dependency_to(xmlStream* xtty, aoqi@0: DepType dept, aoqi@0: int nargs, DepArgument args[], aoqi@0: Klass* witness = NULL); aoqi@0: static void print_dependency(DepType dept, aoqi@0: int nargs, DepArgument args[], aoqi@0: Klass* witness = NULL); aoqi@0: aoqi@0: private: aoqi@0: // helper for encoding common context types as zero: aoqi@0: static ciKlass* ctxk_encoded_as_null(DepType dept, ciBaseObject* x); aoqi@0: aoqi@0: static Klass* ctxk_encoded_as_null(DepType dept, Metadata* x); aoqi@0: aoqi@0: public: aoqi@0: // Use this to iterate over an nmethod's dependency set. aoqi@0: // Works on new and old dependency sets. aoqi@0: // Usage: aoqi@0: // aoqi@0: // ; aoqi@0: // Dependencies::DepType dept; aoqi@0: // for (Dependencies::DepStream deps(nm); deps.next(); ) { aoqi@0: // ... aoqi@0: // } aoqi@0: // aoqi@0: // The caller must be in the VM, since oops are not wrapped in handles. aoqi@0: class DepStream { aoqi@0: private: aoqi@0: nmethod* _code; // null if in a compiler thread aoqi@0: Dependencies* _deps; // null if not in a compiler thread aoqi@0: CompressedReadStream _bytes; aoqi@0: #ifdef ASSERT aoqi@0: size_t _byte_limit; aoqi@0: #endif aoqi@0: aoqi@0: // iteration variables: aoqi@0: DepType _type; aoqi@0: int _xi[max_arg_count+1]; aoqi@0: aoqi@0: void initial_asserts(size_t byte_limit) NOT_DEBUG({}); aoqi@0: aoqi@0: inline Metadata* recorded_metadata_at(int i); aoqi@0: inline oop recorded_oop_at(int i); aoqi@0: aoqi@0: Klass* check_klass_dependency(KlassDepChange* changes); aoqi@0: Klass* check_call_site_dependency(CallSiteDepChange* changes); aoqi@0: aoqi@0: void trace_and_log_witness(Klass* witness); aoqi@0: aoqi@0: public: aoqi@0: DepStream(Dependencies* deps) aoqi@0: : _deps(deps), aoqi@0: _code(NULL), aoqi@0: _bytes(deps->content_bytes()) aoqi@0: { aoqi@0: initial_asserts(deps->size_in_bytes()); aoqi@0: } aoqi@0: DepStream(nmethod* code) aoqi@0: : _deps(NULL), aoqi@0: _code(code), aoqi@0: _bytes(code->dependencies_begin()) aoqi@0: { aoqi@0: initial_asserts(code->dependencies_size()); aoqi@0: } aoqi@0: aoqi@0: bool next(); aoqi@0: aoqi@0: DepType type() { return _type; } aoqi@0: int argument_count() { return dep_args(type()); } aoqi@0: int argument_index(int i) { assert(0 <= i && i < argument_count(), "oob"); aoqi@0: return _xi[i]; } aoqi@0: Metadata* argument(int i); // => recorded_oop_at(argument_index(i)) aoqi@0: oop argument_oop(int i); // => recorded_oop_at(argument_index(i)) aoqi@0: Klass* context_type(); aoqi@0: aoqi@0: bool is_klass_type() { return Dependencies::is_klass_type(type()); } aoqi@0: aoqi@0: Method* method_argument(int i) { aoqi@0: Metadata* x = argument(i); aoqi@0: assert(x->is_method(), "type"); aoqi@0: return (Method*) x; aoqi@0: } aoqi@0: Klass* type_argument(int i) { aoqi@0: Metadata* x = argument(i); aoqi@0: assert(x->is_klass(), "type"); aoqi@0: return (Klass*) x; aoqi@0: } aoqi@0: aoqi@0: // The point of the whole exercise: Is this dep still OK? aoqi@0: Klass* check_dependency() { aoqi@0: Klass* result = check_klass_dependency(NULL); aoqi@0: if (result != NULL) return result; aoqi@0: return check_call_site_dependency(NULL); aoqi@0: } aoqi@0: aoqi@0: // A lighter version: Checks only around recent changes in a class aoqi@0: // hierarchy. (See Universe::flush_dependents_on.) aoqi@0: Klass* spot_check_dependency_at(DepChange& changes); aoqi@0: aoqi@0: // Log the current dependency to xtty or compilation log. aoqi@0: void log_dependency(Klass* witness = NULL); aoqi@0: aoqi@0: // Print the current dependency to tty. aoqi@0: void print_dependency(Klass* witness = NULL, bool verbose = false); aoqi@0: }; aoqi@0: friend class Dependencies::DepStream; aoqi@0: aoqi@0: static void print_statistics() PRODUCT_RETURN; aoqi@0: }; aoqi@0: aoqi@0: aoqi@0: // Every particular DepChange is a sub-class of this class. aoqi@0: class DepChange : public StackObj { aoqi@0: public: aoqi@0: // What kind of DepChange is this? aoqi@0: virtual bool is_klass_change() const { return false; } aoqi@0: virtual bool is_call_site_change() const { return false; } aoqi@0: aoqi@0: // Subclass casting with assertions. aoqi@0: KlassDepChange* as_klass_change() { aoqi@0: assert(is_klass_change(), "bad cast"); aoqi@0: return (KlassDepChange*) this; aoqi@0: } aoqi@0: CallSiteDepChange* as_call_site_change() { aoqi@0: assert(is_call_site_change(), "bad cast"); aoqi@0: return (CallSiteDepChange*) this; aoqi@0: } aoqi@0: aoqi@0: void print(); aoqi@0: aoqi@0: public: aoqi@0: enum ChangeType { aoqi@0: NO_CHANGE = 0, // an uninvolved klass aoqi@0: Change_new_type, // a newly loaded type aoqi@0: Change_new_sub, // a super with a new subtype aoqi@0: Change_new_impl, // an interface with a new implementation aoqi@0: CHANGE_LIMIT, aoqi@0: Start_Klass = CHANGE_LIMIT // internal indicator for ContextStream aoqi@0: }; aoqi@0: aoqi@0: // Usage: aoqi@0: // for (DepChange::ContextStream str(changes); str.next(); ) { aoqi@0: // Klass* k = str.klass(); aoqi@0: // switch (str.change_type()) { aoqi@0: // ... aoqi@0: // } aoqi@0: // } aoqi@0: class ContextStream : public StackObj { aoqi@0: private: aoqi@0: DepChange& _changes; aoqi@0: friend class DepChange; aoqi@0: aoqi@0: // iteration variables: aoqi@0: ChangeType _change_type; aoqi@0: Klass* _klass; aoqi@0: Array* _ti_base; // i.e., transitive_interfaces aoqi@0: int _ti_index; aoqi@0: int _ti_limit; aoqi@0: aoqi@0: // start at the beginning: aoqi@0: void start(); aoqi@0: aoqi@0: public: aoqi@0: ContextStream(DepChange& changes) aoqi@0: : _changes(changes) aoqi@0: { start(); } aoqi@0: aoqi@0: ContextStream(DepChange& changes, No_Safepoint_Verifier& nsv) aoqi@0: : _changes(changes) aoqi@0: // the nsv argument makes it safe to hold oops like _klass aoqi@0: { start(); } aoqi@0: aoqi@0: bool next(); aoqi@0: aoqi@0: ChangeType change_type() { return _change_type; } aoqi@0: Klass* klass() { return _klass; } aoqi@0: }; aoqi@0: friend class DepChange::ContextStream; aoqi@0: }; aoqi@0: aoqi@0: aoqi@0: // A class hierarchy change coming through the VM (under the Compile_lock). aoqi@0: // The change is structured as a single new type with any number of supers aoqi@0: // and implemented interface types. Other than the new type, any of the aoqi@0: // super types can be context types for a relevant dependency, which the aoqi@0: // new type could invalidate. aoqi@0: class KlassDepChange : public DepChange { aoqi@0: private: aoqi@0: // each change set is rooted in exactly one new type (at present): aoqi@0: KlassHandle _new_type; aoqi@0: aoqi@0: void initialize(); aoqi@0: aoqi@0: public: aoqi@0: // notes the new type, marks it and all its super-types aoqi@0: KlassDepChange(KlassHandle new_type) aoqi@0: : _new_type(new_type) aoqi@0: { aoqi@0: initialize(); aoqi@0: } aoqi@0: aoqi@0: // cleans up the marks aoqi@0: ~KlassDepChange(); aoqi@0: aoqi@0: // What kind of DepChange is this? aoqi@0: virtual bool is_klass_change() const { return true; } aoqi@0: aoqi@0: Klass* new_type() { return _new_type(); } aoqi@0: aoqi@0: // involves_context(k) is true if k is new_type or any of the super types aoqi@0: bool involves_context(Klass* k); aoqi@0: }; aoqi@0: aoqi@0: aoqi@0: // A CallSite has changed its target. aoqi@0: class CallSiteDepChange : public DepChange { aoqi@0: private: aoqi@0: Handle _call_site; aoqi@0: Handle _method_handle; aoqi@0: aoqi@0: public: aoqi@0: CallSiteDepChange(Handle call_site, Handle method_handle) aoqi@0: : _call_site(call_site), aoqi@0: _method_handle(method_handle) aoqi@0: { aoqi@0: assert(_call_site() ->is_a(SystemDictionary::CallSite_klass()), "must be"); aoqi@0: assert(_method_handle()->is_a(SystemDictionary::MethodHandle_klass()), "must be"); aoqi@0: } aoqi@0: aoqi@0: // What kind of DepChange is this? aoqi@0: virtual bool is_call_site_change() const { return true; } aoqi@0: aoqi@0: oop call_site() const { return _call_site(); } aoqi@0: oop method_handle() const { return _method_handle(); } aoqi@0: }; aoqi@0: aoqi@0: #endif // SHARE_VM_CODE_DEPENDENCIES_HPP