1 /*
  2  * Copyright (c) 2022, Red Hat, Inc. 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 "jni.h"
 26 #include "jvm.h"
 27 #include "classfile/javaClasses.inline.hpp"
 28 #include "gc/shared/collectedHeap.hpp"
 29 #include "oops/arrayOop.hpp"
 30 #include "oops/instanceKlass.inline.hpp"
 31 #include "oops/oop.inline.hpp"
 32 #include "oops/oopsHierarchy.hpp"
 33 #include "runtime/interfaceSupport.inline.hpp"
 34 #include "runtime/jniHandles.inline.hpp"
 35 #include "runtime/os.hpp"
 36 #include "runtime/orderAccess.hpp"
 37 #include "utilities/macros.hpp"
 38 
 39 #include OS_CPU_HEADER_INLINE(os)
 40 
 41 /**
 42  * Implementation of the net.shipilev.Magic
 43  */
 44 
 45 JVM_ENTRY(static jlong, NetShipilevMagic_timestamp(JNIEnv *env, jclass cls)) {
 46 #if defined(X86) && !defined(ZERO)
 47   return os::rdtsc();
 48 #else
 49   return -1;
 50 #endif
 51 } JVM_END
 52 
 53 JVM_ENTRY(static jlong, NetShipilevMagic_timestamp_serial(JNIEnv *env, jclass cls)) {
 54 #if defined(X86) && !defined(ZERO)
 55   // Rely on rdtscp intrinsic to make the right thing
 56   // serialization-wise. In these fallback/interpreter paths,
 57   // just bite the bullet and do the fence.
 58   OrderAccess::fence();
 59   return os::rdtsc();
 60 #else
 61   return -1;
 62 #endif
 63 } JVM_END
 64 
 65 JVM_ENTRY(jlong, NetShipilevMagic_sizeOf(JNIEnv *env, jclass cls, jobject obj))
 66   assert(obj != nullptr, "object must not be null");
 67 
 68   oop o = JNIHandles::resolve_non_null(obj);
 69   return o->size()*HeapWordSize;
 70 JVM_END
 71 
 72 JVM_ENTRY(jlong, NetShipilevMagic_addressOf(JNIEnv *env, jclass cls, jobject obj))
 73   assert(obj != nullptr, "object must not be null");
 74 
 75   oop o = JNIHandles::resolve_non_null(obj);
 76   return cast_from_oop<jlong>(o);
 77 JVM_END
 78 
 79 JVM_ENTRY(jlong, NetShipilevMagic_fieldOffsetOf(JNIEnv *env, jclass cls, jobject field))
 80   assert(field != nullptr, "field must not be null");
 81 
 82   oop f    = JNIHandles::resolve_non_null(field);
 83   oop m    = java_lang_reflect_Field::clazz(f);
 84   Klass* k = java_lang_Class::as_Klass(m);
 85   int slot = java_lang_reflect_Field::slot(f);
 86 
 87   return InstanceKlass::cast(k)->field_offset(slot);
 88 JVM_END
 89 
 90 JVM_ENTRY(jlong, NetShipilevMagic_fieldSizeOf(JNIEnv *env, jclass cls, jobject field))
 91   assert(field != nullptr, "field must not be null");
 92 
 93   oop f    = JNIHandles::resolve_non_null(field);
 94   oop m    = java_lang_reflect_Field::clazz(f);
 95   Klass* k = java_lang_Class::as_Klass(m);
 96   int slot = java_lang_reflect_Field::slot(f);
 97 
 98   Symbol* sig = InstanceKlass::cast(k)->field_signature(slot);
 99   switch (sig->char_at(0)) {
100     case JVM_SIGNATURE_CLASS    :
101     case JVM_SIGNATURE_ARRAY    : return type2aelembytes(T_OBJECT);
102     case JVM_SIGNATURE_BYTE     : return type2aelembytes(T_BYTE);
103     case JVM_SIGNATURE_CHAR     : return type2aelembytes(T_CHAR);
104     case JVM_SIGNATURE_FLOAT    : return type2aelembytes(T_FLOAT);
105     case JVM_SIGNATURE_DOUBLE   : return type2aelembytes(T_DOUBLE);
106     case JVM_SIGNATURE_INT      : return type2aelembytes(T_INT);
107     case JVM_SIGNATURE_LONG     : return type2aelembytes(T_LONG);
108     case JVM_SIGNATURE_SHORT    : return type2aelembytes(T_SHORT);
109     case JVM_SIGNATURE_BOOLEAN  : return type2aelembytes(T_BOOLEAN);
110   }
111 
112   ShouldNotReachHere();
113   return 0;
114 JVM_END
115 
116 class GetReferencedObjectsClosure : public BasicOopIterateClosure {
117 private:
118   objArrayOopDesc* const _result;
119   int _count;
120 public:
121   GetReferencedObjectsClosure(objArrayOopDesc* result) : _result(result), _count(0) {}
122 
123   template <typename T> void do_oop_nv(T* p) {
124     oop o = HeapAccess<>::oop_load(p);
125     if (!CompressedOops::is_null(o)) {
126       _result->obj_at_put(_count++, o);
127     }
128   }
129 
130   int count() { return _count; }
131 
132   virtual void do_oop(oop* p)       { do_oop_nv(p); }
133   virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
134 };
135 
136 JVM_ENTRY(jint, NetShipilevMagic_getReferencedObjects(JNIEnv *env, jclass cls, jobject obj_ref, jobjectArray ref_buf_ref))
137   oop obj = JNIHandles::resolve_non_null(obj_ref);
138   objArrayOop ref_buf = objArrayOop(JNIHandles::resolve_non_null(ref_buf_ref));
139 
140   assert(Universe::heap()->is_in(obj), "object should be in heap: " PTR_FORMAT, p2i(obj));
141   assert(Universe::heap()->is_in(ref_buf), "ref buf should be in heap: " PTR_FORMAT, p2i(ref_buf));
142 
143   InstanceKlass* k = InstanceKlass::cast(obj->klass());
144 
145   int count = 0;
146   {
147     InstanceKlass* ik = k;
148     while (ik != nullptr) {
149       count += ik->nonstatic_oop_field_count();
150       ik = ik->super();
151     }
152   }
153 
154   if (count == 0) {
155     return 0;
156   }
157 
158   if (count > ref_buf->length()) {
159     return -1;
160   }
161 
162   GetReferencedObjectsClosure cl(ref_buf);
163 
164 #ifdef _LP64
165   if (UseCompressedOops) {
166     k->oop_oop_iterate<narrowOop>(obj, &cl);
167   } else
168 #endif
169   {
170     k->oop_oop_iterate<oop>(obj, &cl);
171   }
172 
173   return cl.count();
174 JVM_END
175 
176 /// JVM_RegisterUnsafeMethods
177 
178 #define CC (char*)  /*cast a literal from (const char*)*/
179 #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
180 
181 #define LANG "Ljava/lang/"
182 
183 #define OBJ LANG "Object;"
184 #define CLS LANG "Class;"
185 #define FLD LANG "reflect/Field;"
186 
187 static JNINativeMethod net_shipilev_Magic_methods[] = {
188   {CC "timestamp",            CC "()J",                 FN_PTR(NetShipilevMagic_timestamp)},
189   {CC "timestampSerial",      CC "()J",                 FN_PTR(NetShipilevMagic_timestamp_serial)},
190   {CC "sizeOf0",              CC "(" OBJ ")J",          FN_PTR(NetShipilevMagic_sizeOf)},
191   {CC "addressOf0",           CC "(" OBJ ")J",          FN_PTR(NetShipilevMagic_addressOf)},
192   {CC "getReferencedObjects", CC "(" OBJ "[" OBJ ")I",  FN_PTR(NetShipilevMagic_getReferencedObjects)},
193   {CC "fieldOffsetOf0",       CC "(" FLD ")J",          FN_PTR(NetShipilevMagic_fieldOffsetOf)},
194   {CC "fieldSizeOf0",         CC "(" FLD ")J",          FN_PTR(NetShipilevMagic_fieldSizeOf)},
195 };
196 
197 #undef LANG
198 #undef OBJ
199 #undef CLS
200 #undef FLD
201 
202 #undef CC
203 #undef FN_PTR
204 
205 JVM_ENTRY(void, JVM_RegisterNetShipilevMagicMethods(JNIEnv *env, jclass cls)) {
206   ThreadToNativeFromVM ttnfv(thread);
207 
208   int ok = env->RegisterNatives(cls, net_shipilev_Magic_methods, sizeof(net_shipilev_Magic_methods)/sizeof(JNINativeMethod));
209   guarantee(ok == 0, "register net.shipilev.Magic natives");
210 } JVM_END