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