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 #include "precompiled.hpp"
  26 #include "classfile/symbolTable.hpp"
  27 #include "classfile/systemDictionary.hpp"
  28 #include "jfr/jni/jfrJavaCall.hpp"
  29 #include "jfr/jni/jfrJavaSupport.hpp"
  30 #include "memory/resourceArea.hpp"
  31 #include "runtime/handles.inline.hpp"
  32 #include "runtime/javaCalls.hpp"
  33 #include "utilities/globalDefinitions.hpp"
  34 
  35 #ifdef ASSERT
  36 static bool is_large_value(const JavaValue& value) {
  37   return value.get_type() == T_LONG || value.get_type() == T_DOUBLE;
  38 }
  39 #endif // ASSERT
  40 
  41 static Symbol* resolve(const char* str, TRAPS) {
  42   assert(str != NULL, "invariant");
  43   return SymbolTable::lookup(str, (int)strlen(str), THREAD);
  44 }
  45 
  46 static Klass* resolve(Symbol* k_sym, TRAPS) {
  47   assert(k_sym != NULL, "invariant");
  48   return SystemDictionary::resolve_or_fail(k_sym, true, THREAD);
  49 }
  50 
  51 JfrJavaArguments::Parameters::Parameters() : _storage_index(0), _java_stack_slots(0) {
  52   JavaValue value(T_VOID);
  53   push(value);
  54 }
  55 
  56 void JfrJavaArguments::Parameters::push(const JavaValue& value) {
  57   assert(_storage != NULL, "invariant");
  58   assert(!is_large_value(value), "invariant");
  59   assert(_storage_index < SIZE, "invariant");
  60   _storage[_storage_index++] = value;
  61   _java_stack_slots++;
  62 }
  63 
  64 void JfrJavaArguments::Parameters::push_large(const JavaValue& value) {
  65   assert(_storage != NULL, "invariant");
  66   assert(is_large_value(value), "invariant");
  67   assert(_storage_index < SIZE, "invariant");
  68   _storage[_storage_index++] = value;
  69   _java_stack_slots += 2;
  70 }
  71 
  72 void JfrJavaArguments::Parameters::set_receiver(const oop receiver) {
  73   assert(_storage != NULL, "invariant");
  74   assert(receiver != NULL, "invariant");
  75   JavaValue value(T_OBJECT);
  76   value.set_jobject((jobject)receiver);
  77   _storage[0] = value;
  78 }
  79 
  80 void JfrJavaArguments::Parameters::set_receiver(Handle receiver) {
  81   set_receiver(receiver());
  82 }
  83 
  84 oop JfrJavaArguments::Parameters::receiver() const {
  85   assert(has_receiver(), "invariant");
  86   assert(_storage[0].get_type() == T_OBJECT, "invariant");
  87   return (oop)_storage[0].get_jobject();
  88 }
  89 
  90 bool JfrJavaArguments::Parameters::has_receiver() const {
  91   assert(_storage != NULL, "invariant");
  92   assert(_storage_index >= 1, "invariant");
  93   assert(_java_stack_slots >= 1, "invariant");
  94   return _storage[0].get_type() == T_OBJECT;
  95 }
  96 
  97 void JfrJavaArguments::Parameters::push_oop(const oop obj) {
  98   JavaValue value(T_OBJECT);
  99   value.set_jobject((jobject)obj);
 100   push(value);
 101 }
 102 
 103 void JfrJavaArguments::Parameters::push_oop(Handle h_obj) {
 104   push_oop(h_obj());
 105 }
 106 
 107 void JfrJavaArguments::Parameters::push_jobject(jobject h) {
 108   JavaValue value(T_ADDRESS);
 109   value.set_jobject(h);
 110   push(value);
 111 }
 112 
 113 void JfrJavaArguments::Parameters::push_jint(jint i) {
 114   JavaValue value(T_INT);
 115   value.set_jint(i);
 116   push(value);
 117 }
 118 
 119 void JfrJavaArguments::Parameters::push_jfloat(jfloat f) {
 120   JavaValue value(T_FLOAT);
 121   value.set_jfloat(f);
 122   push(value);
 123 }
 124 
 125 void JfrJavaArguments::Parameters::push_jdouble(jdouble d) {
 126   JavaValue value(T_DOUBLE);
 127   value.set_jdouble(d);
 128   push_large(value);
 129 }
 130 
 131 void JfrJavaArguments::Parameters::push_jlong(jlong l) {
 132   JavaValue value(T_LONG);
 133   value.set_jlong(l);
 134   push_large(value);
 135 }
 136 
 137 // including receiver (even if there is none)
 138 inline int JfrJavaArguments::Parameters::length() const {
 139   assert(_storage_index >= 1, "invariant");
 140   return _storage_index;
 141 }
 142 
 143 inline int JfrJavaArguments::Parameters::java_stack_slots() const {
 144   return _java_stack_slots;
 145 }
 146 
 147 const JavaValue& JfrJavaArguments::Parameters::values(int idx) const {
 148   assert(idx >= 0, "invariant");
 149   assert(idx < SIZE, "invariant");
 150   return _storage[idx];
 151 }
 152 
 153 void JfrJavaArguments::Parameters::copy(JavaCallArguments& args, TRAPS) const {
 154   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
 155   if (has_receiver()) {
 156     args.set_receiver(Handle(THREAD, receiver()));
 157   }
 158   for (int i = 1; i < length(); ++i) {
 159     switch(values(i).get_type()) {
 160       case T_BOOLEAN:
 161       case T_CHAR:
 162       case T_SHORT:
 163       case T_INT:
 164         args.push_int(values(i).get_jint());
 165         break;
 166       case T_LONG:
 167         args.push_long(values(i).get_jlong());
 168         break;
 169       case T_FLOAT:
 170         args.push_float(values(i).get_jfloat());
 171         break;
 172       case T_DOUBLE:
 173         args.push_double(values(i).get_jdouble());
 174         break;
 175       case T_OBJECT:
 176         args.push_oop(Handle(THREAD, (oop)values(i).get_jobject()));
 177         break;
 178       case T_ADDRESS:
 179         args.push_oop(Handle(THREAD, JNIHandles::resolve(values(i).get_jobject())));
 180         break;
 181       default:
 182         ShouldNotReachHere();
 183     }
 184   }
 185 }
 186 
 187 JfrJavaArguments::JfrJavaArguments(JavaValue* result) : _result(result), _klass(NULL), _name(NULL), _signature(NULL), _array_length(0) {
 188   assert(result != NULL, "invariant");
 189 }
 190 
 191 JfrJavaArguments::JfrJavaArguments(JavaValue* result, const char* klass_name, const char* name, const char* signature, TRAPS) :
 192   _result(result),
 193   _klass(NULL),
 194   _name(NULL),
 195   _signature(NULL),
 196   _array_length(0) {
 197   assert(result != NULL, "invariant");
 198   if (klass_name != NULL) {
 199     set_klass(klass_name, CHECK);
 200   }
 201   if (name != NULL) {
 202     set_name(name, CHECK);
 203   }
 204   if (signature != NULL) {
 205     set_signature(signature, THREAD);
 206   }
 207 }
 208 
 209 JfrJavaArguments::JfrJavaArguments(JavaValue* result, const Klass* klass, const Symbol* name, const Symbol* signature) : _result(result),
 210   _klass(NULL),
 211   _name(NULL),
 212   _signature(NULL),
 213   _array_length(0) {
 214   assert(result != NULL, "invariant");
 215   if (klass != NULL) {
 216     set_klass(klass);
 217   }
 218   if (name != NULL) {
 219     set_name(name);
 220   }
 221   if (signature != NULL) {
 222     set_signature(signature);
 223   }
 224 }
 225 
 226 Klass* JfrJavaArguments::klass() const {
 227   assert(_klass != NULL, "invariant");
 228   return const_cast<Klass*>(_klass);
 229 }
 230 
 231 void JfrJavaArguments::set_klass(const char* klass_name, TRAPS) {
 232   assert(klass_name != NULL, "invariant");
 233   Symbol* const k_sym = resolve(klass_name, CHECK);
 234   assert(k_sym != NULL, "invariant");
 235   const Klass* const klass = resolve(k_sym, CHECK);
 236   set_klass(klass);
 237 }
 238 
 239 void JfrJavaArguments::set_klass(const Klass* klass) {
 240   assert(klass != NULL, "invariant");
 241   _klass = klass;
 242 }
 243 
 244 Symbol* JfrJavaArguments::name() const {
 245   assert(_name != NULL, "invariant");
 246   return const_cast<Symbol*>(_name);
 247 }
 248 
 249 void JfrJavaArguments::set_name(const char* name, TRAPS) {
 250   assert(name != NULL, "invariant");
 251   const Symbol* const sym = resolve(name, CHECK);
 252   set_name(sym);
 253 }
 254 
 255 void JfrJavaArguments::set_name(const Symbol* name) {
 256   assert(name != NULL, "invariant");
 257   _name = name;
 258 }
 259 
 260 Symbol* JfrJavaArguments::signature() const {
 261   assert(_signature != NULL, "invariant");
 262   return const_cast<Symbol*>(_signature);
 263 }
 264 
 265 void JfrJavaArguments::set_signature(const char* signature, TRAPS) {
 266   assert(signature != NULL, "invariant");
 267   const Symbol* const sym = resolve(signature, CHECK);
 268   set_signature(sym);
 269 }
 270 
 271 void JfrJavaArguments::set_signature(const Symbol* signature) {
 272   assert(signature != NULL, "invariant");
 273   _signature = signature;
 274 }
 275 
 276 int JfrJavaArguments::array_length() const {
 277   return _array_length;
 278 }
 279 
 280 void JfrJavaArguments::set_array_length(int length) {
 281   assert(length >= 0, "invariant");
 282   _array_length = length;
 283 }
 284 
 285 JavaValue* JfrJavaArguments::result() const {
 286   assert(_result != NULL, "invariant");
 287   return const_cast<JavaValue*>(_result);
 288 }
 289 
 290 int JfrJavaArguments::length() const {
 291   return _params.length();
 292 }
 293 
 294 bool JfrJavaArguments::has_receiver() const {
 295   return _params.has_receiver();
 296 }
 297 
 298 oop JfrJavaArguments::receiver() const {
 299   return _params.receiver();
 300 }
 301 
 302 void JfrJavaArguments::set_receiver(const oop receiver) {
 303   _params.set_receiver(receiver);
 304 }
 305 
 306 void JfrJavaArguments::set_receiver(Handle receiver) {
 307   _params.set_receiver(receiver);
 308 }
 309 
 310 void JfrJavaArguments::push_oop(const oop obj) {
 311   _params.push_oop(obj);
 312 }
 313 
 314 void JfrJavaArguments::push_oop(Handle h_obj) {
 315   _params.push_oop(h_obj);
 316 }
 317 
 318 void JfrJavaArguments::push_jobject(jobject h) {
 319   _params.push_jobject(h);
 320 }
 321 
 322 void JfrJavaArguments::push_int(jint i) {
 323   _params.push_jint(i);
 324 }
 325 
 326 void JfrJavaArguments::push_float(jfloat f) {
 327   _params.push_jfloat(f);
 328 }
 329 
 330 void JfrJavaArguments::push_double(jdouble d) {
 331   _params.push_jdouble(d);
 332 }
 333 
 334 void JfrJavaArguments::push_long(jlong l) {
 335   _params.push_jlong(l);
 336 }
 337 
 338 const JavaValue& JfrJavaArguments::param(int idx) const {
 339   return _params.values(idx);
 340 }
 341 
 342 int JfrJavaArguments::java_call_arg_slots() const {
 343   return _params.java_stack_slots();
 344 }
 345 
 346 void JfrJavaArguments::copy(JavaCallArguments& args, TRAPS) {
 347   _params.copy(args, THREAD);
 348 }
 349 
 350 void JfrJavaCall::call_static(JfrJavaArguments* args, TRAPS) {
 351   assert(args != NULL, "invariant");
 352   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
 353   ResourceMark rm(THREAD);
 354   HandleMark hm(THREAD);
 355   JavaCallArguments jcas(args->java_call_arg_slots());
 356   args->copy(jcas, CHECK);
 357   JavaCalls::call_static(args->result(), args->klass(), args->name(), args->signature(), &jcas, THREAD);
 358 }
 359 
 360 void JfrJavaCall::call_special(JfrJavaArguments* args, TRAPS) {
 361   assert(args != NULL, "invariant");
 362   assert(args->has_receiver(), "invariant");
 363   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
 364   ResourceMark rm(THREAD);
 365   HandleMark hm(THREAD);
 366   JavaCallArguments jcas(args->java_call_arg_slots());
 367   args->copy(jcas, CHECK);
 368   JavaCalls::call_special(args->result(), args->klass(), args->name(), args->signature(), &jcas, THREAD);
 369 }
 370 
 371 void JfrJavaCall::call_virtual(JfrJavaArguments* args, TRAPS) {
 372   assert(args != NULL, "invariant");
 373   assert(args->has_receiver(), "invariant");
 374   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
 375   ResourceMark rm(THREAD);
 376   HandleMark hm(THREAD);
 377   JavaCallArguments jcas(args->java_call_arg_slots());
 378   args->copy(jcas, CHECK);
 379   JavaCalls::call_virtual(args->result(), args->klass(), args->name(), args->signature(), &jcas, THREAD);
 380 }