diff --git a/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp b/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp index a41b2ee606b..3507cc631ff 100644 --- a/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp +++ b/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp @@ -283,7 +283,7 @@ inline void ThawBase::patch_pd(frame& f, intptr_t* caller_sp) { inline void ThawBase::fix_native_wrapper_return_pc_pd(frame& top) { bool from_interpreted = top.is_interpreted_frame(); - address resume_address = from_interpreted ? Interpreter::native_frame_resume_entry() : SharedRuntime::native_frame_resume_entry(); + address resume_address = from_interpreted ? Interpreter::native_frame_resume_entry() : (top.pc() + SharedRuntime::object_wait_resume_offset()); DEBUG_ONLY(Method* method = from_interpreted ? top.interpreter_frame_method() : CodeCache::find_blob(resume_address)->as_nmethod()->method();) assert(method->is_object_wait0(), ""); ContinuationHelper::Frame::patch_pc(top, resume_address); diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index 93d75c3809a..4a8f8049ac5 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -2374,7 +2374,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ movl(Address(r15_thread, JavaThread::thread_state_offset()), _thread_in_Java); __ bind(after_transition); - int resume_wait_offset = 0; if (LockingMode != LM_LEGACY && method->is_object_wait0()) { // Check preemption for Object.wait() Label not_preempted; @@ -2384,7 +2383,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ movptr(Address(r15_thread, JavaThread::preempt_alternate_return_offset()), NULL_WORD); __ jmp(rscratch1); __ bind(not_preempted); - resume_wait_offset = ((intptr_t)__ pc()) - start; + SharedRuntime::set_object_wait_resume_offset(((intptr_t)__ pc()) - the_pc); } Label reguard; @@ -2606,10 +2605,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, in_ByteSize(lock_slot_offset*VMRegImpl::stack_slot_size), oop_maps); - if (LockingMode != LM_LEGACY && nm != nullptr && method->is_object_wait0()) { - SharedRuntime::set_native_frame_resume_entry(nm->code_begin() + resume_wait_offset); - } - return nm; } diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp index dc94dc73e76..344ef7802a2 100644 --- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp +++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp @@ -347,9 +347,6 @@ bool VM_RedefineClasses::is_modifiable_class(oop klass_mirror) { if (InstanceKlass::cast(k)->is_hidden()) { return false; } - if (InstanceKlass::cast(k) == vmClasses::Object_klass()) { - return false; - } if (InstanceKlass::cast(k) == vmClasses::Continuation_klass()) { // Don't redefine Continuation class. See 8302779. return false; diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index 0c7cf87f57d..479bc00b393 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -3000,15 +3000,16 @@ static void log_frames_after_thaw(JavaThread* thread, ContinuationWrapper& cont, sp0 += frame::metadata_words; } else { // Compiled case: + CodeBlob* cb = CodeCache::find_blob(pc0); + assert(cb != nullptr, ""); #if defined (AMD64) - if (pc0 == SharedRuntime::native_frame_resume_entry()) { + if (cb->is_nmethod()) { + assert(cb->as_nmethod()->method()->is_object_wait0(), ""); // For x64, when top is the compiled native wrapper (Object.wait()) // the pc would have been modified from its original value to return // to the correct place. But that means we won't find the oopMap for // that fixed pc when getting the sender which will trigger asserts. // So just start walking the frames from the sender instead. - CodeBlob* cb = CodeCache::find_blob(pc0); - assert(cb->as_nmethod()->method()->is_object_wait0(), ""); sp0 += cb->frame_size(); if (sp0 == cont.entrySP()) { // sp0[-1] will be the return barrier pc. This is a stub, i.e. associated @@ -3018,9 +3019,8 @@ static void log_frames_after_thaw(JavaThread* thread, ContinuationWrapper& cont, } } #elif defined (AARCH64) || defined (RISCV64) - CodeBlob* cb = CodeCache::find_blob(pc0); - assert(cb != nullptr, "should be either c1 or c2 runtime stub"); if (cb->frame_size() == 2) { + assert(cb->is_runtime_stub(), ""); // Returning to c2 runtime stub requires extra adjustment on aarch64 // and riscv64 (see push_resume_adapter()). sp0 += frame::metadata_words; diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 06f497c0bc8..a72149fd0a3 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -99,7 +99,7 @@ SHARED_STUBS_DO(SHARED_STUB_FIELD_DEFINE) #undef SHARED_STUB_FIELD_DEFINE -address SharedRuntime::_native_frame_resume_entry = nullptr; +int SharedRuntime::_object_wait_resume_offset = 0; nmethod* SharedRuntime::_cont_doYield_stub; diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index 56fec1129ab..c3d7458d67e 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.hpp @@ -88,7 +88,7 @@ class SharedRuntime: AllStatic { #endif - static address _native_frame_resume_entry; + static int _object_wait_resume_offset; // cont_doYieldStub is not yet folded into the general model for // shared stub/blob handling. It is actually a specially generated @@ -243,10 +243,10 @@ class SharedRuntime: AllStatic { address faulting_pc, ImplicitExceptionKind exception_kind); - static address native_frame_resume_entry() { return _native_frame_resume_entry; } - static void set_native_frame_resume_entry(address val) { - assert(_native_frame_resume_entry == nullptr, ""); - _native_frame_resume_entry = val; + static int object_wait_resume_offset() { return _object_wait_resume_offset; } + static void set_object_wait_resume_offset(int offset) { + assert(_object_wait_resume_offset == 0, ""); + _object_wait_resume_offset = offset; } // Post-slow-path-allocation, pre-initializing-stores step for diff --git a/test/hotspot/jtreg/TEST.quick-groups b/test/hotspot/jtreg/TEST.quick-groups index 0612e56826f..fa1f7f5634e 100644 --- a/test/hotspot/jtreg/TEST.quick-groups +++ b/test/hotspot/jtreg/TEST.quick-groups @@ -1185,6 +1185,7 @@ vmTestbase_nsk_jvmti_quick = \ vmTestbase/nsk/jvmti/scenarios/bcinstr/BI02/bi02t002/TestDescription.java \ vmTestbase/nsk/jvmti/scenarios/bcinstr/BI03/bi03t001/TestDescription.java \ vmTestbase/nsk/jvmti/scenarios/bcinstr/BI03/bi03t002/TestDescription.java \ + vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002/TestDescription.java \ vmTestbase/nsk/jvmti/scenarios/capability/CM01/cm01t001/TestDescription.java \ vmTestbase/nsk/jvmti/scenarios/capability/CM01/cm01t002/TestDescription.java \ vmTestbase/nsk/jvmti/scenarios/capability/CM01/cm01t003/TestDescription.java \ diff --git a/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineObject.java b/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineObject.java index d8bedb1fbdc..0490d11b6c8 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineObject.java +++ b/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineObject.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2021, 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 @@ -23,22 +23,37 @@ /* * @test - * @summary Tests that java.lang.Object cannot be redefined/retransformed + * @bug 8232613 + * @summary Ensure Object natives stay registered after redefinition * @requires vm.jvmti * @library /test/lib - * @modules java.instrument + * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.org.objectweb.asm + * java.compiler + * java.instrument * jdk.jartool/sun.tools.jar * @run main RedefineObject buildagent * @run main/othervm -javaagent:redefineagent.jar RedefineObject */ +import static jdk.test.lib.Asserts.assertTrue; import jdk.test.lib.helpers.ClassFileInstaller; import java.io.FileNotFoundException; import java.io.PrintWriter; +import java.lang.RuntimeException; import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.IllegalClassFormatException; import java.lang.instrument.Instrumentation; import java.lang.instrument.UnmodifiableClassException; import java.security.ProtectionDomain; +import java.util.Arrays; + +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.ClassWriter; + +import static jdk.internal.org.objectweb.asm.Opcodes.ASM6; +import static jdk.internal.org.objectweb.asm.Opcodes.V1_8; public class RedefineObject { @@ -49,23 +64,56 @@ public static void premain(String agentArgs, Instrumentation inst) { } static class Transformer implements ClassFileTransformer { - // set to true if transform method called to transform java.lang.Object - private boolean transformObjectInvoked; - @Override - public byte[] transform(ClassLoader loader, - String className, - Class classBeingRedefined, - ProtectionDomain protectionDomain, - byte[] classfileBuffer) { - if (className.contains("java/lang/Object")) { - transformObjectInvoked = true; + public byte[] asm(ClassLoader loader, String className, + Class classBeingRedefined, + ProtectionDomain protectionDomain, byte[] classfileBuffer) + throws IllegalClassFormatException { + ClassWriter cw = new ClassWriter(0); + // Force an older ASM to force a bytecode update + ClassVisitor cv = new DummyClassVisitor(ASM6, cw) { }; + ClassReader cr = new ClassReader(classfileBuffer); + cr.accept(cv, 0); + byte[] bytes = cw.toByteArray(); + return bytes; + } + + public class DummyClassVisitor extends ClassVisitor { + + public DummyClassVisitor(int api, ClassVisitor cv) { + super(api, cv); + } + + public void visit( + final int version, + final int access, + final String name, + final String signature, + final String superName, + final String[] interfaces) { + // Artificially lower to JDK 8 version to force a redefine + cv.visit(V1_8, access, name, signature, superName, interfaces); } - return null; } - boolean transformObjectInvoked() { - return transformObjectInvoked; + @Override public byte[] transform(ClassLoader loader, String className, + Class classBeingRedefined, + ProtectionDomain protectionDomain, byte[] classfileBuffer) + throws IllegalClassFormatException { + + if (className.contains("java/lang/Object")) { + try { + // Here we remove and re-add the dummy fields. This shuffles the constant pool + return asm(loader, className, classBeingRedefined, protectionDomain, classfileBuffer); + } catch (Throwable e) { + // The retransform native code that called this method does not propagate + // exceptions. Instead of getting an uninformative generic error, catch + // problems here and print it, then exit. + e.printStackTrace(); + System.exit(1); + } + } + return null; } } @@ -76,10 +124,12 @@ private static void buildAgent() { throw new RuntimeException("Could not write agent classfile", e); } - try (PrintWriter pw = new PrintWriter("MANIFEST.MF")) { + try { + PrintWriter pw = new PrintWriter("MANIFEST.MF"); pw.println("Premain-Class: RedefineObject"); pw.println("Agent-Class: RedefineObject"); pw.println("Can-Retransform-Classes: true"); + pw.close(); } catch (FileNotFoundException e) { throw new RuntimeException("Could not write manifest file for the agent", e); } @@ -91,6 +141,9 @@ private static void buildAgent() { } public static void main(String[] args) throws Exception { + + int objHash = System.identityHashCode(Object.class); + System.out.println("Object hashCode: " + objHash); if (args.length == 1 && args[0].equals("buildagent")) { buildAgent(); return; @@ -100,20 +153,27 @@ public static void main(String[] args) throws Exception { throw new RuntimeException("Instrumentation object was null"); } - if (inst.isModifiableClass(Object.class)) { - throw new RuntimeException("java.lang.Object should not be modifable"); - } - - var transformer = new Transformer(); - inst.addTransformer(transformer, true); try { + inst.addTransformer(new RedefineObject.Transformer(), true); inst.retransformClasses(Object.class); - throw new RuntimeException("UnmodifiableClassException not thrown by retransformClasses"); } catch (UnmodifiableClassException e) { - // expected + throw new RuntimeException(e); } - if (transformer.transformObjectInvoked()) { - throw new RuntimeException(); + + // Exercise native methods on Object after transform + Object b = new Object(); + b.hashCode(); + + C c = new C(); + assertTrue(c.hashCode() != c.clone().hashCode() || c != c.clone()); + assertTrue(c.clone() instanceof C); + c = (C)c.clone(); // native method on new Object + } + + private static class C implements Cloneable { + @Override + protected Object clone() throws CloneNotSupportedException { + return super.clone(); } } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002.java new file mode 100644 index 00000000000..87a0de5d31d --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2004, 2018, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.jvmti.scenarios.bcinstr.BI04; + +import java.io.PrintStream; + +import nsk.share.Log; +import nsk.share.Consts; + +import nsk.share.jvmti.ArgumentHandler; +import nsk.share.jvmti.DebugeeClass; + +public class bi04t002 extends DebugeeClass { + + // run test from command line + public static void main(String argv[]) { + argv = nsk.share.jvmti.JVMTITest.commonInit(argv); + + // JCK-compatible exit + System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE); + } + + // run test from JCK-compatible environment + public static int run(String argv[], PrintStream out) { + return new bi04t002().runIt(argv, out); + } + + /* =================================================================== */ + + // scaffold objects + ArgumentHandler argHandler = null; + Log.Logger logger; + + /* =================================================================== */ + + // run debuggee + public int runIt(String argv[], PrintStream out) { + argHandler = new ArgumentHandler(argv); + Log log = new Log(out, argHandler); + logger = new Log.Logger(log,"debuggee> "); + + if (checkStatus(Consts.TEST_PASSED) != Consts.TEST_PASSED) { + return Consts.TEST_FAILED; + } + + //checking that instrumenetation code works + if (!checkInstrumentedMethods()) { + logger.complain("Test FAILED"); + return Consts.TEST_FAILED; + } + + logger.display("Test PASSED"); + return Consts.TEST_PASSED; + } + + /** Checks instrumented methods. */ + boolean checkInstrumentedMethods() { + //checking that instrumenetation code works + boolean result = true; + + logger.display("Checking instrumented methods"); + bi04t002b thrd = new bi04t002b(); + + synchronized(bi04t002b.started) { + thrd.start(); + try { + bi04t002b.started.wait(); + thrd.join(); + } catch (InterruptedException e) { + } + + } + + for (int i = 0; i < bi04t002a.TOTAL_INSTRUMENTED_METHODS; i++) { + + logger.display("instrumented method " + methodName(i) + + " was invoked " + + bi04t002a.invocationsCount[i] + " times"); + if (bi04t002a.invocationsCount[i] <= 0) { + logger.complain("Unexpected value " + bi04t002a.invocationsCount[i]); + result = false; + } + + } + return result; + } + + String methodName(int idx) { + switch (idx) { + case bi04t002a.INSTR_EQUALS: return "equals(Object)"; + case bi04t002a.INSTR_TOSTRING: return "toString()"; + case bi04t002a.INSTR_WAIT_JI: return "wait(long, int)"; + case bi04t002a.INSTR_WAIT: return "wait()"; + } + logger.complain("unknown method for " + idx + " index"); + return null; + } +} + +class bi04t002b extends Thread { + + Object obj = new Object(); + static Object started = new Object(); + + public void run() { + + synchronized(started) { + + started.notify(); + + Object obj1 = new Object(); + obj.equals(obj1); + obj.toString(); + + synchronized (obj) { + try { + obj.wait(1, 1); + } catch (InterruptedException e) { + // do nothing + } + } + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002/TestDescription.java new file mode 100644 index 00000000000..a57a2b3092d --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002/TestDescription.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2018, 2020, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/* + * @test + * + * @summary converted from VM Testbase nsk/jvmti/scenarios/bcinstr/BI04/bi04t002. + * VM Testbase keywords: [quick, jpda, jvmti, onload_only_logic, noras, redefine, no_cds] + * VM Testbase readme: + * DESCRIPTION + * This JVMTI test is developed against "bytecode instrumentation" area. + * The test performs the following actions: + * - instrument all java methods of java.lang.Object via RedefineClasses + * function; + * - check that instrumentation code works. + * There are some notes regarding new bytecode for java.lang.Object class: + * - new bytecode for java.lang.Object class is precompiled and its + * classfile is placed in $COMMON_CLASSES_LOCATION/newclass02 directory; + * - source of new bytecode for java.lang.Object is the modified original + * source file borrowed from JDK 1.5.0-beta2-b43, thus it should be + * compiled with the '-source 1.5' option; + * - every java-method of instrumeneted java.lang.Object class invokes + * a method of test which carries out special action in order to register + * invocation, so $COMMON_CLASSES_LOCATION/classes must be added to the + * default bootstrap class path; + * These points could be considered as a negative side of this tests. + * As alternative way - java.lang.Object could be instrumented by bytecode + * generated _on_the_fly_. But such implementation would complicate test. + * COMMENTS + * + * @library /vmTestbase + * /test/lib + * @build nsk.jvmti.scenarios.bcinstr.BI04.bi04t002 + * nsk.jvmti.scenarios.bcinstr.BI04.bi04t002a + * + * @comment compile newclassXX to bin/newclassXX + * @run driver ExecDriver --cmd + * ${compile.jdk}/bin/javac + * --patch-module java.base=${test.src}/newclass02/java.base + * -d bin/newclass02 + * -cp ${test.class.path} + * --add-reads=java.base=ALL-UNNAMED + * ${test.src}/newclass02/java.base/java/lang/Object.java + * + * @run main/othervm/native + * --add-reads=java.base=ALL-UNNAMED + * -XX:+UnlockDiagnosticVMOptions + * -XX:-CheckIntrinsics + * -Xbootclasspath/a:${test.class.path} + * -agentlib:bi04t002=pathToNewByteCode=./bin,-waittime=5 + * nsk.jvmti.scenarios.bcinstr.BI04.bi04t002 + */ + diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002/bi04t002.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002/bi04t002.cpp new file mode 100644 index 00000000000..17733d4ba54 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002/bi04t002.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2004, 2024, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include "jvmti.h" +#include "agent_common.hpp" +#include "ExceptionCheckingJniEnv.hpp" +#include "jni_tools.hpp" +#include "jvmti_tools.hpp" + +extern "C" { + +/* scaffold objects */ +static jlong timeout = 0; + +#define PATH_TO_NEW_BYTECODE "pathToNewByteCode" +#define TESTED_CLASS_NAME "java/lang/Object" + +static jint newClassSize; +static unsigned char* newClassBytes; + +static jvmtiClassDefinition classDef; + +/* ============================================================================= */ + +int readNewBytecode(jvmtiEnv* jvmti) { + + char filename[256]; + FILE *bytecode; + const char *pathToByteCode = nsk_jvmti_findOptionValue(PATH_TO_NEW_BYTECODE); + jint read_bytes; + + if (pathToByteCode) + snprintf(filename, sizeof(filename), "%s/%s/%s.class", + pathToByteCode, "newclass02", TESTED_CLASS_NAME); + else + snprintf(filename, sizeof(filename), "%s/%s.class", + "newclass02", TESTED_CLASS_NAME); + + NSK_DISPLAY1("Reading new bytecode for java.lang.Object\n\tfile name: %s\n", + filename); + + bytecode = fopen(filename, "rb"); + if (bytecode == nullptr) { + NSK_COMPLAIN0("error opening file\n"); + return NSK_FALSE; + } + + fseek(bytecode, 0, SEEK_END); + classDef.class_byte_count = ftell(bytecode); + rewind(bytecode); + + if (!NSK_JVMTI_VERIFY(jvmti->Allocate(classDef.class_byte_count, &newClassBytes))) { + NSK_COMPLAIN0("buffer couldn't be allocated\n"); + return NSK_FALSE; + } + classDef.class_bytes = newClassBytes; + read_bytes = (jint) fread(newClassBytes, 1, + classDef.class_byte_count, bytecode); + fclose(bytecode); + if (read_bytes != classDef.class_byte_count) { + NSK_COMPLAIN0("error reading file\n"); + return NSK_FALSE; + } + + return NSK_TRUE; +} + +/* ============================================================================= */ + +/** Agent algorithm. */ +static void JNICALL +agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { + + ExceptionCheckingJniEnvPtr ec_jni(jni); + /*Wait for debuggee to set classes to be redefined nsk_jvmti_waitForSync#4*/ + NSK_DISPLAY0("Wait for debuggee to set classes to be redefined nsk_jvmti_waitForSync#4\n"); + if (!nsk_jvmti_waitForSync(timeout)) + return; + + NSK_DISPLAY1("Find class: %s\n", TESTED_CLASS_NAME); + classDef.klass = ec_jni->FindClass(TESTED_CLASS_NAME, TRACE_JNI_CALL); + classDef.klass = (jclass) ec_jni->NewGlobalRef(classDef.klass, TRACE_JNI_CALL); + + NSK_DISPLAY0("Redfine class with new byte code\n"); + NSK_DISPLAY3("class definition:\n\t0x%p, 0x%p:%d\n", + classDef.klass, + classDef.class_bytes, + classDef.class_byte_count); + if (nsk_getVerboseMode()) { + nsk_printHexBytes(" ", 16, classDef.class_byte_count, + classDef.class_bytes); + } + if (!NSK_JVMTI_VERIFY(jvmti->RedefineClasses(1, &classDef))) { + nsk_jvmti_setFailStatus(); + return; + } + + ec_jni->DeleteGlobalRef(classDef.klass, TRACE_JNI_CALL); + + if (!nsk_jvmti_resumeSync()) + return; +} + +/* ============================================================================= */ + +/** Agent library initialization. */ +#ifdef STATIC_BUILD +JNIEXPORT jint JNICALL Agent_OnLoad_bi04t002(JavaVM *jvm, char *options, void *reserved) { + return Agent_Initialize(jvm, options, reserved); +} +JNIEXPORT jint JNICALL Agent_OnAttach_bi04t002(JavaVM *jvm, char *options, void *reserved) { + return Agent_Initialize(jvm, options, reserved); +} +JNIEXPORT jint JNI_OnLoad_bi04t002(JavaVM *jvm, char *options, void *reserved) { + return JNI_VERSION_1_8; +} +#endif +jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { + jvmtiEnv *jvmti = nullptr; + + if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) + return JNI_ERR; + + timeout = nsk_jvmti_getWaitTime() * 60 * 1000; + + jvmti = nsk_jvmti_createJVMTIEnv(jvm, reserved); + if (!NSK_VERIFY(jvmti != nullptr)) + return JNI_ERR; + + { + jvmtiCapabilities caps; + memset(&caps, 0, sizeof(caps)); + + caps.can_redefine_classes = 1; + caps.can_redefine_any_class = 1; + if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps))) + return JNI_ERR; + } + + if (!NSK_VERIFY(readNewBytecode(jvmti))) + return JNI_ERR; + + if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, nullptr))) + return JNI_ERR; + + return JNI_OK; +} + +/* ============================================================================= */ + + +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002/libbi04t002.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002/libbi04t002.cpp new file mode 100644 index 00000000000..03b7fad497b --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002/libbi04t002.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018, 2019, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "ExceptionCheckingJniEnv.cpp" +#include "native_thread.cpp" +#include "nsk_tools.cpp" +#include "jni_tools.cpp" +#include "jvmti_tools.cpp" +#include "agent_tools.cpp" +#include "jvmti_FollowRefObjects.cpp" +#include "Injector.cpp" +#include "JVMTITools.cpp" +#include "agent_common.cpp" +#include "bi04t002.cpp" diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002/newclass02/java.base/java/lang/Object.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002/newclass02/java.base/java/lang/Object.java new file mode 100644 index 00000000000..8b710ab8735 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002/newclass02/java.base/java/lang/Object.java @@ -0,0 +1,621 @@ +/* + * Copyright (c) 1994, 2024, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +import jdk.internal.vm.annotation.IntrinsicCandidate; +import nsk.jvmti.scenarios.bcinstr.BI04.bi04t002a; + +/** + * Class {@code Object} is the root of the class hierarchy. + * Every class has {@code Object} as a superclass. All objects, + * including arrays, implement the methods of this class. + * + * @see java.lang.Class + * @since 1.0 + */ +public class Object { + + /** + * Constructs a new object. + */ + @IntrinsicCandidate + public Object() {} + + /** + * Returns the runtime class of this {@code Object}. The returned + * {@code Class} object is the object that is locked by {@code + * static synchronized} methods of the represented class. + * + *

The actual result type is {@code Class} + * where {@code |X|} is the erasure of the static type of the + * expression on which {@code getClass} is called. For + * example, no cast is required in this code fragment:

+ * + *

+ * {@code Number n = 0; }
+ * {@code Class c = n.getClass(); } + *

+ * + * @return The {@code Class} object that represents the runtime + * class of this object. + * @jls 15.8.2 Class Literals + */ + @IntrinsicCandidate + public final native Class getClass(); + + /** + * {@return a hash code value for this object} This method is + * supported for the benefit of hash tables such as those provided by + * {@link java.util.HashMap}. + *

+ * The general contract of {@code hashCode} is: + *

+ * + * @implSpec + * As far as is reasonably practical, the {@code hashCode} method defined + * by class {@code Object} returns distinct integers for distinct objects. + * + * @apiNote + * The {@link java.util.Objects#hash(Object...) hash} and {@link + * java.util.Objects#hashCode(Object) hashCode} methods of {@link + * java.util.Objects} can be used to help construct simple hash codes. + * + * @see java.lang.Object#equals(java.lang.Object) + * @see java.lang.System#identityHashCode + */ + @IntrinsicCandidate + public native int hashCode(); + + /** + * Indicates whether some other object is "equal to" this one. + *

+ * The {@code equals} method implements an equivalence relation + * on non-null object references: + *

+ * + *

+ * An equivalence relation partitions the elements it operates on + * into equivalence classes; all the members of an + * equivalence class are equal to each other. Members of an + * equivalence class are substitutable for each other, at least + * for some purposes. + * + * @implSpec + * The {@code equals} method for class {@code Object} implements + * the most discriminating possible equivalence relation on objects; + * that is, for any non-null reference values {@code x} and + * {@code y}, this method returns {@code true} if and only + * if {@code x} and {@code y} refer to the same object + * ({@code x == y} has the value {@code true}). + * + * In other words, under the reference equality equivalence + * relation, each equivalence class only has a single element. + * + * @apiNote + * It is generally necessary to override the {@link #hashCode() hashCode} + * method whenever this method is overridden, so as to maintain the + * general contract for the {@code hashCode} method, which states + * that equal objects must have equal hash codes. + *

The two-argument {@link java.util.Objects#equals(Object, + * Object) Objects.equals} method implements an equivalence relation + * on two possibly-null object references. + * + * @param obj the reference object with which to compare. + * @return {@code true} if this object is the same as the obj + * argument; {@code false} otherwise. + * @see #hashCode() + * @see java.util.HashMap + */ + public boolean equals(Object obj) { + bi04t002a.instrInvoke(bi04t002a.INSTR_EQUALS); + return (this == obj); + } + + /** + * Creates and returns a copy of this object. The precise meaning + * of "copy" may depend on the class of the object. The general + * intent is that, for any object {@code x}, the expression: + *

+ *
+     * x.clone() != x
+ * will be true, and that the expression: + *
+ *
+     * x.clone().getClass() == x.getClass()
+ * will be {@code true}, but these are not absolute requirements. + * While it is typically the case that: + *
+ *
+     * x.clone().equals(x)
+ * will be {@code true}, this is not an absolute requirement. + *

+ * By convention, the returned object should be obtained by calling + * {@code super.clone}. If a class and all of its superclasses (except + * {@code Object}) obey this convention, it will be the case that + * {@code x.clone().getClass() == x.getClass()}. + *

+ * By convention, the object returned by this method should be independent + * of this object (which is being cloned). To achieve this independence, + * it may be necessary to modify one or more fields of the object returned + * by {@code super.clone} before returning it. Typically, this means + * copying any mutable objects that comprise the internal "deep structure" + * of the object being cloned and replacing the references to these + * objects with references to the copies. If a class contains only + * primitive fields or references to immutable objects, then it is usually + * the case that no fields in the object returned by {@code super.clone} + * need to be modified. + * + * @implSpec + * The method {@code clone} for class {@code Object} performs a + * specific cloning operation. First, if the class of this object does + * not implement the interface {@code Cloneable}, then a + * {@code CloneNotSupportedException} is thrown. Note that all arrays + * are considered to implement the interface {@code Cloneable} and that + * the return type of the {@code clone} method of an array type {@code T[]} + * is {@code T[]} where T is any reference or primitive type. + * Otherwise, this method creates a new instance of the class of this + * object and initializes all its fields with exactly the contents of + * the corresponding fields of this object, as if by assignment; the + * contents of the fields are not themselves cloned. Thus, this method + * performs a "shallow copy" of this object, not a "deep copy" operation. + *

+ * The class {@code Object} does not itself implement the interface + * {@code Cloneable}, so calling the {@code clone} method on an object + * whose class is {@code Object} will result in throwing an + * exception at run time. + * + * @return a clone of this instance. + * @throws CloneNotSupportedException if the object's class does not + * support the {@code Cloneable} interface. Subclasses + * that override the {@code clone} method can also + * throw this exception to indicate that an instance cannot + * be cloned. + * @see java.lang.Cloneable + */ + @IntrinsicCandidate + protected native Object clone() throws CloneNotSupportedException; + + /** + * {@return a string representation of the object} + * + * Satisfying this method's contract implies a non-{@code null} + * result must be returned. + * + * @apiNote + * In general, the + * {@code toString} method returns a string that + * "textually represents" this object. The result should + * be a concise but informative representation that is easy for a + * person to read. + * It is recommended that all subclasses override this method. + * The string output is not necessarily stable over time or across + * JVM invocations. + * @implSpec + * The {@code toString} method for class {@code Object} + * returns a string consisting of the name of the class of which the + * object is an instance, the at-sign character `{@code @}', and + * the unsigned hexadecimal representation of the hash code of the + * object. In other words, this method returns a string equal to the + * value of: + * {@snippet lang=java : + * getClass().getName() + '@' + Integer.toHexString(hashCode()) + * } + * The {@link java.util.Objects#toIdentityString(Object) + * Objects.toIdentityString} method returns the string for an + * object equal to the string that would be returned if neither + * the {@code toString} nor {@code hashCode} methods were + * overridden by the object's class. + */ + public String toString() { + bi04t002a.instrInvoke(bi04t002a.INSTR_TOSTRING); + return getClass().getName() + "@" + Integer.toHexString(hashCode()); + } + + /** + * Wakes up a single thread that is waiting on this object's + * monitor. If any threads are waiting on this object, one of them + * is chosen to be awakened. The choice is arbitrary and occurs at + * the discretion of the implementation. A thread waits on an object's + * monitor by calling one of the {@code wait} methods. + *

+ * The awakened thread will not be able to proceed until the current + * thread relinquishes the lock on this object. The awakened thread will + * compete in the usual manner with any other threads that might be + * actively competing to synchronize on this object; for example, the + * awakened thread enjoys no reliable privilege or disadvantage in being + * the next thread to lock this object. + *

+ * This method should only be called by a thread that is the owner + * of this object's monitor. A thread becomes the owner of the + * object's monitor in one of three ways: + *

+ *

+ * Only one thread at a time can own an object's monitor. + * + * @throws IllegalMonitorStateException if the current thread is not + * the owner of this object's monitor. + * @see java.lang.Object#notifyAll() + * @see java.lang.Object#wait() + */ + @IntrinsicCandidate + public final native void notify(); + + /** + * Wakes up all threads that are waiting on this object's monitor. A + * thread waits on an object's monitor by calling one of the + * {@code wait} methods. + *

+ * The awakened threads will not be able to proceed until the current + * thread relinquishes the lock on this object. The awakened threads + * will compete in the usual manner with any other threads that might + * be actively competing to synchronize on this object; for example, + * the awakened threads enjoy no reliable privilege or disadvantage in + * being the next thread to lock this object. + *

+ * This method should only be called by a thread that is the owner + * of this object's monitor. See the {@code notify} method for a + * description of the ways in which a thread can become the owner of + * a monitor. + * + * @throws IllegalMonitorStateException if the current thread is not + * the owner of this object's monitor. + * @see java.lang.Object#notify() + * @see java.lang.Object#wait() + */ + @IntrinsicCandidate + public final native void notifyAll(); + + /** + * Causes the current thread to wait until it is awakened, typically + * by being notified or interrupted. + *

+ * In all respects, this method behaves as if {@code wait(0L, 0)} + * had been called. See the specification of the {@link #wait(long, int)} method + * for details. + * + * @throws IllegalMonitorStateException if the current thread is not + * the owner of the object's monitor + * @throws InterruptedException if any thread interrupted the current thread before or + * while the current thread was waiting. The interrupted status of the + * current thread is cleared when this exception is thrown. + * @see #notify() + * @see #notifyAll() + * @see #wait(long) + * @see #wait(long, int) + */ + public final void wait() throws InterruptedException { + bi04t002a.instrInvoke(bi04t002a.INSTR_WAIT); + wait(0L); + } + + /** + * Causes the current thread to wait until it is awakened, typically + * by being notified or interrupted, or until a + * certain amount of real time has elapsed. + *

+ * In all respects, this method behaves as if {@code wait(timeoutMillis, 0)} + * had been called. See the specification of the {@link #wait(long, int)} method + * for details. + * + * @param timeoutMillis the maximum time to wait, in milliseconds + * @throws IllegalArgumentException if {@code timeoutMillis} is negative + * @throws IllegalMonitorStateException if the current thread is not + * the owner of the object's monitor + * @throws InterruptedException if any thread interrupted the current thread before or + * while the current thread was waiting. The interrupted status of the + * current thread is cleared when this exception is thrown. + * @see #notify() + * @see #notifyAll() + * @see #wait() + * @see #wait(long, int) + */ + public final void wait(long timeoutMillis) throws InterruptedException { + if (timeoutMillis < 0) { + throw new IllegalArgumentException("timeout value is negative"); + } + + if (Thread.currentThread() instanceof VirtualThread vthread) { + try { + wait0(timeoutMillis); + } catch (InterruptedException e) { + // virtual thread's interrupt status needs to be cleared + vthread.getAndClearInterrupt(); + throw e; + } finally { + if (timeoutMillis > 0) { + vthread.cancelWaitTimeout(); + } + } + } else { + wait0(timeoutMillis); + } + } + + // final modifier so method not in vtable + private final native void wait0(long timeoutMillis) throws InterruptedException; + + /** + * Causes the current thread to wait until it is awakened, typically + * by being notified or interrupted, or until a + * certain amount of real time has elapsed. + *

+ * The current thread must own this object's monitor lock. See the + * {@link #notify notify} method for a description of the ways in which + * a thread can become the owner of a monitor lock. + *

+ * This method causes the current thread (referred to here as T) to + * place itself in the wait set for this object and then to relinquish any + * and all synchronization claims on this object. Note that only the locks + * on this object are relinquished; any other objects on which the current + * thread may be synchronized remain locked while the thread waits. + *

+ * Thread T then becomes disabled for thread scheduling purposes + * and lies dormant until one of the following occurs: + *

+ *

+ * The thread T is then removed from the wait set for this + * object and re-enabled for thread scheduling. It competes in the + * usual manner with other threads for the right to synchronize on the + * object; once it has regained control of the object, all its + * synchronization claims on the object are restored to the status quo + * ante - that is, to the situation as of the time that the {@code wait} + * method was invoked. Thread T then returns from the + * invocation of the {@code wait} method. Thus, on return from the + * {@code wait} method, the synchronization state of the object and of + * thread {@code T} is exactly as it was when the {@code wait} method + * was invoked. + *

+ * A thread can wake up without being notified, interrupted, or timing out, a + * so-called spurious wakeup. While this will rarely occur in practice, + * applications must guard against it by testing for the condition that should + * have caused the thread to be awakened, and continuing to wait if the condition + * is not satisfied. See the example below. + *

+ * For more information on this topic, see section 14.2, + * "Condition Queues," in Brian Goetz and others' Java Concurrency + * in Practice (Addison-Wesley, 2006) or Item 81 in Joshua + * Bloch's Effective Java, Third Edition (Addison-Wesley, + * 2018). + *

+ * If the current thread is {@linkplain java.lang.Thread#interrupt() interrupted} + * by any thread before or while it is waiting, then an {@code InterruptedException} + * is thrown. The interrupted status of the current thread is cleared when + * this exception is thrown. This exception is not thrown until the lock status of + * this object has been restored as described above. + * + * @apiNote + * The recommended approach to waiting is to check the condition being awaited in + * a {@code while} loop around the call to {@code wait}, as shown in the example + * below. Among other things, this approach avoids problems that can be caused + * by spurious wakeups. + * + * {@snippet lang=java : + * synchronized (obj) { + * while ( ) { + * long timeoutMillis = ... ; // recompute timeout values + * int nanos = ... ; + * obj.wait(timeoutMillis, nanos); + * } + * ... // Perform action appropriate to condition or timeout + * } + * } + * + * @param timeoutMillis the maximum time to wait, in milliseconds + * @param nanos additional time, in nanoseconds, in the range 0-999999 inclusive + * @throws IllegalArgumentException if {@code timeoutMillis} is negative, + * or if the value of {@code nanos} is out of range + * @throws IllegalMonitorStateException if the current thread is not + * the owner of the object's monitor + * @throws InterruptedException if any thread interrupted the current thread before or + * while the current thread was waiting. The interrupted status of the + * current thread is cleared when this exception is thrown. + * @see #notify() + * @see #notifyAll() + * @see #wait() + * @see #wait(long) + */ + public final void wait(long timeoutMillis, int nanos) throws InterruptedException { + + bi04t002a.instrInvoke(bi04t002a.INSTR_WAIT_JI); + + if (timeoutMillis < 0) { + throw new IllegalArgumentException("timeoutMillis value is negative"); + } + + if (nanos < 0 || nanos > 999999) { + throw new IllegalArgumentException( + "nanosecond timeout value out of range"); + } + + if (nanos > 0 && timeoutMillis < Long.MAX_VALUE) { + timeoutMillis++; + } + + wait(timeoutMillis); + } + + /** + * Called by the garbage collector on an object when garbage collection + * determines that there are no more references to the object. + * A subclass overrides the {@code finalize} method to dispose of + * system resources or to perform other cleanup. + *

+ * When running in a Java virtual machine in which finalization has been + * disabled or removed, the garbage collector will never call + * {@code finalize()}. In a Java virtual machine in which finalization is + * enabled, the garbage collector might call {@code finalize} only after an + * indefinite delay. + *

+ * The general contract of {@code finalize} is that it is invoked + * if and when the Java virtual + * machine has determined that there is no longer any + * means by which this object can be accessed by any thread that has + * not yet died, except as a result of an action taken by the + * finalization of some other object or class which is ready to be + * finalized. The {@code finalize} method may take any action, including + * making this object available again to other threads; the usual purpose + * of {@code finalize}, however, is to perform cleanup actions before + * the object is irrevocably discarded. For example, the finalize method + * for an object that represents an input/output connection might perform + * explicit I/O transactions to break the connection before the object is + * permanently discarded. + *

+ * The {@code finalize} method of class {@code Object} performs no + * special action; it simply returns normally. Subclasses of + * {@code Object} may override this definition. + *

+ * The Java programming language does not guarantee which thread will + * invoke the {@code finalize} method for any given object. It is + * guaranteed, however, that the thread that invokes finalize will not + * be holding any user-visible synchronization locks when finalize is + * invoked. If an uncaught exception is thrown by the finalize method, + * the exception is ignored and finalization of that object terminates. + *

+ * After the {@code finalize} method has been invoked for an object, no + * further action is taken until the Java virtual machine has again + * determined that there is no longer any means by which this object can + * be accessed by any thread that has not yet died, including possible + * actions by other objects or classes which are ready to be finalized, + * at which point the object may be discarded. + *

+ * The {@code finalize} method is never invoked more than once by a Java + * virtual machine for any given object. + *

+ * Any exception thrown by the {@code finalize} method causes + * the finalization of this object to be halted, but is otherwise + * ignored. + * + * @apiNote + * Classes that embed non-heap resources have many options + * for cleanup of those resources. The class must ensure that the + * lifetime of each instance is longer than that of any resource it embeds. + * {@link java.lang.ref.Reference#reachabilityFence} can be used to ensure that + * objects remain reachable while resources embedded in the object are in use. + *

+ * A subclass should avoid overriding the {@code finalize} method + * unless the subclass embeds non-heap resources that must be cleaned up + * before the instance is collected. + * Finalizer invocations are not automatically chained, unlike constructors. + * If a subclass overrides {@code finalize} it must invoke the superclass + * finalizer explicitly. + * To guard against exceptions prematurely terminating the finalize chain, + * the subclass should use a {@code try-finally} block to ensure + * {@code super.finalize()} is always invoked. For example, + * {@snippet lang="java": + * @Override + * protected void finalize() throws Throwable { + * try { + * ... // cleanup subclass state + * } finally { + * super.finalize(); + * } + * } + * } + * + * @deprecated Finalization is deprecated and subject to removal in a future + * release. The use of finalization can lead to problems with security, + * performance, and reliability. + * See JEP 421 for + * discussion and alternatives. + *

+ * Subclasses that override {@code finalize} to perform cleanup should use + * alternative cleanup mechanisms and remove the {@code finalize} method. + * Use {@link java.lang.ref.Cleaner} and + * {@link java.lang.ref.PhantomReference} as safer ways to release resources + * when an object becomes unreachable. Alternatively, add a {@code close} + * method to explicitly release resources, and implement + * {@code AutoCloseable} to enable use of the {@code try}-with-resources + * statement. + *

+ * This method will remain in place until finalizers have been removed from + * most existing code. + * + * @throws Throwable the {@code Exception} raised by this method + * @see java.lang.ref.WeakReference + * @see java.lang.ref.PhantomReference + * @jls 12.6 Finalization of Class Instances + */ + @Deprecated(since="9", forRemoval=true) + protected void finalize() throws Throwable { } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002a.java new file mode 100644 index 00000000000..43369200389 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002a.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2004, 2018, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package nsk.jvmti.scenarios.bcinstr.BI04; + +public class bi04t002a { + + public final static int TOTAL_INSTRUMENTED_METHODS = 4; + + public final static int INSTR_EQUALS = 0; + public final static int INSTR_TOSTRING = 1; + public final static int INSTR_WAIT_JI = 2; + public final static int INSTR_WAIT = 3; + + static int invocationsCount[] = new int[TOTAL_INSTRUMENTED_METHODS]; + + public static void instrInvoke(int idx) { + invocationsCount[idx]++; + } + +} diff --git a/test/jdk/java/lang/instrument/TraceUsageAgent.java b/test/jdk/java/lang/instrument/TraceUsageAgent.java index 4760afcf2ec..8ad92707f46 100644 --- a/test/jdk/java/lang/instrument/TraceUsageAgent.java +++ b/test/jdk/java/lang/instrument/TraceUsageAgent.java @@ -47,7 +47,7 @@ private static void test(String methodNames, Instrumentation inst) throws Except inst.addTransformer(transformer); } case "retransformClasses" -> { - inst.retransformClasses(Integer.class); + inst.retransformClasses(Object.class); } case "redefineModule" -> { Module base = Object.class.getModule(); diff --git a/test/lib/jdk/test/lib/thread/VThreadRunner.java b/test/lib/jdk/test/lib/thread/VThreadRunner.java index 1b09e5e0d12..24f695508c8 100644 --- a/test/lib/jdk/test/lib/thread/VThreadRunner.java +++ b/test/lib/jdk/test/lib/thread/VThreadRunner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, 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