1 /*
  2  * Copyright (c) 2017, 2018, 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 #ifndef SHARE_OOPS_ACCESS_INLINE_HPP
 26 #define SHARE_OOPS_ACCESS_INLINE_HPP
 27 
 28 #include "gc/shared/barrierSetConfig.inline.hpp"
 29 #include "oops/access.hpp"
 30 #include "oops/accessBackend.inline.hpp"
 31 
 32 // This file outlines the last 2 steps of the template pipeline of accesses going through
 33 // the Access API.
 34 // * Step 5.a: Barrier resolution. This step is invoked the first time a runtime-dispatch
 35 //             happens for an access. The appropriate BarrierSet::AccessBarrier accessor
 36 //             is resolved, then the function pointer is updated to that accessor for
 37 //             future invocations.
 38 // * Step 5.b: Post-runtime dispatch. This step now casts previously unknown types such
 39 //             as the address type of an oop on the heap (is it oop* or narrowOop*) to
 40 //             the appropriate type. It also splits sufficiently orthogonal accesses into
 41 //             different functions, such as whether the access involves oops or primitives
 42 //             and whether the access is performed on the heap or outside. Then the
 43 //             appropriate BarrierSet::AccessBarrier is called to perform the access.
 44 
 45 namespace AccessInternal {
 46   // Step 5.b: Post-runtime dispatch.
 47   // This class is the last step before calling the BarrierSet::AccessBarrier.
 48   // Here we make sure to figure out types that were not known prior to the
 49   // runtime dispatch, such as whether an oop on the heap is oop or narrowOop.
 50   // We also split orthogonal barriers such as handling primitives vs oops
 51   // and on-heap vs off-heap into different calls to the barrier set.
 52   template <class GCBarrierType, BarrierType type, DecoratorSet decorators>
 53   struct PostRuntimeDispatch: public AllStatic { };
 54 
 55   template <class GCBarrierType, DecoratorSet decorators>
 56   struct PostRuntimeDispatch<GCBarrierType, BARRIER_STORE, decorators>: public AllStatic {
 57     template <typename T>
 58     static void access_barrier(void* addr, T value) {
 59       GCBarrierType::store_in_heap(reinterpret_cast<T*>(addr), value);
 60     }
 61 
 62     static void oop_access_barrier(void* addr, oop value) {
 63       typedef typename HeapOopType<decorators>::type OopType;
 64       if (HasDecorator<decorators, IN_HEAP>::value) {
 65         GCBarrierType::oop_store_in_heap(reinterpret_cast<OopType*>(addr), value);
 66       } else {
 67         GCBarrierType::oop_store_not_in_heap(reinterpret_cast<OopType*>(addr), value);
 68       }
 69     }
 70   };
 71 
 72   template <class GCBarrierType, DecoratorSet decorators>
 73   struct PostRuntimeDispatch<GCBarrierType, BARRIER_LOAD, decorators>: public AllStatic {
 74     template <typename T>
 75     static T access_barrier(void* addr) {
 76       return GCBarrierType::load_in_heap(reinterpret_cast<T*>(addr));
 77     }
 78 
 79     static oop oop_access_barrier(void* addr) {
 80       typedef typename HeapOopType<decorators>::type OopType;
 81       if (HasDecorator<decorators, IN_HEAP>::value) {
 82         return GCBarrierType::oop_load_in_heap(reinterpret_cast<OopType*>(addr));
 83       } else {
 84         return GCBarrierType::oop_load_not_in_heap(reinterpret_cast<OopType*>(addr));
 85       }
 86     }
 87   };
 88 
 89   template <class GCBarrierType, DecoratorSet decorators>
 90   struct PostRuntimeDispatch<GCBarrierType, BARRIER_ATOMIC_XCHG, decorators>: public AllStatic {
 91     template <typename T>
 92     static T access_barrier(T new_value, void* addr) {
 93       return GCBarrierType::atomic_xchg_in_heap(new_value, reinterpret_cast<T*>(addr));
 94     }
 95 
 96     static oop oop_access_barrier(oop new_value, void* addr) {
 97       typedef typename HeapOopType<decorators>::type OopType;
 98       if (HasDecorator<decorators, IN_HEAP>::value) {
 99         return GCBarrierType::oop_atomic_xchg_in_heap(new_value, reinterpret_cast<OopType*>(addr));
100       } else {
101         return GCBarrierType::oop_atomic_xchg_not_in_heap(new_value, reinterpret_cast<OopType*>(addr));
102       }
103     }
104   };
105 
106   template <class GCBarrierType, DecoratorSet decorators>
107   struct PostRuntimeDispatch<GCBarrierType, BARRIER_ATOMIC_CMPXCHG, decorators>: public AllStatic {
108     template <typename T>
109     static T access_barrier(T new_value, void* addr, T compare_value) {
110       return GCBarrierType::atomic_cmpxchg_in_heap(new_value, reinterpret_cast<T*>(addr), compare_value);
111     }
112 
113     static oop oop_access_barrier(oop new_value, void* addr, oop compare_value) {
114       typedef typename HeapOopType<decorators>::type OopType;
115       if (HasDecorator<decorators, IN_HEAP>::value) {
116         return GCBarrierType::oop_atomic_cmpxchg_in_heap(new_value, reinterpret_cast<OopType*>(addr), compare_value);
117       } else {
118         return GCBarrierType::oop_atomic_cmpxchg_not_in_heap(new_value, reinterpret_cast<OopType*>(addr), compare_value);
119       }
120     }
121   };
122 
123   template <class GCBarrierType, DecoratorSet decorators>
124   struct PostRuntimeDispatch<GCBarrierType, BARRIER_ARRAYCOPY, decorators>: public AllStatic {
125     template <typename T>
126     static bool access_barrier(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length) {
127       GCBarrierType::arraycopy_in_heap(src_obj, dst_obj, src, dst, length);
128       return true;
129     }
130 
131     template <typename T>
132     static bool oop_access_barrier(arrayOop src_obj, arrayOop dst_obj, T* src, T* dst, size_t length) {
133       typedef typename HeapOopType<decorators>::type OopType;
134       return GCBarrierType::oop_arraycopy_in_heap(src_obj, dst_obj,
135                                                   reinterpret_cast<OopType*>(src),
136                                                   reinterpret_cast<OopType*>(dst), length);
137     }
138   };
139 
140   template <class GCBarrierType, DecoratorSet decorators>
141   struct PostRuntimeDispatch<GCBarrierType, BARRIER_STORE_AT, decorators>: public AllStatic {
142     template <typename T>
143     static void access_barrier(oop base, ptrdiff_t offset, T value) {
144       GCBarrierType::store_in_heap_at(base, offset, value);
145     }
146 
147     static void oop_access_barrier(oop base, ptrdiff_t offset, oop value) {
148       GCBarrierType::oop_store_in_heap_at(base, offset, value);
149     }
150   };
151 
152   template <class GCBarrierType, DecoratorSet decorators>
153   struct PostRuntimeDispatch<GCBarrierType, BARRIER_LOAD_AT, decorators>: public AllStatic {
154     template <typename T>
155     static T access_barrier(oop base, ptrdiff_t offset) {
156       return GCBarrierType::template load_in_heap_at<T>(base, offset);
157     }
158 
159     static oop oop_access_barrier(oop base, ptrdiff_t offset) {
160       return GCBarrierType::oop_load_in_heap_at(base, offset);
161     }
162   };
163 
164   template <class GCBarrierType, DecoratorSet decorators>
165   struct PostRuntimeDispatch<GCBarrierType, BARRIER_ATOMIC_XCHG_AT, decorators>: public AllStatic {
166     template <typename T>
167     static T access_barrier(T new_value, oop base, ptrdiff_t offset) {
168       return GCBarrierType::atomic_xchg_in_heap_at(new_value, base, offset);
169     }
170 
171     static oop oop_access_barrier(oop new_value, oop base, ptrdiff_t offset) {
172       return GCBarrierType::oop_atomic_xchg_in_heap_at(new_value, base, offset);
173     }
174   };
175 
176   template <class GCBarrierType, DecoratorSet decorators>
177   struct PostRuntimeDispatch<GCBarrierType, BARRIER_ATOMIC_CMPXCHG_AT, decorators>: public AllStatic {
178     template <typename T>
179     static T access_barrier(T new_value, oop base, ptrdiff_t offset, T compare_value) {
180       return GCBarrierType::atomic_cmpxchg_in_heap_at(new_value, base, offset, compare_value);
181     }
182 
183     static oop oop_access_barrier(oop new_value, oop base, ptrdiff_t offset, oop compare_value) {
184       return GCBarrierType::oop_atomic_cmpxchg_in_heap_at(new_value, base, offset, compare_value);
185     }
186   };
187 
188   template <class GCBarrierType, DecoratorSet decorators>
189   struct PostRuntimeDispatch<GCBarrierType, BARRIER_CLONE, decorators>: public AllStatic {
190     static void access_barrier(oop src, oop dst, size_t size) {
191       GCBarrierType::clone_in_heap(src, dst, size);
192     }
193   };
194 
195   template <class GCBarrierType, DecoratorSet decorators>
196   struct PostRuntimeDispatch<GCBarrierType, BARRIER_RESOLVE, decorators>: public AllStatic {
197     static oop access_barrier(oop obj) {
198       return GCBarrierType::resolve(obj);
199     }
200   };
201 
202   template <class GCBarrierType, DecoratorSet decorators>
203   struct PostRuntimeDispatch<GCBarrierType, BARRIER_EQUALS, decorators>: public AllStatic {
204     static bool access_barrier(oop o1, oop o2) {
205       return GCBarrierType::equals(o1, o2);
206     }
207   };
208 
209   // Resolving accessors with barriers from the barrier set happens in two steps.
210   // 1. Expand paths with runtime-decorators, e.g. is UseCompressedOops on or off.
211   // 2. Expand paths for each BarrierSet available in the system.
212   template <DecoratorSet decorators, typename FunctionPointerT, BarrierType barrier_type>
213   struct BarrierResolver: public AllStatic {
214     template <DecoratorSet ds>
215     static typename EnableIf<
216       HasDecorator<ds, INTERNAL_VALUE_IS_OOP>::value,
217       FunctionPointerT>::type
218     resolve_barrier_gc() {
219       BarrierSet* bs = BarrierSet::barrier_set();
220       assert(bs != NULL, "GC barriers invoked before BarrierSet is set");
221       switch (bs->kind()) {
222 #define BARRIER_SET_RESOLVE_BARRIER_CLOSURE(bs_name)                    \
223         case BarrierSet::bs_name: {                                     \
224           return PostRuntimeDispatch<typename BarrierSet::GetType<BarrierSet::bs_name>::type:: \
225             AccessBarrier<ds>, barrier_type, ds>::oop_access_barrier; \
226         }                                                               \
227         break;
228         FOR_EACH_CONCRETE_BARRIER_SET_DO(BARRIER_SET_RESOLVE_BARRIER_CLOSURE)
229 #undef BARRIER_SET_RESOLVE_BARRIER_CLOSURE
230 
231       default:
232         fatal("BarrierSet AccessBarrier resolving not implemented");
233         return NULL;
234       };
235     }
236 
237     template <DecoratorSet ds>
238     static typename EnableIf<
239       !HasDecorator<ds, INTERNAL_VALUE_IS_OOP>::value,
240       FunctionPointerT>::type
241     resolve_barrier_gc() {
242       BarrierSet* bs = BarrierSet::barrier_set();
243       assert(bs != NULL, "GC barriers invoked before BarrierSet is set");
244       switch (bs->kind()) {
245 #define BARRIER_SET_RESOLVE_BARRIER_CLOSURE(bs_name)                    \
246         case BarrierSet::bs_name: {                                       \
247           return PostRuntimeDispatch<typename BarrierSet::GetType<BarrierSet::bs_name>::type:: \
248             AccessBarrier<ds>, barrier_type, ds>::access_barrier; \
249         }                                                                 \
250         break;
251         FOR_EACH_CONCRETE_BARRIER_SET_DO(BARRIER_SET_RESOLVE_BARRIER_CLOSURE)
252 #undef BARRIER_SET_RESOLVE_BARRIER_CLOSURE
253 
254       default:
255         fatal("BarrierSet AccessBarrier resolving not implemented");
256         return NULL;
257       };
258     }
259 
260     static FunctionPointerT resolve_barrier_rt() {
261       if (UseCompressedOops) {
262         const DecoratorSet expanded_decorators = decorators | INTERNAL_RT_USE_COMPRESSED_OOPS;
263         return resolve_barrier_gc<expanded_decorators>();
264       } else {
265         return resolve_barrier_gc<decorators>();
266       }
267     }
268 
269     static FunctionPointerT resolve_barrier() {
270       return resolve_barrier_rt();
271     }
272   };
273 
274   // Step 5.a: Barrier resolution
275   // The RuntimeDispatch class is responsible for performing a runtime dispatch of the
276   // accessor. This is required when the access either depends on whether compressed oops
277   // is being used, or it depends on which GC implementation was chosen (e.g. requires GC
278   // barriers). The way it works is that a function pointer initially pointing to an
279   // accessor resolution function gets called for each access. Upon first invocation,
280   // it resolves which accessor to be used in future invocations and patches the
281   // function pointer to this new accessor.
282 
283   template <DecoratorSet decorators, typename T>
284   void RuntimeDispatch<decorators, T, BARRIER_STORE>::store_init(void* addr, T value) {
285     func_t function = BarrierResolver<decorators, func_t, BARRIER_STORE>::resolve_barrier();
286     _store_func = function;
287     function(addr, value);
288   }
289 
290   template <DecoratorSet decorators, typename T>
291   void RuntimeDispatch<decorators, T, BARRIER_STORE_AT>::store_at_init(oop base, ptrdiff_t offset, T value) {
292     func_t function = BarrierResolver<decorators, func_t, BARRIER_STORE_AT>::resolve_barrier();
293     _store_at_func = function;
294     function(base, offset, value);
295   }
296 
297   template <DecoratorSet decorators, typename T>
298   T RuntimeDispatch<decorators, T, BARRIER_LOAD>::load_init(void* addr) {
299     func_t function = BarrierResolver<decorators, func_t, BARRIER_LOAD>::resolve_barrier();
300     _load_func = function;
301     return function(addr);
302   }
303 
304   template <DecoratorSet decorators, typename T>
305   T RuntimeDispatch<decorators, T, BARRIER_LOAD_AT>::load_at_init(oop base, ptrdiff_t offset) {
306     func_t function = BarrierResolver<decorators, func_t, BARRIER_LOAD_AT>::resolve_barrier();
307     _load_at_func = function;
308     return function(base, offset);
309   }
310 
311   template <DecoratorSet decorators, typename T>
312   T RuntimeDispatch<decorators, T, BARRIER_ATOMIC_CMPXCHG>::atomic_cmpxchg_init(T new_value, void* addr, T compare_value) {
313     func_t function = BarrierResolver<decorators, func_t, BARRIER_ATOMIC_CMPXCHG>::resolve_barrier();
314     _atomic_cmpxchg_func = function;
315     return function(new_value, addr, compare_value);
316   }
317 
318   template <DecoratorSet decorators, typename T>
319   T RuntimeDispatch<decorators, T, BARRIER_ATOMIC_CMPXCHG_AT>::atomic_cmpxchg_at_init(T new_value, oop base, ptrdiff_t offset, T compare_value) {
320     func_t function = BarrierResolver<decorators, func_t, BARRIER_ATOMIC_CMPXCHG_AT>::resolve_barrier();
321     _atomic_cmpxchg_at_func = function;
322     return function(new_value, base, offset, compare_value);
323   }
324 
325   template <DecoratorSet decorators, typename T>
326   T RuntimeDispatch<decorators, T, BARRIER_ATOMIC_XCHG>::atomic_xchg_init(T new_value, void* addr) {
327     func_t function = BarrierResolver<decorators, func_t, BARRIER_ATOMIC_XCHG>::resolve_barrier();
328     _atomic_xchg_func = function;
329     return function(new_value, addr);
330   }
331 
332   template <DecoratorSet decorators, typename T>
333   T RuntimeDispatch<decorators, T, BARRIER_ATOMIC_XCHG_AT>::atomic_xchg_at_init(T new_value, oop base, ptrdiff_t offset) {
334     func_t function = BarrierResolver<decorators, func_t, BARRIER_ATOMIC_XCHG_AT>::resolve_barrier();
335     _atomic_xchg_at_func = function;
336     return function(new_value, base, offset);
337   }
338 
339   template <DecoratorSet decorators, typename T>
340   bool RuntimeDispatch<decorators, T, BARRIER_ARRAYCOPY>::arraycopy_init(arrayOop src_obj, arrayOop dst_obj, T *src, T* dst, size_t length) {
341     func_t function = BarrierResolver<decorators, func_t, BARRIER_ARRAYCOPY>::resolve_barrier();
342     _arraycopy_func = function;
343     return function(src_obj, dst_obj, src, dst, length);
344   }
345 
346   template <DecoratorSet decorators, typename T>
347   void RuntimeDispatch<decorators, T, BARRIER_CLONE>::clone_init(oop src, oop dst, size_t size) {
348     func_t function = BarrierResolver<decorators, func_t, BARRIER_CLONE>::resolve_barrier();
349     _clone_func = function;
350     function(src, dst, size);
351   }
352 
353   template <DecoratorSet decorators, typename T>
354   oop RuntimeDispatch<decorators, T, BARRIER_RESOLVE>::resolve_init(oop obj) {
355     func_t function = BarrierResolver<decorators, func_t, BARRIER_RESOLVE>::resolve_barrier();
356     _resolve_func = function;
357     return function(obj);
358   }
359 
360   template <DecoratorSet decorators, typename T>
361   bool RuntimeDispatch<decorators, T, BARRIER_EQUALS>::equals_init(oop o1, oop o2) {
362     func_t function = BarrierResolver<decorators, func_t, BARRIER_EQUALS>::resolve_barrier();
363     _equals_func = function;
364     return function(o1, o2);
365   }
366 }
367 
368 #endif // SHARE_OOPS_ACCESS_INLINE_HPP