1 /*
  2  * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 #include "asm/assembler.hpp"
 26 #include "asm/codeBuffer.hpp"
 27 #include "memory/allocation.hpp"
 28 #include "opto/c2_MacroAssembler.hpp"
 29 #include "opto/compile.hpp"
 30 #include "opto/output.hpp"
 31 #include "utilities/growableArray.hpp"
 32 #include "utilities/tuple.hpp"
 33 
 34 #ifndef SHARE_OPTO_C2_CODESTUBS_HPP
 35 #define SHARE_OPTO_C2_CODESTUBS_HPP
 36 
 37 template <class... Ts>
 38 class C2GeneralStub;
 39 
 40 class C2CodeStub : public ArenaObj {
 41 private:
 42   Label _entry;
 43   Label _continuation;
 44 
 45   void add_to_stub_list();
 46 protected:
 47   C2CodeStub() :
 48     _entry(),
 49     _continuation() {}
 50 
 51 public:
 52   Label& entry()        { return _entry; }
 53   Label& continuation() { return _continuation; }
 54 
 55   virtual void emit(C2_MacroAssembler& masm) = 0;
 56   virtual int max_size() const = 0;
 57 
 58   template <class... Ts>
 59   static C2GeneralStub<Ts...>* make(const Ts&... data, int max_size,
 60                                     void (*emit)(C2_MacroAssembler&, C2GeneralStub<Ts...>&));
 61 };
 62 
 63 class C2CodeStubList {
 64 private:
 65   GrowableArray<C2CodeStub*> _stubs;
 66 
 67 public:
 68   C2CodeStubList();
 69 
 70   void add_stub(C2CodeStub* stub) { _stubs.append(stub); }
 71   void emit(C2_MacroAssembler& masm);
 72 };
 73 
 74 class C2SafepointPollStub : public C2CodeStub {
 75 private:
 76   uintptr_t _safepoint_offset;
 77 
 78 public:
 79   C2SafepointPollStub(uintptr_t safepoint_offset) :
 80     _safepoint_offset(safepoint_offset) {}
 81   int max_size() const;
 82   void emit(C2_MacroAssembler& masm);
 83 };
 84 
 85 // We move non-hot code of the nmethod entry barrier to an out-of-line stub
 86 class C2EntryBarrierStub: public C2CodeStub {
 87 private:
 88   Label _guard; // Used on AArch64 and RISCV
 89 
 90 public:
 91   C2EntryBarrierStub() : C2CodeStub(),
 92     _guard() {}
 93 
 94   Label& guard() { return _guard; }
 95 
 96   int max_size() const;
 97   void emit(C2_MacroAssembler& masm);
 98 };
 99 
100 class C2FastUnlockLightweightStub : public C2CodeStub {
101 private:
102   Register _obj;
103   Register _mark;
104   Register _t;
105   Register _thread;
106   Label _slow_path;
107   Label _push_and_slow_path;
108   Label _check_successor;
109   Label _unlocked_continuation;
110 public:
111   C2FastUnlockLightweightStub(Register obj, Register mark, Register t, Register thread) : C2CodeStub(),
112     _obj(obj), _mark(mark), _t(t), _thread(thread) {}
113   int max_size() const;
114   void emit(C2_MacroAssembler& masm);
115   Label& slow_path() { return _slow_path; }
116   Label& push_and_slow_path() { return _push_and_slow_path; }
117   Label& check_successor() { return _check_successor; }
118   Label& unlocked_continuation() { return _unlocked_continuation; }
119   Label& slow_path_continuation() { return continuation(); }
120 };
121 
122 #ifdef _LP64
123 class C2HandleAnonOMOwnerStub : public C2CodeStub {
124 private:
125   Register _monitor;
126   Register _tmp;
127 public:
128   C2HandleAnonOMOwnerStub(Register monitor, Register tmp = noreg) : C2CodeStub(),
129     _monitor(monitor), _tmp(tmp) {}
130   Register monitor() { return _monitor; }
131   Register tmp() { return _tmp; }
132   int max_size() const;
133   void emit(C2_MacroAssembler& masm);
134 };
135 #endif // _LP64
136 
137 //-----------------------------C2GeneralStub-----------------------------------
138 // A generalized stub that can be used to implement an arbitrary stub in a
139 // type-safe manner. An example:
140 //
141 // Register dst; XMMRegister src;
142 // // The lambda defining how the code is emitted in the stub
143 // auto slowpath = [](C2_MacroAssembler& masm, C2GeneralStub<Register, XMMRegister>& stub) {
144 //   // Access the saved data in a type safe manner
145 //   Register dst = stub.get<0>();
146 //   XMMRegister src = stub.get<1>();
147 //   masm.bind(stub.entry());
148 //   ...
149 //   masm.jump(stub.continuation());
150 // }
151 // // Create a stub with 2 data fields being dst and src, a max size of 4 bytes
152 // // and predefined emission function
153 // auto stub = C2CodeStub::make<Register, XMMRegister>(dst, src, 4, slowpath);
154 // __ jump_conditional(stub->entry());
155 // ...
156 // __ bind(stub->continuation());
157 //
158 template <class... Ts>
159 class C2GeneralStub : public C2CodeStub {
160 private:
161   Tuple<Ts...> _data;
162   int _max_size;
163   void (*_emit)(C2_MacroAssembler&, C2GeneralStub&);
164 
165   constexpr C2GeneralStub(const Ts&... data, int max_size,
166                           void (*emit)(C2_MacroAssembler&, C2GeneralStub<Ts...>&))
167     : _data(data...), _max_size(max_size), _emit(emit) {}
168 
169   friend C2CodeStub;
170 public:
171   template <std::size_t I>
172   constexpr const auto& data() const { return _data.template get<I>(); }
173 
174   int max_size() const { return _max_size; }
175   void emit(C2_MacroAssembler& masm) { _emit(masm, *this); }
176 };
177 
178 template <class... Ts>
179 C2GeneralStub<Ts...>* C2CodeStub::make(const Ts&... data, int max_size,
180                                        void (*emit)(C2_MacroAssembler&, C2GeneralStub<Ts...>&)) {
181   auto stub = new (Compile::current()->comp_arena()) C2GeneralStub<Ts...>(data..., max_size, emit);
182   stub->add_to_stub_list();
183   return stub;
184 }
185 
186 #endif // SHARE_OPTO_C2_CODESTUBS_HPP