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