< prev index next >

src/hotspot/share/prims/jvmtiImpl.cpp

Print this page
@@ -1,7 +1,7 @@
  /*
-  * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
+  * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.

@@ -46,11 +46,11 @@
  #include "runtime/frame.inline.hpp"
  #include "runtime/handles.inline.hpp"
  #include "runtime/interfaceSupport.inline.hpp"
  #include "runtime/javaCalls.hpp"
  #include "runtime/javaThread.hpp"
- #include "runtime/jniHandles.hpp"
+ #include "runtime/jniHandles.inline.hpp"
  #include "runtime/os.hpp"
  #include "runtime/serviceThread.hpp"
  #include "runtime/signature.hpp"
  #include "runtime/threadSMR.hpp"
  #include "runtime/vframe.inline.hpp"

@@ -325,10 +325,11 @@
    , _type(type)
    , _value(value)
    , _jvf(nullptr)
    , _set(set)
    , _self(self)
+   , _need_clone(false)
    , _result(JVMTI_ERROR_NONE)
  {
  }
  
  // Check that the klass is assignable to a type with the given signature.

@@ -474,10 +475,38 @@
      return false;
    }
    return true;
  }
  
+ void VM_BaseGetOrSetLocal::check_and_clone_this_value_object() {
+   oop obj = JNIHandles::resolve(_value.l);
+   HandleMark hm(_calling_thread);
+   Handle obj_h(_calling_thread, obj);
+ 
+   assert(_type == T_OBJECT, "sanity check");
+   assert(obj != nullptr, "expected non-null oop");
+   assert(obj_h()->is_inline(), "expected inline oop");
+   assert(_index == 0, "expected slot 0 for THIS object");
+ 
+   InlineKlass* klass = InlineKlass::cast(obj_h()->klass());
+   inlineOop obj_copy = klass->allocate_instance(_calling_thread);
+   if (obj_copy == nullptr) {
+     _result = JVMTI_ERROR_OUT_OF_MEMORY;
+   } else {
+     inlineOop thisObj = inlineOop(obj_h());
+     // copy object payload into the object snapshot
+     BufferedValuePayload src(thisObj);
+     BufferedValuePayload dst(obj_copy, klass);
+     src.copy_to(dst);
+ 
+     // Must ensure the content of the buffered value is visible
+     // before publishing the buffered value oop
+     OrderAccess::storestore();
+   }
+   _value.l = JNIHandles::make_local(_calling_thread, obj_copy);
+ }
+ 
  static bool can_be_deoptimized(vframe* vf) {
    return (vf->is_compiled_frame() && vf->fr().can_be_deoptimized());
  }
  
  bool VM_GetOrSetLocal::doit_prologue() {

@@ -608,19 +637,32 @@
          case T_DOUBLE: _value.d = locals->double_at(_index);   break;
          case T_OBJECT: {
            // Wrap the oop to be returned in a local JNI handle since
            // oops_do() no longer applies after doit() is finished.
            oop obj = locals->obj_at(_index)();
+ 
+           if (Arguments::is_valhalla_enabled()) {
+             bool is_ctor = _jvf->method()->is_object_constructor();
+             if (is_ctor && _index == 0 && obj != nullptr && obj->is_inline()) {
+               _need_clone = true; // need to allocate an object snapshot in doit_epilogue
+             }
+           }
            _value.l = JNIHandles::make_local(_calling_thread, obj);
            break;
          }
          default: ShouldNotReachHere();
        }
      }
    }
  }
  
+ void VM_BaseGetOrSetLocal::doit_epilogue() {
+   if (_need_clone) {
+     check_and_clone_this_value_object();
+   }
+ }
+ 
  bool VM_BaseGetOrSetLocal::allow_nested_vm_operations() const {
    return true; // May need to deoptimize
  }
  
  
< prev index next >