duke@435: /* trims@1907: * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * trims@1907: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA trims@1907: * or visit www.oracle.com if you need additional information or have any trims@1907: * questions. duke@435: * duke@435: */ duke@435: duke@435: //----------------------------------------------------------------------------- duke@435: // The CompiledIC represents a compiled inline cache. duke@435: // duke@435: // In order to make patching of the inline cache MT-safe, we only allow the following duke@435: // transitions (when not at a safepoint): duke@435: // duke@435: // duke@435: // [1] --<-- Clean -->--- [1] duke@435: // / (null) \ duke@435: // / \ /-<-\ duke@435: // / [2] \ / \ duke@435: // Interpreted ---------> Monomorphic | [3] duke@435: // (compiledICHolderOop) (klassOop) | duke@435: // \ / \ / duke@435: // [4] \ / [4] \->-/ duke@435: // \->- Megamorphic -<-/ duke@435: // (methodOop) duke@435: // duke@435: // The text in paranteses () refere to the value of the inline cache receiver (mov instruction) duke@435: // duke@435: // The numbers in square brackets refere to the kind of transition: duke@435: // [1]: Initial fixup. Receiver it found from debug information duke@435: // [2]: Compilation of a method duke@435: // [3]: Recompilation of a method (note: only entry is changed. The klassOop must stay the same) duke@435: // [4]: Inline cache miss. We go directly to megamorphic call. duke@435: // duke@435: // The class automatically inserts transition stubs (using the InlineCacheBuffer) when an MT-unsafe duke@435: // transition is made to a stub. duke@435: // duke@435: class CompiledIC; duke@435: duke@435: class CompiledICInfo { duke@435: friend class CompiledIC; duke@435: private: duke@435: address _entry; // entry point for call duke@435: Handle _cached_oop; // Value of cached_oop (either in stub or inline cache) duke@435: bool _is_optimized; // it is an optimized virtual call (i.e., can be statically bound) duke@435: bool _to_interpreter; // Call it to interpreter duke@435: public: duke@435: address entry() const { return _entry; } duke@435: Handle cached_oop() const { return _cached_oop; } duke@435: bool is_optimized() const { return _is_optimized; } duke@435: }; duke@435: duke@435: class CompiledIC: public ResourceObj { duke@435: friend class InlineCacheBuffer; duke@435: friend class ICStub; duke@435: duke@435: duke@435: private: duke@435: NativeCall* _ic_call; // the call instruction duke@435: oop* _oop_addr; // patchable oop cell for this IC duke@435: RelocIterator _oops; // iteration over any and all set-oop instructions duke@435: bool _is_optimized; // an optimized virtual call (i.e., no compiled IC) duke@435: duke@435: CompiledIC(NativeCall* ic_call); duke@435: CompiledIC(Relocation* ic_reloc); // Must be of virtual_call_type/opt_virtual_call_type duke@435: duke@435: // low-level inline-cache manipulation. Cannot be accessed directly, since it might not be MT-safe duke@435: // to change an inline-cache. These changes the underlying inline-cache directly. They *newer* make duke@435: // changes to a transition stub. duke@435: void set_ic_destination(address entry_point); duke@435: void set_cached_oop(oop cache); duke@435: duke@435: // Reads the location of the transition stub. This will fail with an assertion, if no transition stub is duke@435: // associated with the inline cache. duke@435: address stub_address() const; duke@435: bool is_in_transition_state() const; // Use InlineCacheBuffer duke@435: duke@435: public: duke@435: // conversion (machine PC to CompiledIC*) duke@435: friend CompiledIC* CompiledIC_before(address return_addr); duke@435: friend CompiledIC* CompiledIC_at(address call_site); duke@435: friend CompiledIC* CompiledIC_at(Relocation* call_site); duke@435: duke@435: // Return the cached_oop/destination associated with this inline cache. If the cache currently points duke@435: // to a transition stub, it will read the values from the transition stub. duke@435: oop cached_oop() const; duke@435: address ic_destination() const; duke@435: duke@435: bool is_optimized() const { return _is_optimized; } duke@435: duke@435: // State duke@435: bool is_clean() const; duke@435: bool is_megamorphic() const; duke@435: bool is_call_to_compiled() const; duke@435: bool is_call_to_interpreted() const; duke@435: duke@435: address end_of_call() { return _ic_call->return_address(); } duke@435: duke@435: // MT-safe patching of inline caches. Note: Only safe to call is_xxx when holding the CompiledIC_ock duke@435: // so you are guaranteed that no patching takes place. The same goes for verify. duke@435: // duke@435: // Note: We do not provide any direct access to the stub code, to prevent parts of the code duke@435: // to manipulate the inline cache in MT-unsafe ways. duke@435: // duke@435: // They all takes a TRAP argument, since they can cause a GC if the inline-cache buffer is full. duke@435: // duke@435: void set_to_clean(); // Can only be called during a safepoint operation duke@435: void set_to_monomorphic(const CompiledICInfo& info); duke@435: void set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecode, TRAPS); duke@435: duke@435: static void compute_monomorphic_entry(methodHandle method, KlassHandle receiver_klass, duke@435: bool is_optimized, bool static_bound, CompiledICInfo& info, TRAPS); duke@435: duke@435: // Location duke@435: address instruction_address() const { return _ic_call->instruction_address(); } duke@435: duke@435: // Misc duke@435: void print() PRODUCT_RETURN; duke@435: void print_compiled_ic() PRODUCT_RETURN; duke@435: void verify() PRODUCT_RETURN; duke@435: }; duke@435: duke@435: inline CompiledIC* CompiledIC_before(address return_addr) { duke@435: CompiledIC* c_ic = new CompiledIC(nativeCall_before(return_addr)); duke@435: c_ic->verify(); duke@435: return c_ic; duke@435: } duke@435: duke@435: inline CompiledIC* CompiledIC_at(address call_site) { duke@435: CompiledIC* c_ic = new CompiledIC(nativeCall_at(call_site)); duke@435: c_ic->verify(); duke@435: return c_ic; duke@435: } duke@435: duke@435: inline CompiledIC* CompiledIC_at(Relocation* call_site) { duke@435: CompiledIC* c_ic = new CompiledIC(call_site); duke@435: c_ic->verify(); duke@435: return c_ic; duke@435: } duke@435: duke@435: duke@435: //----------------------------------------------------------------------------- duke@435: // The CompiledStaticCall represents a call to a static method in the compiled duke@435: // duke@435: // Transition diagram of a static call site is somewhat simpler than for an inlined cache: duke@435: // duke@435: // duke@435: // -----<----- Clean ----->----- duke@435: // / \ duke@435: // / \ duke@435: // compilled code <------------> interpreted code duke@435: // duke@435: // Clean: Calls directly to runtime method for fixup duke@435: // Compiled code: Calls directly to compiled code duke@435: // Interpreted code: Calls to stub that set methodOop reference duke@435: // duke@435: // duke@435: class CompiledStaticCall; duke@435: duke@435: class StaticCallInfo { duke@435: private: duke@435: address _entry; // Entrypoint duke@435: methodHandle _callee; // Callee (used when calling interpreter) duke@435: bool _to_interpreter; // call to interpreted method (otherwise compiled) duke@435: duke@435: friend class CompiledStaticCall; duke@435: public: duke@435: address entry() const { return _entry; } duke@435: methodHandle callee() const { return _callee; } duke@435: }; duke@435: duke@435: duke@435: class CompiledStaticCall: public NativeCall { duke@435: friend class CompiledIC; duke@435: duke@435: // Also used by CompiledIC duke@435: void set_to_interpreted(methodHandle callee, address entry); duke@435: bool is_optimized_virtual(); duke@435: duke@435: public: duke@435: friend CompiledStaticCall* compiledStaticCall_before(address return_addr); duke@435: friend CompiledStaticCall* compiledStaticCall_at(address native_call); duke@435: friend CompiledStaticCall* compiledStaticCall_at(Relocation* call_site); duke@435: duke@435: // State duke@435: bool is_clean() const; duke@435: bool is_call_to_compiled() const; duke@435: bool is_call_to_interpreted() const; duke@435: duke@435: // Clean static call (will force resolving on next use) duke@435: void set_to_clean(); duke@435: duke@435: // Set state. The entry must be the same, as computed by compute_entry. duke@435: // Computation and setting is split up, since the actions are separate during duke@435: // a OptoRuntime::resolve_xxx. duke@435: void set(const StaticCallInfo& info); duke@435: duke@435: // Compute entry point given a method duke@435: static void compute_entry(methodHandle m, StaticCallInfo& info); duke@435: duke@435: // Stub support duke@435: address find_stub(); duke@435: static void set_stub_to_clean(static_stub_Relocation* static_stub); duke@435: duke@435: // Misc. duke@435: void print() PRODUCT_RETURN; duke@435: void verify() PRODUCT_RETURN; duke@435: }; duke@435: duke@435: duke@435: inline CompiledStaticCall* compiledStaticCall_before(address return_addr) { duke@435: CompiledStaticCall* st = (CompiledStaticCall*)nativeCall_before(return_addr); duke@435: st->verify(); duke@435: return st; duke@435: } duke@435: duke@435: inline CompiledStaticCall* compiledStaticCall_at(address native_call) { duke@435: CompiledStaticCall* st = (CompiledStaticCall*)native_call; duke@435: st->verify(); duke@435: return st; duke@435: } duke@435: duke@435: inline CompiledStaticCall* compiledStaticCall_at(Relocation* call_site) { duke@435: return compiledStaticCall_at(call_site->addr()); duke@435: }