Compare commits

...

84 Commits

Author SHA1 Message Date
Tobias Hartmann
ec1782cd5b 8331194: NPE in ArrayCreationTree.java with -XX:-UseCompressedOops
Reviewed-by: kvn
Backport-of: 005fb67e99
2024-07-17 06:33:55 +00:00
SendaoYan
024b39c36b 8269657: Test java/nio/channels/DatagramChannel/Loopback.java failed: Unexpected message
Reviewed-by: jpai
Backport-of: c798316bc4
2024-07-17 06:12:13 +00:00
Jaikiran Pai
7afb958e8d Merge
Reviewed-by: djelinski, dholmes
2024-07-17 06:06:04 +00:00
Jayathirth D V
d876cacf73 8323390: Enhance mask blit functionality
Reviewed-by: prr, rhalade, psadhukhan
2024-07-17 05:41:28 +05:30
Phil Race
7aaf83df1d 8320097: Improve Image transformations
Reviewed-by: jdv, psadhukhan, aivanov, rhalade
2024-07-17 05:41:28 +05:30
Christian Hagedorn
f2e126dd5f 8327413: Enhance compilation efficiency
Co-authored-by: Roland Westrelin <roland@openjdk.org>
Reviewed-by: ahgross, rhalade, thartmann, epeter, mbalao, fferrari
2024-07-17 05:41:28 +05:30
Jayathirth D V
73e83a3e19 8324559: Improve 2D image handling
Reviewed-by: rhalade, mschoene, psadhukhan, prr
2024-07-17 05:41:28 +05:30
David Holmes
30260adb13 8325600: Better symbol storage
Reviewed-by: coleenp, rhalade, matsaave
2024-07-17 05:41:27 +05:30
David Holmes
cf1b618dc7 8319859: Better symbol storage
Reviewed-by: rhalade, coleenp, matsaave, iklam
2024-07-17 05:41:27 +05:30
Matias Saavedra Silva
58a274dc23 8314794: Improve UTF8 String supports
Reviewed-by: dholmes, coleenp, rhalade
2024-07-17 05:41:27 +05:30
Emanuel Peter
794cd0e591 8320548: Improved loop handling
Reviewed-by: mschoene, rhalade, thartmann, chagedorn
2024-07-17 05:41:27 +05:30
Tobias Hartmann
343da68432 8323231: Improve array management
Co-authored-by: Martin Balao <mbalao@openjdk.org>
Reviewed-by: iveresov, rhalade, mschoene, dlong, kvn
2024-07-17 05:41:27 +05:30
Patricio Chilano Mateo
d7b7c1724d 8335409: Can't allocate and retain memory from resource area in frame::oops_interpreted_do oop closure after 8329665
Reviewed-by: shade
Backport-of: 7ab96c74e2
2024-07-16 14:38:23 +00:00
Justin Lu
5162e1a31c 8334653: ISO 4217 Amendment 177 Update
Reviewed-by: naoto, iris
Backport-of: 86b0cf259f
2024-07-15 19:33:14 +00:00
Chen Liang
908d1e92fc 8336259: Wrong link to stylesheet.css in JavaDoc API documentation
Reviewed-by: iris, prappo
Backport-of: 5bc86f3329
2024-07-15 15:41:41 +00:00
Chen Liang
fd3860685d 8325369: @sealedGraph: Bad link to image for tag on nested classes
Reviewed-by: prappo
Backport-of: d06d79c809
2024-07-15 15:41:25 +00:00
Matthew Donovan
a106e522f8 8324841: PKCS11 tests still skip execution
Reviewed-by: jpai
Backport-of: 9d4a4bd2c2
2024-07-15 11:56:46 +00:00
Adam Sotona
52cd9bb534 8335820: java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java fails due to IllegalArgumentException: hash must be nonzero
Reviewed-by: jpai
Backport-of: 3f2636d9b7
2024-07-15 09:04:12 +00:00
Jaikiran Pai
7cc50a181a 8334719: (se) Deferred close of SelectableChannel may result in a Selector doing the final close before concurrent I/O on channel has completed
Reviewed-by: alanb
Backport-of: 9bb675f89d
2024-07-15 01:37:34 +00:00
Chen Liang
cfbfe4a472 8318106: Generated HTML for snippet does not always contain an id
Reviewed-by: prappo
Backport-of: 4166e53452
2024-07-14 13:27:28 +00:00
Chen Liang
d1373a2fd6 8336036: Synthetic documentation for a record's equals is incorrect for floating-point types
Reviewed-by: prappo
Backport-of: b3ef2a600c
2024-07-14 13:27:17 +00:00
Justin Lu
0a9e3bfc90 8334418: Update IANA Language Subtag Registry to Version 2024-06-14
Reviewed-by: naoto, iris
Backport-of: 861aefcafa
2024-07-12 20:18:30 +00:00
Chen Liang
06191aca86 8335935: Chained builders not sending transformed models to next transforms
Reviewed-by: asotona
Backport-of: cad68e06ec
2024-07-11 20:51:38 +00:00
Jorn Vernee
9620b912dd 8333884: MemorySegment::reinterpret removes read-only property
Reviewed-by: liach, sundar
Backport-of: 6f7f0f1de0
2024-07-11 12:42:21 +00:00
Jan Lahoda
e991c0f921 8335766: Switch case with pattern matching and guard clause compiles inconsistently
Reviewed-by: vromero
Backport-of: 537d20afbf
2024-07-11 11:08:31 +00:00
Jaikiran Pai
6720685abd 8335966: Remove incorrect problem listing of java/lang/instrument/NativeMethodPrefixAgent.java in ProblemList-Virtual.txt
Reviewed-by: kevinw
Backport-of: dcf4e0d51f
2024-07-11 08:20:10 +00:00
Joe Darcy
4aab58be4a 8335637: Add explicit non-null return value expectations to Object.toString()
Reviewed-by: jpai
Backport-of: 66db71563c
2024-07-11 03:06:38 +00:00
Jorn Vernee
5b9ecb1786 8333886: Explicitly specify that asSlice and reinterpret return a memory segment backed by the same region of memory.
Reviewed-by: sundar
Backport-of: c80e2eb35c
2024-07-10 16:58:04 +00:00
Kevin Walls
70ad622bc2 8335124: com/sun/management/ThreadMXBean/ThreadCpuTimeArray.java failed with CPU time out of expected range
Reviewed-by: cjplummer
Backport-of: 79a3554e1d
2024-07-09 19:39:25 +00:00
Liam Miller-Cushon
ca37a482cc 8334757: AssertionError: Missing type variable in where clause
Reviewed-by: jlahoda, vromero
Backport-of: babf6df7d9
2024-07-09 16:05:45 +00:00
Thomas Schatzl
ae10055b2c 8335824: Test gc/arguments/TestMinInitialErgonomics.java is timing out
Reviewed-by: kbarrett, ayang
Backport-of: 953c35eb5b
2024-07-09 08:12:38 +00:00
Jan Lahoda
4e52320979 8334433: jshell.exe runs an executable test.exe on startup
Reviewed-by: vromero
Backport-of: 99d2bbf767
2024-07-09 07:35:22 +00:00
Chen Liang
2f60d36848 8335475: ClassBuilder incorrectly calculates max_locals in some cases
Reviewed-by: asotona
Backport-of: 1ef34c1833
2024-07-08 11:01:53 +00:00
Christoph Langer
b415b98139 8334297: (so) java/nio/channels/SocketChannel/OpenLeak.java should not depend on SecurityManager
Reviewed-by: mbaesken, dfuchs
Backport-of: 50bed6c67b
2024-07-06 20:01:16 +00:00
Erik Gahlin
90d5b5b4c4 8324089: Fix typo in the manual page for "jcmd" (man jcmd)
Reviewed-by: mgronlun
Backport-of: 0bb9c76288
2024-07-05 10:53:09 +00:00
Erik Gahlin
653c481d71 8335479: JFR: Missing documentation for -XX:StartFlightRecording
Reviewed-by: mgronlun
Backport-of: 68ffec9800
2024-07-05 10:17:50 +00:00
Erik Gahlin
10b28babe5 8322812: Manpage for jcmd is missing JFR.view command
Reviewed-by: mgronlun
Backport-of: 350f9c1947
2024-07-05 09:58:56 +00:00
Erik Österlund
d383365ea4 8334890: Missing unconditional cross modifying fence in nmethod entry barriers
Reviewed-by: aboldtch
Backport-of: c0604fb823
2024-07-05 07:54:43 +00:00
Vladimir Kozlov
b6d0ead93f 8335221: Some C2 intrinsics incorrectly assume that type argument is compile-time constant
Reviewed-by: thartmann
Backport-of: 166f9d9ac0
2024-07-02 17:04:13 +00:00
Emanuel Peter
272d11a389 8335390: C2 MergeStores: wrong result with Unsafe
Reviewed-by: thartmann
Backport-of: 9046d7aee3
2024-07-02 14:27:45 +00:00
Chris Plummer
9d744b0e04 8335134: Test com/sun/jdi/BreakpointOnClassPrepare.java timeout
Reviewed-by: dholmes
Backport-of: 4e8cbf884a
2024-07-01 22:43:47 +00:00
SendaoYan
4410cdc839 8334600: TEST java/net/MulticastSocket/IPMulticastIF.java fails on linux-aarch64
Reviewed-by: clanger
Backport-of: f23295ec1d
2024-07-01 15:48:32 +00:00
Coleen Phillimore
7040de19bd 8333542: Breakpoint in parallel code does not work
Reviewed-by: cjplummer
Backport-of: b3bf31a0a0
2024-07-01 12:16:58 +00:00
Axel Boldt-Christmas
e5fbc631ca 8326820: Metadata artificially kept alive
Reviewed-by: stefank
Backport-of: 5909d54147
2024-07-01 10:24:28 +00:00
Daniel Fuchs
e78c682142 8333849: (dc) DatagramChannel send/receive fails with UOE if buffer backed by memory segment allocated from shared arena
Reviewed-by: alanb
Backport-of: e7dc76b577
2024-07-01 07:55:31 +00:00
Vladimir Kozlov
87a29629e3 8335220: C2: Missing check for Opaque4 node in EscapeAnalysis
Reviewed-by: vlivanov
Backport-of: 9d986a013d
2024-06-29 02:20:07 +00:00
Erik Gahlin
32ed61572c 8334886: jdk/jfr/api/recording/time/TestTimeMultiple.java failed with RuntimeException: getStopTime() > afterStop
Reviewed-by: mgronlun
Backport-of: 0e6b0cbaaa
2024-06-27 22:07:32 +00:00
Vladimir Kozlov
62d0ee9cc0 8334421: assert(!oldbox->is_unbalanced()) failed: this should not be called for unbalanced region
Reviewed-by: shade, thartmann
Backport-of: 9c89f0861c
2024-06-27 19:29:18 +00:00
Anthony Scarpino
98fd657cfa 8326705: Test CertMsgCheck.java fails to find alert certificate_required
Reviewed-by: rhalade
Backport-of: 4ffc5e6077
2024-06-27 14:17:56 +00:00
Stefan Karlsson
d7b9454205 8324781: runtime/Thread/TestAlwaysPreTouchStacks.java failed with Expected a higher ratio between stack committed and reserved
8325218: gc/parallel/TestAlwaysPreTouchBehavior.java fails

Reviewed-by: tschatzl
Backport-of: 31e8debae6
2024-06-27 14:01:23 +00:00
Volodymyr Paprotski
b5fbdb2166 8333583: Crypto-XDH.generateSecret regression after JDK-8329538
Reviewed-by: thartmann, sviswanathan
Backport-of: f101e153ce
2024-06-26 15:24:19 +00:00
Tobias Hartmann
2086b0f070 8334629: [BACKOUT] PhaseIdealLoop::conditional_move is too conservative
Reviewed-by: chagedorn, qamai
Backport-of: 933eababf2
2024-06-26 10:49:44 +00:00
Aleksey Shipilev
d1510505c1 8334594: Generational ZGC: Deadlock after OopMap rewrites in 8331572
Reviewed-by: stefank
Backport-of: 05ff3185ed
2024-06-26 07:46:27 +00:00
Prasanta Sadhukhan
ae49182985 8334580: Deprecate no-arg constructor BasicSliderUI() for removal
Reviewed-by: aivanov
Backport-of: e527e1c32f
2024-06-26 02:59:02 +00:00
Erik Österlund
37ebecec88 8332717: ZGC: Division by zero in heuristics
Reviewed-by: shade
Backport-of: 2d4185f4f1
2024-06-25 07:57:09 +00:00
Christoph Langer
08c7c38342 8222884: ConcurrentClassDescLookup.java times out intermittently
Reviewed-by: mdoerr
Backport-of: bd046d9b9e
2024-06-25 03:38:09 +00:00
Erik Gahlin
fa7521b29e 8323196: jdk/jfr/api/consumer/filestream/TestOrdered.java failed with "Events are not ordered! Reuse = false"
Reviewed-by: mgronlun
Backport-of: bdd96604ae
2024-06-24 17:53:14 +00:00
Prasanta Sadhukhan
fbcf6d9c4f 8334509: Cancelling PageDialog does not return the same PageFormat object
Reviewed-by: prr
Backport-of: 689cee3d09
2024-06-24 17:26:11 +00:00
Chen Liang
a124e6e5c7 8333748: javap crash - Fatal error: Unmatched bit position 0x2 for location CLASS
Reviewed-by: asotona
Backport-of: 7e55ed3b10
2024-06-24 12:57:37 +00:00
Vicente Romero
0779f0d668 8334762: [BACKOUT BACKPORT] Improve error for illegal early access from nested class
Reviewed-by: liach, mcimadamore
2024-06-24 12:38:19 +00:00
SendaoYan
bd66b6b6f9 8333358: java/io/IO/IO.java test fails intermittently
Reviewed-by: prappo
Backport-of: 1b1dba8082
2024-06-24 09:53:50 +00:00
Hannes Greule
3edf379b67 8334708: FFM: two javadoc problems
Reviewed-by: jpai
Backport-of: 72ca7bafcd
2024-06-24 06:30:12 +00:00
SendaoYan
10d81a337d 8334441: Mark tests in jdk_security_infra group as manual
Reviewed-by: clanger
Backport-of: 8e1d2b091c
2024-06-23 16:43:27 +00:00
Chen Liang
1dbad8058b 8333854: IllegalAccessError with proxies after JDK-8332457
Reviewed-by: asotona
Backport-of: 91bd85d65d
2024-06-21 22:33:23 +00:00
SendaoYan
215149310c 8334333: MissingResourceCauseTestRun.java fails if run by root
Reviewed-by: naoto
Backport-of: de8ee97718
2024-06-21 16:39:18 +00:00
Kevin Walls
23f2c97f4c 8333344: JMX attaching of Subject does not work when security manager not allowed
Reviewed-by: dfuchs
Backport-of: bcf4bb4882
2024-06-21 10:09:14 +00:00
Vicente Romero
e84e0cdf62 8334488: Improve error for illegal early access from nested class
Reviewed-by: mcimadamore
Backport-of: 7b3a96d570
2024-06-20 18:02:13 +00:00
Erik Gahlin
2243974d29 8304732: jdk/jfr/api/consumer/recordingstream/TestStop.java failed again with "Expected outer stream to have 3 events"
Reviewed-by: mgronlun
Backport-of: 856931d01f
2024-06-20 13:55:55 +00:00
Richard Reingruber
79dd575113 8334402: ProblemList test/hotspot/jtreg/compiler/c2/TestMergeStores.java on big endian platforms
Reviewed-by: kvn
2024-06-20 07:09:24 +00:00
Vicente Romero
12a61bce8d 8334043: VerifyError when inner class is accessed in prologue
Reviewed-by: jpai
Backport-of: d4c1373717
2024-06-19 04:00:58 +00:00
Vicente Romero
d9dd2d19b0 8334258: Compiler erronousely allows access to instance variable in argument expression of a constructor invocation
Reviewed-by: jpai
Backport-of: e227c7e37d
2024-06-19 04:00:37 +00:00
Daniel Fuchs
b21d7b23c1 8333804: java/net/httpclient/ForbiddenHeadTest.java threw an exception with 0 failures
Reviewed-by: jpai
Backport-of: ec1664e8c9
2024-06-18 18:46:03 +00:00
SendaoYan
867312a7e5 8334332: TestIOException.java fails if run by root
Reviewed-by: prappo
Backport-of: 472b935b44
2024-06-18 13:13:31 +00:00
Christoph Langer
a4b49253e3 8331675: gtest CollectorPolicy.young_min_ergo_vm fails after 8272364
Reviewed-by: ayang, mdoerr
Backport-of: badf1cb9ce
2024-06-18 12:11:28 +00:00
Daniel Fuchs
86fcbe09f8 8299487: Test java/net/httpclient/whitebox/SSLTubeTestDriver.java timed out
Reviewed-by: jpai
Backport-of: 81083a0e10
2024-06-17 16:03:26 +00:00
Markus Grönlund
48997f54c9 8326715: ZGC: RunThese24H fails with ExitCode 139 during shutdown
Reviewed-by: egahlin
Backport-of: cdf22b1320
2024-06-17 14:22:29 +00:00
Christoph Langer
4e3bfc926e 8211847: [aix] java/lang/ProcessHandle/InfoTest.java fails: "reported cputime less than expected"
Reviewed-by: mbaesken
Backport-of: f5213671f7
2024-06-17 12:20:39 +00:00
Christoph Langer
d0b4f9baab 8334222: exclude containers/cgroup/PlainRead.java
Reviewed-by: mbaesken
Backport-of: 5e09397bf6
2024-06-17 12:19:36 +00:00
Christoph Langer
cb3c45a698 8211854: [aix] java/net/ServerSocket/AcceptInheritHandle.java fails: read times out
Reviewed-by: mbaesken
Backport-of: 9d8439c107
2024-06-17 12:19:27 +00:00
Marc R. Hoffmann
10f71f7dd4 8334032: javax.print: Missing @since tag in new class OutputBin
Reviewed-by: prr
Backport-of: 0721dbe442
2024-06-13 22:25:10 +00:00
Damon Nguyen
a7964453cf 8333827: JDK 23 RDP1 L10n resource files update
Reviewed-by: jlu, naoto
Backport-of: c4702ca8c0
2024-06-13 21:48:34 +00:00
Viktor Klang
5230786a0d 8334162: Gatherer.defaultCombiner has an erronous @see-link
Reviewed-by: iris
Backport-of: cff048c735
2024-06-13 16:58:58 +00:00
Christoph Langer
378cd12f6b 8333724: Problem list security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java#teliasonerarootcav1
Reviewed-by: mbaesken
Backport-of: 8ffc35d117
2024-06-13 13:25:26 +00:00
Christian Hagedorn
d96476d8bd 8332920: C2: Partial Peeling is wrongly applied for CmpU with negative limit
Reviewed-by: thartmann
Backport-of: ef101f1bf2
2024-06-12 06:17:07 +00:00
267 changed files with 5610 additions and 1756 deletions

View File

@@ -778,7 +778,7 @@ public class FieldGen {
result.appendLine("}");
result.appendLine("@Override");
result.appendLine("protected int mult(long[] a, long[] b, long[] r) {");
result.appendLine("protected void mult(long[] a, long[] b, long[] r) {");
result.incrIndent();
for (int i = 0; i < 2 * params.getNumLimbs() - 1; i++) {
result.appendIndent();
@@ -804,9 +804,6 @@ public class FieldGen {
}
}
result.append(");\n");
result.appendIndent();
result.append("return 0;");
result.appendLine();
result.decrIndent();
result.appendLine("}");
@@ -836,7 +833,7 @@ public class FieldGen {
// }
// }
result.appendLine("@Override");
result.appendLine("protected int square(long[] a, long[] r) {");
result.appendLine("protected void square(long[] a, long[] r) {");
result.incrIndent();
for (int i = 0; i < 2 * params.getNumLimbs() - 1; i++) {
result.appendIndent();
@@ -877,9 +874,6 @@ public class FieldGen {
}
}
result.append(");\n");
result.appendIndent();
result.append("return 0;");
result.appendLine();
result.decrIndent();
result.appendLine("}");

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -107,7 +107,7 @@ public final class SealedGraph implements Taglet {
throw new RuntimeException(e);
}
String simpleTypeName = element.getSimpleName().toString();
String simpleTypeName = packagelessCanonicalName(typeElement).replace('.', '/');
String imageFile = simpleTypeName + "-sealed-graph.svg";
int thumbnailHeight = 100; // also appears in the stylesheet
String hoverImage = "<span>"
@@ -315,14 +315,14 @@ public final class SealedGraph implements Taglet {
case MEMBER -> packageName((TypeElement) element.getEnclosingElement());
};
}
}
private static String packagelessCanonicalName(TypeElement element) {
String result = element.getSimpleName().toString();
while (element.getNestingKind() == NestingKind.MEMBER) {
element = (TypeElement) element.getEnclosingElement();
result = element.getSimpleName().toString() + '.' + result;
}
return result;
private static String packagelessCanonicalName(TypeElement element) {
String result = element.getSimpleName().toString();
while (element.getNestingKind() == NestingKind.MEMBER) {
element = (TypeElement) element.getEnclosingElement();
result = element.getSimpleName().toString() + '.' + result;
}
return result;
}
}

View File

@@ -249,7 +249,6 @@ address StubGenerator::generate_intpoly_montgomeryMult_P256() {
const Register tmp = r9;
montgomeryMultiply(aLimbs, bLimbs, rLimbs, tmp, _masm);
__ mov64(rax, 0x1); // Return 1 (Fig. 5, Step 6 [1] skipped in montgomeryMultiply)
__ leave();
__ ret(0);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 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
@@ -483,14 +483,14 @@ void RangeCheckEliminator::in_block_motion(BlockBegin *block, AccessIndexedList
if (c) {
jint value = c->type()->as_IntConstant()->value();
if (value != min_jint) {
if (ao->op() == Bytecodes::_isub) {
value = -value;
}
if (ao->op() == Bytecodes::_iadd) {
base = java_add(base, value);
last_integer = base;
last_instruction = other;
} else {
assert(ao->op() == Bytecodes::_isub, "unexpected bytecode");
base = java_subtract(base, value);
}
last_integer = base;
last_instruction = other;
index = other;
} else {
break;

View File

@@ -241,9 +241,14 @@ LockedClassesDo::~LockedClassesDo() {
// Iterating over the CLDG needs to be locked because
// unloading can remove entries concurrently soon.
template <bool keep_alive = true>
class ClassLoaderDataGraphIteratorBase : public StackObj {
// unloading can remove entries concurrently.
// This iterator does not keep the CLD alive.
// Any CLD OopHandles (modules, mirrors, resolved refs)
// resolved must be treated as no keepalive. And requires
// that its CLD's holder is kept alive if they escape the
// caller's safepoint or ClassLoaderDataGraph_lock
// critical section.
class ClassLoaderDataGraph::ClassLoaderDataGraphIterator : public StackObj {
ClassLoaderData* _next;
Thread* _thread;
HandleMark _hm; // clean up handles when this is done.
@@ -251,12 +256,8 @@ class ClassLoaderDataGraphIteratorBase : public StackObj {
// unless verifying at a safepoint.
public:
ClassLoaderDataGraphIteratorBase() : _next(ClassLoaderDataGraph::_head), _thread(Thread::current()), _hm(_thread) {
if (keep_alive) {
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
} else {
assert_at_safepoint();
}
ClassLoaderDataGraphIterator() : _next(ClassLoaderDataGraph::_head), _thread(Thread::current()), _hm(_thread) {
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
}
ClassLoaderData* get_next() {
@@ -266,10 +267,6 @@ public:
cld = cld->next();
}
if (cld != nullptr) {
if (keep_alive) {
// Keep cld that is being returned alive.
Handle(_thread, cld->holder());
}
_next = cld->next();
} else {
_next = nullptr;
@@ -278,9 +275,6 @@ public:
}
};
using ClassLoaderDataGraphIterator = ClassLoaderDataGraphIteratorBase<true /* keep_alive */>;
using ClassLoaderDataGraphIteratorNoKeepAlive = ClassLoaderDataGraphIteratorBase<false /* keep_alive */>;
void ClassLoaderDataGraph::loaded_cld_do(CLDClosure* cl) {
ClassLoaderDataGraphIterator iter;
while (ClassLoaderData* cld = iter.get_next()) {
@@ -288,13 +282,6 @@ void ClassLoaderDataGraph::loaded_cld_do(CLDClosure* cl) {
}
}
void ClassLoaderDataGraph::loaded_cld_do_no_keepalive(CLDClosure* cl) {
ClassLoaderDataGraphIteratorNoKeepAlive iter;
while (ClassLoaderData* cld = iter.get_next()) {
cl->do_cld(cld);
}
}
// These functions assume that the caller has locked the ClassLoaderDataGraph_lock
// if they are not calling the function from a safepoint.
void ClassLoaderDataGraph::classes_do(KlassClosure* klass_closure) {
@@ -318,6 +305,16 @@ void ClassLoaderDataGraph::methods_do(void f(Method*)) {
}
}
void ClassLoaderDataGraph::modules_do_keepalive(void f(ModuleEntry*)) {
assert_locked_or_safepoint(Module_lock);
ClassLoaderDataGraphIterator iter;
while (ClassLoaderData* cld = iter.get_next()) {
// Keep the holder alive.
(void)cld->holder();
cld->modules_do(f);
}
}
void ClassLoaderDataGraph::modules_do(void f(ModuleEntry*)) {
assert_locked_or_safepoint(Module_lock);
ClassLoaderDataGraphIterator iter;
@@ -334,9 +331,11 @@ void ClassLoaderDataGraph::packages_do(void f(PackageEntry*)) {
}
}
void ClassLoaderDataGraph::loaded_classes_do(KlassClosure* klass_closure) {
void ClassLoaderDataGraph::loaded_classes_do_keepalive(KlassClosure* klass_closure) {
ClassLoaderDataGraphIterator iter;
while (ClassLoaderData* cld = iter.get_next()) {
// Keep the holder alive.
(void)cld->holder();
cld->loaded_classes_do(klass_closure);
}
}
@@ -346,7 +345,7 @@ void ClassLoaderDataGraph::classes_unloading_do(void f(Klass* const)) {
}
void ClassLoaderDataGraph::verify_dictionary() {
ClassLoaderDataGraphIteratorNoKeepAlive iter;
ClassLoaderDataGraphIterator iter;
while (ClassLoaderData* cld = iter.get_next()) {
if (cld->dictionary() != nullptr) {
cld->dictionary()->verify();
@@ -354,26 +353,28 @@ void ClassLoaderDataGraph::verify_dictionary() {
}
}
#define FOR_ALL_DICTIONARY(X) ClassLoaderDataGraphIterator iter; \
while (ClassLoaderData* X = iter.get_next()) \
if (X->dictionary() != nullptr)
void ClassLoaderDataGraph::print_dictionary(outputStream* st) {
FOR_ALL_DICTIONARY(cld) {
st->print("Dictionary for ");
cld->print_value_on(st);
st->cr();
cld->dictionary()->print_on(st);
st->cr();
ClassLoaderDataGraphIterator iter;
while (ClassLoaderData *cld = iter.get_next()) {
if (cld->dictionary() != nullptr) {
st->print("Dictionary for ");
cld->print_value_on(st);
st->cr();
cld->dictionary()->print_on(st);
st->cr();
}
}
}
void ClassLoaderDataGraph::print_table_statistics(outputStream* st) {
FOR_ALL_DICTIONARY(cld) {
ResourceMark rm; // loader_name_and_id
stringStream tempst;
tempst.print("System Dictionary for %s class loader", cld->loader_name_and_id());
cld->dictionary()->print_table_statistics(st, tempst.freeze());
ClassLoaderDataGraphIterator iter;
while (ClassLoaderData *cld = iter.get_next()) {
if (cld->dictionary() != nullptr) {
ResourceMark rm; // loader_name_and_id
stringStream tempst;
tempst.print("System Dictionary for %s class loader", cld->loader_name_and_id());
cld->dictionary()->print_table_statistics(st, tempst.freeze());
}
}
}
@@ -550,7 +551,7 @@ Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass() {
}
void ClassLoaderDataGraph::verify() {
ClassLoaderDataGraphIteratorNoKeepAlive iter;
ClassLoaderDataGraphIterator iter;
while (ClassLoaderData* cld = iter.get_next()) {
cld->verify();
}

View File

@@ -37,10 +37,10 @@ class ClassLoaderDataGraph : public AllStatic {
friend class ClassLoaderDataGraphMetaspaceIterator;
friend class ClassLoaderDataGraphKlassIteratorAtomic;
friend class ClassLoaderDataGraphKlassIteratorStatic;
template <bool keep_alive>
friend class ClassLoaderDataGraphIteratorBase;
friend class VMStructs;
private:
class ClassLoaderDataGraphIterator;
// All CLDs (except unlinked CLDs) can be reached by walking _head->_next->...
static ClassLoaderData* volatile _head;
@@ -71,8 +71,12 @@ class ClassLoaderDataGraph : public AllStatic {
static void roots_cld_do(CLDClosure* strong, CLDClosure* weak);
static void always_strong_cld_do(CLDClosure* cl);
// Iteration through CLDG not by GC.
// All the do suffixed functions do not keep the CLD alive. Any CLD OopHandles
// (modules, mirrors, resolved refs) resolved must be treated as no keepalive.
// And requires that its CLD's holder is kept alive if they escape the
// caller's safepoint or ClassLoaderDataGraph_lock critical section.
// The do_keepalive suffixed functions will keep all CLDs alive.
static void loaded_cld_do(CLDClosure* cl);
static void loaded_cld_do_no_keepalive(CLDClosure* cl);
// klass do
// Walking classes through the ClassLoaderDataGraph include array classes. It also includes
// classes that are allocated but not loaded, classes that have errors, and scratch classes
@@ -81,9 +85,10 @@ class ClassLoaderDataGraph : public AllStatic {
static void classes_do(KlassClosure* klass_closure);
static void classes_do(void f(Klass* const));
static void methods_do(void f(Method*));
static void modules_do_keepalive(void f(ModuleEntry*));
static void modules_do(void f(ModuleEntry*));
static void packages_do(void f(PackageEntry*));
static void loaded_classes_do(KlassClosure* klass_closure);
static void loaded_classes_do_keepalive(KlassClosure* klass_closure);
static void classes_unloading_do(void f(Klass* const));
static bool do_unloading();

View File

@@ -165,7 +165,7 @@ void ClassLoaderStatsClosure::addEmptyParents(oop cl) {
void ClassLoaderStatsVMOperation::doit() {
ClassLoaderStatsClosure clsc (_out);
ClassLoaderDataGraph::loaded_cld_do_no_keepalive(&clsc);
ClassLoaderDataGraph::loaded_cld_do(&clsc);
clsc.print();
}

View File

@@ -788,6 +788,7 @@ int java_lang_Class::_class_loader_offset;
int java_lang_Class::_module_offset;
int java_lang_Class::_protection_domain_offset;
int java_lang_Class::_component_mirror_offset;
int java_lang_Class::_init_lock_offset;
int java_lang_Class::_signers_offset;
int java_lang_Class::_name_offset;
int java_lang_Class::_source_file_offset;
@@ -911,6 +912,12 @@ void java_lang_Class::initialize_mirror_fields(Klass* k,
Handle protection_domain,
Handle classData,
TRAPS) {
// Allocate a simple java object for a lock.
// This needs to be a java object because during class initialization
// it can be held across a java call.
typeArrayOop r = oopFactory::new_typeArray(T_INT, 0, CHECK);
set_init_lock(mirror(), r);
// Set protection domain also
set_protection_domain(mirror(), protection_domain());
@@ -1132,6 +1139,10 @@ bool java_lang_Class::restore_archived_mirror(Klass *k,
if (!k->is_array_klass()) {
// - local static final fields with initial values were initialized at dump time
// create the init_lock
typeArrayOop r = oopFactory::new_typeArray(T_INT, 0, CHECK_(false));
set_init_lock(mirror(), r);
if (protection_domain.not_null()) {
set_protection_domain(mirror(), protection_domain());
}
@@ -1196,6 +1207,15 @@ oop java_lang_Class::component_mirror(oop java_class) {
return java_class->obj_field(_component_mirror_offset);
}
oop java_lang_Class::init_lock(oop java_class) {
assert(_init_lock_offset != 0, "must be set");
return java_class->obj_field(_init_lock_offset);
}
void java_lang_Class::set_init_lock(oop java_class, oop init_lock) {
assert(_init_lock_offset != 0, "must be set");
java_class->obj_field_put(_init_lock_offset, init_lock);
}
objArrayOop java_lang_Class::signers(oop java_class) {
assert(_signers_offset != 0, "must be set");
return (objArrayOop)java_class->obj_field(_signers_offset);
@@ -1415,12 +1435,18 @@ void java_lang_Class::compute_offsets() {
InstanceKlass* k = vmClasses::Class_klass();
CLASS_FIELDS_DO(FIELD_COMPUTE_OFFSET);
// Init lock is a C union with component_mirror. Only instanceKlass mirrors have
// init_lock and only ArrayKlass mirrors have component_mirror. Since both are oops
// GC treats them the same.
_init_lock_offset = _component_mirror_offset;
CLASS_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
}
#if INCLUDE_CDS
void java_lang_Class::serialize_offsets(SerializeClosure* f) {
f->do_bool(&_offsets_computed);
f->do_u4((u4*)&_init_lock_offset);
CLASS_FIELDS_DO(FIELD_SERIALIZE_OFFSET);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@@ -226,6 +226,7 @@ class java_lang_Class : AllStatic {
static int _static_oop_field_count_offset;
static int _protection_domain_offset;
static int _init_lock_offset;
static int _signers_offset;
static int _class_loader_offset;
static int _module_offset;
@@ -240,6 +241,7 @@ class java_lang_Class : AllStatic {
static GrowableArray<Klass*>* _fixup_mirror_list;
static GrowableArray<Klass*>* _fixup_module_field_list;
static void set_init_lock(oop java_class, oop init_lock);
static void set_protection_domain(oop java_class, oop protection_domain);
static void set_class_loader(oop java_class, oop class_loader);
static void set_component_mirror(oop java_class, oop comp_mirror);
@@ -292,6 +294,10 @@ class java_lang_Class : AllStatic {
// Support for embedded per-class oops
static oop protection_domain(oop java_class);
static oop init_lock(oop java_class);
static void clear_init_lock(oop java_class) {
set_init_lock(java_class, nullptr);
}
static oop component_mirror(oop java_class);
static objArrayOop signers(oop java_class);
static void set_signers(oop java_class, objArrayOop signers);

View File

@@ -344,8 +344,23 @@ Symbol* SymbolTable::lookup_common(const char* name,
return sym;
}
// Symbols should represent entities from the constant pool that are
// limited to <64K in length, but usage errors creep in allowing Symbols
// to be used for arbitrary strings. For debug builds we will assert if
// a string is too long, whereas product builds will truncate it.
static int check_length(const char* name, int len) {
assert(len <= Symbol::max_length(),
"String length %d exceeds the maximum Symbol length of %d", len, Symbol::max_length());
if (len > Symbol::max_length()) {
warning("A string \"%.80s ... %.80s\" exceeds the maximum Symbol "
"length of %d and has been truncated", name, (name + len - 80), Symbol::max_length());
len = Symbol::max_length();
}
return len;
}
Symbol* SymbolTable::new_symbol(const char* name, int len) {
assert(len <= Symbol::max_length(), "sanity");
len = check_length(name, len);
unsigned int hash = hash_symbol(name, len, _alt_hash);
Symbol* sym = lookup_common(name, len, hash);
if (sym == nullptr) {
@@ -485,6 +500,7 @@ void SymbolTable::new_symbols(ClassLoaderData* loader_data, const constantPoolHa
for (int i = 0; i < names_count; i++) {
const char *name = names[i];
int len = lengths[i];
assert(len <= Symbol::max_length(), "must be - these come from the constant pool");
unsigned int hash = hashValues[i];
assert(lookup_shared(name, len, hash) == nullptr, "must have checked already");
Symbol* sym = do_add_if_needed(name, len, hash, is_permanent);
@@ -494,6 +510,7 @@ void SymbolTable::new_symbols(ClassLoaderData* loader_data, const constantPoolHa
}
Symbol* SymbolTable::do_add_if_needed(const char* name, int len, uintx hash, bool is_permanent) {
assert(len <= Symbol::max_length(), "caller should have ensured this");
SymbolTableLookup lookup(name, len, hash);
SymbolTableGet stg;
bool clean_hint = false;
@@ -542,7 +559,7 @@ Symbol* SymbolTable::do_add_if_needed(const char* name, int len, uintx hash, boo
Symbol* SymbolTable::new_permanent_symbol(const char* name) {
unsigned int hash = 0;
int len = (int)strlen(name);
int len = check_length(name, (int)strlen(name));
Symbol* sym = SymbolTable::lookup_only(name, len, hash);
if (sym == nullptr) {
sym = do_add_if_needed(name, len, hash, /* is_permanent */ true);

View File

@@ -177,7 +177,7 @@ class SystemDictionary : AllStatic {
static void classes_do(MetaspaceClosure* it);
// Iterate over all methods in all klasses
// Will not keep metadata alive. See ClassLoaderDataGraph::methods_do.
static void methods_do(void f(Method*));
// Garbage collection support

View File

@@ -529,8 +529,8 @@ class methodHandle;
/* support for sun.security.util.math.intpoly.MontgomeryIntegerPolynomialP256 */ \
do_class(sun_security_util_math_intpoly_MontgomeryIntegerPolynomialP256, "sun/security/util/math/intpoly/MontgomeryIntegerPolynomialP256") \
do_intrinsic(_intpoly_montgomeryMult_P256, sun_security_util_math_intpoly_MontgomeryIntegerPolynomialP256, intPolyMult_name, intPolyMult_signature, F_R) \
do_name(intPolyMult_name, "mult") \
do_signature(intPolyMult_signature, "([J[J[J)I") \
do_name(intPolyMult_name, "multImpl") \
do_signature(intPolyMult_signature, "([J[J[J)V") \
\
do_class(sun_security_util_math_intpoly_IntegerPolynomial, "sun/security/util/math/intpoly/IntegerPolynomial") \
do_intrinsic(_intpoly_assign, sun_security_util_math_intpoly_IntegerPolynomial, intPolyAssign_name, intPolyAssign_signature, F_S) \

View File

@@ -557,6 +557,7 @@ class SerializeClosure;
template(bool_array_signature, "[Z") \
template(byte_array_signature, "[B") \
template(char_array_signature, "[C") \
template(int_array_signature, "[I") \
template(runnable_signature, "Ljava/lang/Runnable;") \
template(continuation_signature, "Ljdk/internal/vm/Continuation;") \
template(continuationscope_signature, "Ljdk/internal/vm/ContinuationScope;") \

View File

@@ -172,13 +172,9 @@ int BarrierSetNMethod::nmethod_stub_entry_barrier(address* return_address_ptr) {
nmethod* nm = cb->as_nmethod();
BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
if (!bs_nm->is_armed(nm)) {
return 0;
}
assert(!nm->is_osr_method(), "Should not reach here");
// Called upon first entry after being armed
bool may_enter = bs_nm->nmethod_entry_barrier(nm);
assert(!nm->is_osr_method() || may_enter, "OSR nmethods should always be entrant after migration");
// In case a concurrent thread disarmed the nmethod, we need to ensure the new instructions
// are made visible, by using a cross modify fence. Note that this is synchronous cross modifying
@@ -188,11 +184,11 @@ int BarrierSetNMethod::nmethod_stub_entry_barrier(address* return_address_ptr) {
// it can be made conditional on the nmethod_patching_type.
OrderAccess::cross_modify_fence();
// Diagnostic option to force deoptimization 1 in 3 times. It is otherwise
// Diagnostic option to force deoptimization 1 in 10 times. It is otherwise
// a very rare event.
if (DeoptimizeNMethodBarriersALot) {
if (DeoptimizeNMethodBarriersALot && !nm->is_osr_method()) {
static volatile uint32_t counter=0;
if (Atomic::add(&counter, 1u) % 3 == 0) {
if (Atomic::add(&counter, 1u) % 10 == 0) {
may_enter = false;
}
}
@@ -205,15 +201,6 @@ int BarrierSetNMethod::nmethod_stub_entry_barrier(address* return_address_ptr) {
}
bool BarrierSetNMethod::nmethod_osr_entry_barrier(nmethod* nm) {
// This check depends on the invariant that all nmethods that are deoptimized / made not entrant
// are NOT disarmed.
// This invariant is important because a method can be deoptimized after the method have been
// resolved / looked up by OSR by another thread. By not deoptimizing them we guarantee that
// a deoptimized method will always hit the barrier and come to the same conclusion - deoptimize
if (!is_armed(nm)) {
return true;
}
assert(nm->is_osr_method(), "Should not reach here");
log_trace(nmethod, barrier)("Running osr nmethod entry barrier: " PTR_FORMAT, p2i(nm));
bool result = nmethod_entry_barrier(nm);

View File

@@ -132,7 +132,7 @@ bool VM_GC_Operation::doit_prologue() {
void VM_GC_Operation::doit_epilogue() {
// GC thread root traversal likely used OopMapCache a lot, which
// might have created lots of old entries. Trigger the cleanup now.
OopMapCache::trigger_cleanup();
OopMapCache::try_trigger_cleanup();
if (Universe::has_reference_pending_list()) {
Heap_lock->notify_all();
}

View File

@@ -44,7 +44,7 @@ void VM_ShenandoahOperation::doit_epilogue() {
assert(!ShenandoahHeap::heap()->has_gc_state_changed(), "GC State was not synchronized to java threads.");
// GC thread root traversal likely used OopMapCache a lot, which
// might have created lots of old entries. Trigger the cleanup now.
OopMapCache::trigger_cleanup();
OopMapCache::try_trigger_cleanup();
}
bool VM_ShenandoahReferenceOperation::doit_prologue() {

View File

@@ -134,7 +134,7 @@ public:
// GC thread root traversal likely used OopMapCache a lot, which
// might have created lots of old entries. Trigger the cleanup now.
OopMapCache::trigger_cleanup();
OopMapCache::try_trigger_cleanup();
}
bool gc_locked() const {

View File

@@ -524,6 +524,10 @@ static bool rule_major_allocation_rate(const ZDirectorStats& stats) {
}
static double calculate_young_to_old_worker_ratio(const ZDirectorStats& stats) {
if (!stats._old_stats._cycle._is_time_trustable) {
return 1.0;
}
const double young_gc_time = gc_time(stats._young_stats);
const double old_gc_time = gc_time(stats._old_stats);
const size_t reclaimed_per_young_gc = stats._young_stats._stat_heap._reclaimed_avg;

View File

@@ -456,7 +456,7 @@ public:
// GC thread root traversal likely used OopMapCache a lot, which
// might have created lots of old entries. Trigger the cleanup now.
OopMapCache::trigger_cleanup();
OopMapCache::try_trigger_cleanup();
}
bool success() const {

View File

@@ -1810,7 +1810,7 @@ void LinkResolver::resolve_invokedynamic(CallInfo& result, const constantPoolHan
// the interpreter or runtime performs a serialized check of
// the relevant ResolvedIndyEntry::method field. This is done by the caller
// of this method, via CPC::set_dynamic_call, which uses
// a lock to do the final serialization of updates
// an ObjectLocker to do the final serialization of updates
// to ResolvedIndyEntry state, including method.
// Log dynamic info to CDS classlist.

View File

@@ -66,9 +66,6 @@ class OopMapCacheEntry: private InterpreterOopMap {
public:
OopMapCacheEntry() : InterpreterOopMap() {
_next = nullptr;
#ifdef ASSERT
_resource_allocate_bit_mask = false;
#endif
}
};
@@ -177,9 +174,13 @@ class VerifyClosure : public OffsetClosure {
InterpreterOopMap::InterpreterOopMap() {
initialize();
#ifdef ASSERT
_resource_allocate_bit_mask = true;
#endif
}
InterpreterOopMap::~InterpreterOopMap() {
if (has_valid_mask() && mask_size() > small_mask_limit) {
assert(_bit_mask[0] != 0, "should have pointer to C heap");
FREE_C_HEAP_ARRAY(uintptr_t, _bit_mask[0]);
}
}
bool InterpreterOopMap::is_empty() const {
@@ -399,37 +400,24 @@ void OopMapCacheEntry::deallocate(OopMapCacheEntry* const entry) {
// Implementation of OopMapCache
void InterpreterOopMap::resource_copy(OopMapCacheEntry* from) {
assert(_resource_allocate_bit_mask,
"Should not resource allocate the _bit_mask");
assert(from->has_valid_mask(),
"Cannot copy entry with an invalid mask");
void InterpreterOopMap::copy_from(const OopMapCacheEntry* src) {
// The expectation is that this InterpreterOopMap is recently created
// and empty. It is used to get a copy of a cached entry.
assert(!has_valid_mask(), "InterpreterOopMap object can only be filled once");
assert(src->has_valid_mask(), "Cannot copy entry with an invalid mask");
set_method(from->method());
set_bci(from->bci());
set_mask_size(from->mask_size());
set_expression_stack_size(from->expression_stack_size());
_num_oops = from->num_oops();
set_method(src->method());
set_bci(src->bci());
set_mask_size(src->mask_size());
set_expression_stack_size(src->expression_stack_size());
_num_oops = src->num_oops();
// Is the bit mask contained in the entry?
if (from->mask_size() <= small_mask_limit) {
memcpy((void *)_bit_mask, (void *)from->_bit_mask,
mask_word_size() * BytesPerWord);
if (src->mask_size() <= small_mask_limit) {
memcpy(_bit_mask, src->_bit_mask, mask_word_size() * BytesPerWord);
} else {
// The expectation is that this InterpreterOopMap is a recently created
// and empty. It is used to get a copy of a cached entry.
// If the bit mask has a value, it should be in the
// resource area.
assert(_bit_mask[0] == 0 ||
Thread::current()->resource_area()->contains((void*)_bit_mask[0]),
"The bit mask should have been allocated from a resource area");
// Allocate the bit_mask from a Resource area for performance. Allocating
// from the C heap as is done for OopMapCache has a significant
// performance impact.
_bit_mask[0] = (uintptr_t) NEW_RESOURCE_ARRAY(uintptr_t, mask_word_size());
assert(_bit_mask[0] != 0, "bit mask was not allocated");
memcpy((void*) _bit_mask[0], (void*) from->_bit_mask[0],
mask_word_size() * BytesPerWord);
_bit_mask[0] = (uintptr_t) NEW_C_HEAP_ARRAY(uintptr_t, mask_word_size(), mtClass);
memcpy((void*) _bit_mask[0], (void*) src->_bit_mask[0], mask_word_size() * BytesPerWord);
}
}
@@ -516,7 +504,7 @@ void OopMapCache::lookup(const methodHandle& method,
for (int i = 0; i < _probe_depth; i++) {
OopMapCacheEntry *entry = entry_at(probe + i);
if (entry != nullptr && !entry->is_empty() && entry->match(method, bci)) {
entry_for->resource_copy(entry);
entry_for->copy_from(entry);
assert(!entry_for->is_empty(), "A non-empty oop map should be returned");
log_debug(interpreter, oopmap)("- found at hash %d", probe + i);
return;
@@ -530,7 +518,7 @@ void OopMapCache::lookup(const methodHandle& method,
OopMapCacheEntry* tmp = NEW_C_HEAP_OBJ(OopMapCacheEntry, mtClass);
tmp->initialize();
tmp->fill(method, bci);
entry_for->resource_copy(tmp);
entry_for->copy_from(tmp);
if (method->should_not_be_cached()) {
// It is either not safe or not a good idea to cache this Method*
@@ -592,10 +580,13 @@ bool OopMapCache::has_cleanup_work() {
return Atomic::load(&_old_entries) != nullptr;
}
void OopMapCache::trigger_cleanup() {
if (has_cleanup_work()) {
MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
void OopMapCache::try_trigger_cleanup() {
// See we can take the lock for the notification without blocking.
// This allows triggering the cleanup from GC paths, that can hold
// the service lock for e.g. oop iteration in service thread.
if (has_cleanup_work() && Service_lock->try_lock_without_rank_check()) {
Service_lock->notify_all();
Service_lock->unlock();
}
}
@@ -628,7 +619,7 @@ void OopMapCache::compute_one_oop_map(const methodHandle& method, int bci, Inter
tmp->initialize();
tmp->fill(method, bci);
if (tmp->has_valid_mask()) {
entry->resource_copy(tmp);
entry->copy_from(tmp);
}
OopMapCacheEntry::deallocate(tmp);
}

View File

@@ -36,13 +36,14 @@
// OopMapCache's are allocated lazily per InstanceKlass.
// The oopMap (InterpreterOopMap) is stored as a bit mask. If the
// bit_mask can fit into two words it is stored in
// bit_mask can fit into four words it is stored in
// the _bit_mask array, otherwise it is allocated on the heap.
// For OopMapCacheEntry the bit_mask is allocated in the C heap
// because these entries persist between garbage collections.
// For InterpreterOopMap the bit_mask is allocated in
// a resource area for better performance. InterpreterOopMap
// should only be created and deleted during same garbage collection.
// For InterpreterOopMap the bit_mask is allocated in the C heap
// to avoid issues with allocations from the resource area that have
// to live accross the oop closure. InterpreterOopMap should only be
// created and deleted during the same garbage collection.
//
// If ENABBLE_ZAP_DEAD_LOCALS is defined, two bits are used
// per entry instead of one. In all cases,
@@ -95,9 +96,6 @@ class InterpreterOopMap: ResourceObj {
// access it without using trickery in
// method bit_mask().
int _num_oops;
#ifdef ASSERT
bool _resource_allocate_bit_mask;
#endif
// access methods
Method* method() const { return _method; }
@@ -128,12 +126,13 @@ class InterpreterOopMap: ResourceObj {
public:
InterpreterOopMap();
~InterpreterOopMap();
// Copy the OopMapCacheEntry in parameter "from" into this
// InterpreterOopMap. If the _bit_mask[0] in "from" points to
// allocated space (i.e., the bit mask was to large to hold
// in-line), allocate the space from a Resource area.
void resource_copy(OopMapCacheEntry* from);
// Copy the OopMapCacheEntry in parameter "src" into this
// InterpreterOopMap. If the _bit_mask[0] in "src" points to
// allocated space (i.e., the bit mask was too large to hold
// in-line), allocate the space from the C heap.
void copy_from(const OopMapCacheEntry* src);
void iterate_oop(OffsetClosure* oop_closure) const;
void print() const;
@@ -183,8 +182,8 @@ class OopMapCache : public CHeapObj<mtClass> {
// Check if we need to clean up old entries
static bool has_cleanup_work();
// Request cleanup if work is needed
static void trigger_cleanup();
// Request cleanup if work is needed and notification is currently possible
static void try_trigger_cleanup();
// Clean up the old entries
static void cleanup();

View File

@@ -30,6 +30,7 @@
#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/checkpoint/jfrMetadataEvent.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
#include "jfr/recorder/repository/jfrChunk.hpp"
#include "jfr/recorder/repository/jfrRepository.hpp"
#include "jfr/recorder/repository/jfrChunkRotation.hpp"
#include "jfr/recorder/repository/jfrChunkWriter.hpp"
@@ -425,3 +426,7 @@ JVM_END
JVM_ENTRY_NO_ENV(void, jfr_unregister_stack_filter(JNIEnv* env, jclass jvm, jlong id))
JfrStackFilterRegistry::remove(id);
JVM_END
NO_TRANSITION(jlong, jfr_nanos_now(JNIEnv* env, jclass jvm))
return JfrChunk::nanos_now();
NO_TRANSITION_END

View File

@@ -165,6 +165,8 @@ jlong JNICALL jfr_register_stack_filter(JNIEnv* env, jclass jvm, jobjectArray cl
jlong JNICALL jfr_unregister_stack_filter(JNIEnv* env, jclass jvm, jlong id);
jlong JNICALL jfr_nanos_now(JNIEnv* env, jclass jvm);
#ifdef __cplusplus
}
#endif

View File

@@ -100,7 +100,8 @@ JfrJniMethodRegistration::JfrJniMethodRegistration(JNIEnv* env) {
(char*)"hostTotalSwapMemory", (char*)"()J", (void*) jfr_host_total_swap_memory,
(char*)"emitDataLoss", (char*)"(J)V", (void*)jfr_emit_data_loss,
(char*)"registerStackFilter", (char*)"([Ljava/lang/String;[Ljava/lang/String;)J", (void*)jfr_register_stack_filter,
(char*)"unregisterStackFilter", (char*)"(J)V", (void*)jfr_unregister_stack_filter
(char*)"unregisterStackFilter", (char*)"(J)V", (void*)jfr_unregister_stack_filter,
(char*)"nanosNow", (char*)"()J", (void*)jfr_nanos_now
};
const size_t method_array_length = sizeof(method) / sizeof(JNINativeMethod);

View File

@@ -36,6 +36,7 @@
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
#include "jfr/recorder/service/jfrOptionSet.hpp"
#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
#include "jfr/recorder/storage/jfrReferenceCountedStorage.hpp"
#include "jfr/support/jfrKlassUnloading.hpp"
#include "jfr/support/jfrMethodLookup.hpp"
#include "jfr/utilities/jfrHashtable.hpp"
@@ -272,11 +273,30 @@ static void install_stack_traces(const ObjectSampler* sampler) {
iterate_samples(installer);
}
// Resets the blob write states from the previous epoch.
static void reset_blob_write_state(const ObjectSampler* sampler, JavaThread* jt) {
assert(sampler != nullptr, "invariant");
const ObjectSample* sample = sampler->last_resolved();
while (sample != nullptr) {
if (sample->has_stacktrace()) {
sample->stacktrace()->reset_write_state();
}
if (sample->has_thread()) {
sample->thread()->reset_write_state();
}
if (sample->has_type_set()) {
sample->type_set()->reset_write_state();
}
sample = sample->next();
}
}
void ObjectSampleCheckpoint::on_rotation(const ObjectSampler* sampler) {
assert(sampler != nullptr, "invariant");
assert(LeakProfiler::is_running(), "invariant");
JavaThread* const thread = JavaThread::current();
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(thread);)
reset_blob_write_state(sampler, thread);
if (!ObjectSampler::has_unresolved_entry()) {
return;
}
@@ -326,38 +346,34 @@ void ObjectSampleCheckpoint::write_stacktrace(const JfrStackTrace* trace, JfrChe
}
}
static void write_blob(const JfrBlobHandle& blob, JfrCheckpointWriter& writer, bool reset) {
if (reset) {
blob->reset_write_state();
return;
}
static void write_blob(const JfrBlobHandle& blob, JfrCheckpointWriter& writer) {
blob->exclusive_write(writer);
}
static void write_type_set_blob(const ObjectSample* sample, JfrCheckpointWriter& writer, bool reset) {
static void write_type_set_blob(const ObjectSample* sample, JfrCheckpointWriter& writer) {
if (sample->has_type_set()) {
write_blob(sample->type_set(), writer, reset);
write_blob(sample->type_set(), writer);
}
}
static void write_thread_blob(const ObjectSample* sample, JfrCheckpointWriter& writer, bool reset) {
static void write_thread_blob(const ObjectSample* sample, JfrCheckpointWriter& writer) {
assert(sample->has_thread(), "invariant");
if (sample->is_virtual_thread() || has_thread_exited(sample->thread_id())) {
write_blob(sample->thread(), writer, reset);
write_blob(sample->thread(), writer);
}
}
static void write_stacktrace_blob(const ObjectSample* sample, JfrCheckpointWriter& writer, bool reset) {
static void write_stacktrace_blob(const ObjectSample* sample, JfrCheckpointWriter& writer) {
if (sample->has_stacktrace()) {
write_blob(sample->stacktrace(), writer, reset);
write_blob(sample->stacktrace(), writer);
}
}
static void write_blobs(const ObjectSample* sample, JfrCheckpointWriter& writer, bool reset) {
static void write_blobs(const ObjectSample* sample, JfrCheckpointWriter& writer) {
assert(sample != nullptr, "invariant");
write_stacktrace_blob(sample, writer, reset);
write_thread_blob(sample, writer, reset);
write_type_set_blob(sample, writer, reset);
write_stacktrace_blob(sample, writer);
write_thread_blob(sample, writer);
write_type_set_blob(sample, writer);
}
class BlobWriter {
@@ -365,18 +381,14 @@ class BlobWriter {
const ObjectSampler* _sampler;
JfrCheckpointWriter& _writer;
const jlong _last_sweep;
bool _reset;
public:
BlobWriter(const ObjectSampler* sampler, JfrCheckpointWriter& writer, jlong last_sweep) :
_sampler(sampler), _writer(writer), _last_sweep(last_sweep), _reset(false) {}
_sampler(sampler), _writer(writer), _last_sweep(last_sweep) {}
void sample_do(ObjectSample* sample) {
if (sample->is_alive_and_older_than(_last_sweep)) {
write_blobs(sample, _writer, _reset);
write_blobs(sample, _writer);
}
}
void set_reset() {
_reset = true;
}
};
static void write_sample_blobs(const ObjectSampler* sampler, bool emit_all, Thread* thread) {
@@ -385,9 +397,6 @@ static void write_sample_blobs(const ObjectSampler* sampler, bool emit_all, Thre
JfrCheckpointWriter writer(thread, false);
BlobWriter cbw(sampler, writer, last_sweep);
iterate_samples(cbw, true);
// reset blob write states
cbw.set_reset();
iterate_samples(cbw, true);
}
void ObjectSampleCheckpoint::write(const ObjectSampler* sampler, EdgeStore* edge_store, bool emit_all, Thread* thread) {
@@ -403,67 +412,17 @@ void ObjectSampleCheckpoint::write(const ObjectSampler* sampler, EdgeStore* edge
}
}
// A linked list of saved type set blobs for the epoch.
// The link consist of a reference counted handle.
static JfrBlobHandle saved_type_set_blobs;
static void release_state_for_previous_epoch() {
// decrements the reference count and the list is reinitialized
saved_type_set_blobs = JfrBlobHandle();
}
class BlobInstaller {
public:
~BlobInstaller() {
release_state_for_previous_epoch();
}
void sample_do(ObjectSample* sample) {
if (!sample->is_dead()) {
sample->set_type_set(saved_type_set_blobs);
}
}
};
static void install_type_set_blobs() {
if (saved_type_set_blobs.valid()) {
BlobInstaller installer;
iterate_samples(installer);
}
}
static void save_type_set_blob(JfrCheckpointWriter& writer) {
assert(writer.has_data(), "invariant");
const JfrBlobHandle blob = writer.copy();
if (saved_type_set_blobs.valid()) {
saved_type_set_blobs->set_next(blob);
} else {
saved_type_set_blobs = blob;
}
}
// This routine has exclusive access to the sampler instance on entry.
void ObjectSampleCheckpoint::on_type_set(JfrCheckpointWriter& writer) {
void ObjectSampleCheckpoint::on_type_set(JavaThread* jt) {
assert(LeakProfiler::is_running(), "invariant");
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(JavaThread::current());)
assert(ClassLoaderDataGraph_lock->owned_by_self(), "invariant");
if (!ObjectSampler::has_unresolved_entry()) {
return;
}
const ObjectSample* const last = ObjectSampler::sampler()->last();
ObjectSample* const last = ObjectSampler::sampler()->last();
assert(last != nullptr, "invariant");
assert(last != ObjectSampler::sampler()->last_resolved(), "invariant");
if (writer.has_data()) {
save_type_set_blob(writer);
}
install_type_set_blobs();
JfrReferenceCountedStorage::install(last, ObjectSampler::sampler()->last_resolved());
ObjectSampler::sampler()->set_last_resolved(last);
}
// This routine does NOT have exclusive access to the sampler instance on entry.
void ObjectSampleCheckpoint::on_type_set_unload(JfrCheckpointWriter& writer) {
assert(LeakProfiler::is_running(), "invariant");
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
if (writer.has_data() && ObjectSampler::has_unresolved_entry()) {
save_type_set_blob(writer);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 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
@@ -50,8 +50,7 @@ class ObjectSampleCheckpoint : AllStatic {
static void write(const ObjectSampler* sampler, EdgeStore* edge_store, bool emit_all, Thread* thread);
static void clear();
public:
static void on_type_set(JfrCheckpointWriter& writer);
static void on_type_set_unload(JfrCheckpointWriter& writer);
static void on_type_set(JavaThread* jt);
static void on_thread_exit(traceid tid);
static void on_rotation(const ObjectSampler* sampler);
};

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 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
@@ -233,7 +233,7 @@ class ObjectSample : public JfrCHeapObj {
return _type_set.valid();
}
void set_type_set(const JfrBlobHandle& ref) {
void install_type_set(const JfrBlobHandle& ref) {
if (_type_set != ref) {
if (_type_set.valid()) {
_type_set->set_next(ref);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 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
@@ -37,6 +37,7 @@
#include "jfr/recorder/service/jfrOptionSet.hpp"
#include "jfr/recorder/storage/jfrEpochStorage.inline.hpp"
#include "jfr/recorder/storage/jfrMemorySpace.inline.hpp"
#include "jfr/recorder/storage/jfrReferenceCountedStorage.hpp"
#include "jfr/recorder/storage/jfrStorageUtils.inline.hpp"
#include "jfr/recorder/stringpool/jfrStringPool.hpp"
#include "jfr/support/jfrDeprecationManager.hpp"
@@ -589,12 +590,14 @@ void JfrCheckpointManager::clear_type_set() {
MutexLocker module_lock(Module_lock);
JfrTypeSet::clear(&writer, &leakp_writer);
}
JfrDeprecationManager::on_type_set(leakp_writer, nullptr, thread);
// We placed a blob in the Deprecated subsystem by moving the information
// from the leakp writer. For the real writer, the data will not be
// committed, because the JFR system is yet to be started.
// Therefore, the writer is cancelled before its destructor is run,
// to avoid writing unnecessary information into the checkpoint system.
JfrAddRefCountedBlob add_blob(leakp_writer);
JfrDeprecationManager::on_type_set(nullptr, thread);
// We installed a blob in the JfrReferenceCountedStorage subsystem
// by moving the information from the leakp writer.
// For the real writer, the data will not be committed,
// because the JFR system is yet to be started.
// Therefore, we cancel the writer before its destructor is run
// to avoid writing invalid information into the checkpoint system.
writer.cancel();
}
@@ -613,11 +616,11 @@ void JfrCheckpointManager::write_type_set() {
MutexLocker module_lock(thread, Module_lock);
JfrTypeSet::serialize(&writer, &leakp_writer, false, false);
}
JfrAddRefCountedBlob add_blob(leakp_writer);
if (LeakProfiler::is_running()) {
ObjectSampleCheckpoint::on_type_set(leakp_writer);
ObjectSampleCheckpoint::on_type_set(thread);
}
// Place this call after ObjectSampleCheckpoint::on_type_set.
JfrDeprecationManager::on_type_set(leakp_writer, _chunkwriter, thread);
JfrDeprecationManager::on_type_set(_chunkwriter, thread);
}
write();
}
@@ -626,10 +629,7 @@ void JfrCheckpointManager::on_unloading_classes() {
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
JfrCheckpointWriter writer(Thread::current());
JfrTypeSet::on_unloading_classes(&writer);
if (LeakProfiler::is_running()) {
ObjectSampleCheckpoint::on_type_set_unload(writer);
}
JfrDeprecationManager::on_type_set_unload(writer);
JfrAddRefCountedBlob add_blob(writer, false /* move */, false /* reset */);
}
static size_t flush_type_set(Thread* thread) {

View File

@@ -54,6 +54,7 @@ struct JfrCheckpointContext {
};
class JfrCheckpointWriter : public JfrCheckpointWriterBase {
friend class JfrAddRefCountedBlob;
friend class JfrCheckpointManager;
friend class JfrDeprecationManager;
friend class JfrSerializerRegistration;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 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
@@ -35,7 +35,7 @@ static const u2 JFR_VERSION_MAJOR = 2;
static const u2 JFR_VERSION_MINOR = 1;
// strictly monotone
static jlong nanos_now() {
jlong JfrChunk::nanos_now() {
static jlong last = 0;
jlong seconds;
@@ -47,8 +47,6 @@ static jlong nanos_now() {
const jlong now = seconds * 1000000000 + nanos;
if (now > last) {
last = now;
} else {
++last;
}
return last;
}
@@ -147,7 +145,7 @@ void JfrChunk::update_start_ticks() {
}
void JfrChunk::update_start_nanos() {
const jlong now = nanos_now();
const jlong now = JfrChunk::nanos_now();
assert(now >= _start_nanos, "invariant");
assert(now >= _last_update_nanos, "invariant");
_start_nanos = _last_update_nanos = now;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 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
@@ -34,6 +34,8 @@ const u1 PAD = 0;
class JfrChunk : public JfrCHeapObj {
friend class JfrChunkWriter;
friend class JfrChunkHeadWriter;
public:
static jlong nanos_now();
private:
char* _path;
int64_t _start_ticks;

View File

@@ -0,0 +1,79 @@
/*
* Copyright (c) 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 "precompiled.hpp"
#include "jfr/leakprofiler/sampling/objectSampler.hpp"
#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
#include "jfr/recorder/storage/jfrReferenceCountedStorage.hpp"
#include "jfr/support/jfrDeprecationManager.hpp"
// Currently only two subsystems use type set blobs. Save a blob only if either has an unresolved entry.
static inline bool save_blob_predicate() {
return JfrDeprecationManager::has_unresolved_entry() || ObjectSampler::has_unresolved_entry();
}
JfrAddRefCountedBlob::JfrAddRefCountedBlob(JfrCheckpointWriter& writer, bool move /* true */, bool reset /* true */) : _reset(reset) {
if (writer.has_data()) {
if (save_blob_predicate()) {
JfrReferenceCountedStorage::save_blob(writer, move);
} else if (move) {
writer.cancel();
}
}
DEBUG_ONLY(if (reset) JfrReferenceCountedStorage::set_scope();)
}
JfrAddRefCountedBlob::~JfrAddRefCountedBlob() {
if (_reset) {
JfrReferenceCountedStorage::reset();
}
}
JfrBlobHandle JfrReferenceCountedStorage::_type_sets = JfrBlobHandle();
DEBUG_ONLY(bool JfrReferenceCountedStorage::_scope = false;)
void JfrReferenceCountedStorage::save_blob(JfrCheckpointWriter& writer, bool move /* false */) {
assert(writer.has_data(), "invariant");
const JfrBlobHandle blob = move ? writer.move() : writer.copy();
if (_type_sets.valid()) {
_type_sets->set_next(blob);
return;
}
_type_sets = blob;
}
void JfrReferenceCountedStorage::reset() {
assert(_scope, "invariant");
if (_type_sets.valid()) {
_type_sets = JfrBlobHandle();
}
DEBUG_ONLY(_scope = false;)
}
#ifdef ASSERT
void JfrReferenceCountedStorage::set_scope() {
assert(!_scope, "invariant");
_scope = true;
}
#endif

View File

@@ -0,0 +1,68 @@
/*
* Copyright (c) 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.
*
*/
#ifndef SHARE_JFR_RECORDER_STORAGE_JFRREFERENCECOUNTEDSTORAGE_HPP
#define SHARE_JFR_RECORDER_STORAGE_JFRREFERENCECOUNTEDSTORAGE_HPP
#include "jfr/utilities/jfrBlob.hpp"
#include "memory/allocation.hpp"
#include "utilities/macros.hpp"
class JfrCheckpointWriter;
// RAII helper class for adding blobs to the storage.
class JfrAddRefCountedBlob : public StackObj {
private:
bool _reset;
public:
JfrAddRefCountedBlob(JfrCheckpointWriter& writer, bool move = true, bool reset = true);
~JfrAddRefCountedBlob();
};
// The debug aid 'scope' implies the proper RAII save construct is placed on stack.
// This is a necessary condition for installing reference counted storage to nodes.
class JfrReferenceCountedStorage : AllStatic {
friend class JfrAddRefCountedBlob;
private:
static JfrBlobHandle _type_sets; // linked-list of blob handles saved during epoch.
DEBUG_ONLY(static bool _scope;)
static void save_blob(JfrCheckpointWriter& writer, bool move = false);
static void reset();
DEBUG_ONLY(static void set_scope();)
public:
template <typename T>
static void install(T* node, const T* end) {
assert(_scope, "invariant");
if (_type_sets.valid()) {
while (node != end) {
node->install_type_set(_type_sets);
node = node->next();
}
}
}
};
#endif // SHARE_JFR_RECORDER_STORAGE_JFRREFERENCECOUNTEDSTORAGE_HPP

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
@@ -116,8 +116,8 @@ bool JfrDeprecatedStackTraceWriter::process(const JfrDeprecatedEdge* edge) {
return true;
}
JfrDeprecatedEventWriter::JfrDeprecatedEventWriter(JfrChunkWriter& cw, bool stacktrace) :
_now(JfrTicks::now()),_cw(cw), _for_removal(only_for_removal()), _stacktrace(stacktrace), _did_write(false) {}
JfrDeprecatedEventWriter::JfrDeprecatedEventWriter(JfrChunkWriter& cw, JfrCheckpointWriter& tsw, bool stacktrace) :
_now(JfrTicks::now()),_cw(cw), _tsw(tsw), _for_removal(only_for_removal()), _stacktrace(stacktrace) {}
static size_t calculate_event_size(const JfrDeprecatedEdge* edge, JfrChunkWriter& cw, const JfrTicks& now, bool stacktrace) {
assert(edge != nullptr, "invariant");
@@ -141,14 +141,31 @@ static void write_event(const JfrDeprecatedEdge* edge, JfrChunkWriter& cw, const
cw.write(edge->for_removal());
}
static void write_type_set(const JfrDeprecatedEdge* edge, JfrCheckpointWriter& tsw) {
if (!edge->has_type_set()) {
return;
}
edge->type_set()->exclusive_write(tsw);
}
bool JfrDeprecatedEventWriter::process(const JfrDeprecatedEdge* edge) {
assert(edge != nullptr, "invariant");
if (_for_removal && !edge->for_removal()) {
return true;
}
write_event(edge, _cw,_now, _stacktrace);
if (!_did_write) {
_did_write = true;
}
write_event(edge, _cw, _now, _stacktrace);
write_type_set(edge, _tsw);
return true;
}
JfrDeprecatedEventClear::JfrDeprecatedEventClear() {}
bool JfrDeprecatedEventClear::process(const JfrDeprecatedEdge* edge) {
assert(edge != nullptr, "invariant");
if (!edge->has_type_set()) {
return true;
}
edge->type_set()->reset_write_state();
return true;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
@@ -56,12 +56,17 @@ class JfrDeprecatedEventWriter : public StackObj {
private:
JfrTicks _now;
JfrChunkWriter& _cw;
JfrCheckpointWriter& _tsw;
bool _for_removal;
bool _stacktrace;
bool _did_write;
public:
JfrDeprecatedEventWriter(JfrChunkWriter& cw, bool stacktrace);
bool did_write() const { return _did_write; }
JfrDeprecatedEventWriter(JfrChunkWriter& cw, JfrCheckpointWriter& tsw, bool stacktrace);
bool process(const JfrDeprecatedEdge* edge);
};
class JfrDeprecatedEventClear : public StackObj {
public:
JfrDeprecatedEventClear();
bool process(const JfrDeprecatedEdge* edge);
};

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
@@ -32,6 +32,7 @@
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
#include "jfr/recorder/repository/jfrChunkWriter.hpp"
#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
#include "jfr/recorder/storage/jfrReferenceCountedStorage.hpp"
#include "jfr/support/jfrDeprecationEventWriter.hpp"
#include "jfr/support/jfrDeprecationManager.hpp"
#include "jfr/support/jfrKlassUnloading.hpp"
@@ -66,6 +67,7 @@ static inline traceid load_traceid(const Method* method) {
JfrDeprecatedEdge::JfrDeprecatedEdge(const Method* method, Method* sender, int bci, u1 frame_type, JavaThread* jt) :
_invocation_time(JfrTicks::now()),
_stacktrace(),
_type_set(),
_next(nullptr),
_deprecated_ik(method->method_holder()),
_deprecated_methodid(load_traceid(method)),
@@ -94,11 +96,25 @@ const JfrBlobHandle& JfrDeprecatedEdge::stacktrace() const {
return _stacktrace;
}
bool JfrDeprecatedEdge::has_type_set() const {
return _type_set.valid();
}
const JfrBlobHandle& JfrDeprecatedEdge::type_set() const {
assert(has_type_set(), "invariant");
return _type_set;
}
void JfrDeprecatedEdge::install_type_set(const JfrBlobHandle& type_set) {
assert(!has_type_set(), "invariant");
_type_set = type_set;
}
typedef JfrLinkedList<JfrDeprecatedEdge> DeprecatedEdgeList;
static DeprecatedEdgeList _list; // Newly constructed edges are concurrently added to this list.
static DeprecatedEdgeList _pending_list; // During epoch rotation (safepoint) entries in _list are moved onto _pending_list
static DeprecatedEdgeList _resolved_list; // Fully resolved edges (event and stacktrace blobs).
static DeprecatedEdgeList _resolved_list; // Fully resolved edges (event, stacktrace and typeset blobs).
static JfrDeprecatedEdge* allocate_edge(const Method* method, Method* sender, int bci, u1 frame_type, JavaThread* jt) {
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt);)
@@ -225,10 +241,6 @@ static void transfer_list() {
}
}
void JfrDeprecationManager::on_level_setting_update(int64_t new_level) {
JfrDeprecatedEventWriterState::on_level_setting_update(new_level);
}
void JfrDeprecationManager::on_safepoint_clear() {
assert(!_enqueue_klasses, "invariant");
// We are now starting JFR, so begin enqueuing tagged klasses.
@@ -270,6 +282,23 @@ static void add_to_leakp_set(const JfrDeprecatedEdge* edge) {
static DeprecatedEdgeList::NodePtr _pending_head = nullptr;
static DeprecatedEdgeList::NodePtr _pending_tail = nullptr;
inline DeprecatedEdgeList::NodePtr pending_head() {
return Atomic::load(&_pending_head);
}
// The test for a pending head can be read concurrently from a thread doing class unloading.
inline static bool has_pending_head() {
return pending_head() != nullptr;
}
inline static bool no_pending_head() {
return !has_pending_head();
}
inline static void set_pending_head(DeprecatedEdgeList::NodePtr head) {
Atomic::store(&_pending_head, head);
}
class PendingListProcessor {
private:
JfrCheckpointWriter& _writer;
@@ -281,66 +310,57 @@ class PendingListProcessor {
JfrDeprecatedStackTraceWriter::install_stacktrace_blob(edge, _writer, _jt);
assert(edge->has_stacktrace(), "invariant");
add_to_leakp_set(edge);
if (_pending_head == nullptr) {
_pending_head = edge;
if (no_pending_head()) {
set_pending_head(edge);
}
_pending_tail = edge;
return true;
}
};
void JfrDeprecationManager::prepare_type_set(JavaThread* jt) {
_pending_head = nullptr;
// Resets the pending head and tail.
// Resets blob write states for nodes on the resolved list, dirtied in the previous epoch.
static void reset_type_set_blobs() {
set_pending_head(nullptr);
_pending_tail = nullptr;
if (_resolved_list.is_nonempty()) {
JfrDeprecatedEventClear clear;
_resolved_list.iterate(clear);
}
}
void JfrDeprecationManager::prepare_type_set(JavaThread* jt) {
reset_type_set_blobs();
if (_pending_list.is_nonempty()) {
JfrKlassUnloading::sort(true);
JfrCheckpointWriter writer(true /* prev epoch */, jt, false /* header */);
PendingListProcessor plp(writer, jt);
_pending_list.iterate(plp);
assert(_pending_head != nullptr, "invariant");
assert(has_pending_head(), "invariant");
assert(_pending_tail != nullptr, "invariant");
assert(_pending_tail->next() == nullptr, "invariant");
// Excise already resolved edges to link them.
_pending_tail->set_next(_resolved_list.cut());
// Re-insertion.
_resolved_list.add_list(_pending_head);
_resolved_list.add_list(pending_head());
_pending_list.clear();
}
assert(_pending_list.is_empty(), "invariant");
}
// A linked-list of blob handles.
static JfrBlobHandle type_set_blobs;
static inline void write_type_set_blobs(JfrCheckpointWriter& writer) {
type_set_blobs->write(writer);
}
static void save_type_set_blob(JfrCheckpointWriter& writer, bool copy = false) {
assert(writer.has_data(), "invariant");
const JfrBlobHandle blob = copy ? writer.copy() : writer.move();
if (type_set_blobs.valid()) {
type_set_blobs->set_next(blob);
} else {
type_set_blobs = blob;
}
}
void JfrDeprecationManager::on_type_set_unload(JfrCheckpointWriter& writer) {
if (writer.has_data()) {
save_type_set_blob(writer, true);
}
bool JfrDeprecationManager::has_unresolved_entry() {
return _list.is_nonempty() || has_pending_head() || _pending_list.is_nonempty();
}
static inline bool has_stacktrace() {
return JfrEventSetting::has_stacktrace(JfrDeprecatedInvocationEvent);
}
static inline bool write_events(JfrChunkWriter& cw) {
static inline void write_events(JfrChunkWriter& cw, Thread* thread, bool on_error) {
assert(_resolved_list.is_nonempty(), "invariant");
JfrDeprecatedEventWriter ebw(cw, has_stacktrace());
JfrCheckpointWriter type_set_writer(!on_error, thread, false);
JfrDeprecatedEventWriter ebw(cw, type_set_writer, has_stacktrace());
_resolved_list.iterate(ebw);
return ebw.did_write();
}
static inline void write_stacktraces(JfrChunkWriter& cw) {
@@ -349,34 +369,30 @@ static inline void write_stacktraces(JfrChunkWriter& cw) {
_resolved_list.iterate(scw);
}
static inline void write_type_sets(Thread* thread, bool on_error) {
JfrCheckpointWriter writer(!on_error, thread, false);
write_type_set_blobs(writer);
}
// First, we consolidate all stacktrace blobs into a single TYPE_STACKTRACE checkpoint and serialize it to the chunk.
// Secondly, we serialize all events to the chunk.
// Thirdly, the type set blobs are written into the JfrCheckpoint system, to be serialized to the chunk
// just after we return from here.
// First, we consolidate all stack trace blobs into a single TYPE_STACKTRACE checkpoint
// and serialize it to the chunk. Then, all events are serialized, and unique type set blobs
// written into the JfrCheckpoint system to be serialized to the chunk upon return.
void JfrDeprecationManager::write_edges(JfrChunkWriter& cw, Thread* thread, bool on_error /* false */) {
if (_resolved_list.is_nonempty() && JfrEventSetting::is_enabled(JfrDeprecatedInvocationEvent)) {
if (has_stacktrace()) {
write_stacktraces(cw);
}
if (write_events(cw)) {
write_type_sets(thread, on_error);
}
write_events(cw, thread, on_error);
}
}
void JfrDeprecationManager::on_type_set(JfrCheckpointWriter& writer, JfrChunkWriter* cw, Thread* thread) {
void JfrDeprecationManager::on_type_set(JfrChunkWriter* cw, Thread* thread) {
assert(_pending_list.is_empty(), "invariant");
if (_pending_head != nullptr) {
save_type_set_blob(writer);
} else {
writer.cancel();
if (has_pending_head()) {
assert(_pending_tail != nullptr, "invariant");
// Install type set blobs for the pending, i.e. unresolved nodes.
JfrReferenceCountedStorage::install(pending_head(), _pending_tail->next());
}
if (cw != nullptr) {
write_edges(*cw, thread);
}
}
void JfrDeprecationManager::on_level_setting_update(int64_t new_level) {
JfrDeprecatedEventWriterState::on_level_setting_update(new_level);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
@@ -42,6 +42,7 @@ class JfrDeprecatedEdge : public CHeapObj<mtTracing> {
private:
JfrTicks _invocation_time;
JfrBlobHandle _stacktrace;
JfrBlobHandle _type_set;
JfrDeprecatedEdge* _next;
InstanceKlass* _deprecated_ik;
traceid _deprecated_methodid;
@@ -58,7 +59,7 @@ class JfrDeprecatedEdge : public CHeapObj<mtTracing> {
public:
JfrDeprecatedEdge(const Method* method, Method* sender, int bci, u1 frame_type, JavaThread* jt);
const JfrDeprecatedEdge* next() const { return _next; }
JfrDeprecatedEdge* next() const { return _next; }
void set_next(JfrDeprecatedEdge* edge) { _next = edge; }
bool has_event() const;
@@ -68,6 +69,10 @@ class JfrDeprecatedEdge : public CHeapObj<mtTracing> {
const JfrBlobHandle& stacktrace() const;
void install_stacktrace_blob(JavaThread* jt);
bool has_type_set() const;
const JfrBlobHandle& type_set() const;
void install_type_set(const JfrBlobHandle& type_set);
const InstanceKlass* deprecated_ik() const { return _deprecated_ik; }
traceid deprecated_methodid() const { return _deprecated_methodid; }
@@ -89,11 +94,11 @@ class JfrDeprecationManager : AllStatic {
static void on_safepoint_write();
static void on_recorder_stop();
static void prepare_type_set(JavaThread* jt);
static void on_type_set(JfrCheckpointWriter& writer, JfrChunkWriter* cw, Thread* thread);
static void on_type_set_unload(JfrCheckpointWriter& writer);
static void on_type_set(JfrChunkWriter* cw, Thread* thread);
static void write_edges(JfrChunkWriter& cw, Thread* thread, bool on_error = false);
static void on_link(const Method* method, Method* sender, int bci, u1 frame_type, JavaThread* thread);
static void on_level_setting_update(int64_t new_level);
static bool has_unresolved_entry();
};
#endif // SHARE_JFR_SUPPORT_JFRDEPRECATIONMANAGER_HPP

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 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
@@ -47,13 +47,13 @@ class JfrIntrinsicSupport : AllStatic {
#define JFR_HAVE_INTRINSICS
#define JFR_TEMPLATES(template) \
template(jdk_jfr_internal_HiddenWait, "jdk/jfr/internal/HiddenWait") \
template(jdk_jfr_internal_JVM, "jdk/jfr/internal/JVM") \
template(jdk_jfr_internal_event_EventWriterFactory, "jdk/jfr/internal/event/EventWriterFactory") \
template(jdk_jfr_internal_event_EventConfiguration_signature, "Ljdk/jfr/internal/event/EventConfiguration;") \
template(getEventWriter_signature, "()Ljdk/jfr/internal/event/EventWriter;") \
template(eventConfiguration_name, "eventConfiguration") \
template(commit_name, "commit") \
template(jfr_chunk_rotation_monitor, "jdk/jfr/internal/JVM$ChunkRotationMonitor") \
#define JFR_INTRINSICS(do_intrinsic, do_class, do_name, do_signature, do_alias) \
do_intrinsic(_counterTime, jdk_jfr_internal_JVM, counterTime_name, void_long_signature, F_SN) \

View File

@@ -55,6 +55,7 @@
#include "runtime/atomic.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/synchronizer.hpp"
#include "runtime/vm_version.hpp"
#include "utilities/macros.hpp"
@@ -173,7 +174,7 @@ void ConstantPoolCache::set_direct_or_vtable_call(Bytecodes::Code invoke_code,
}
if (invoke_code == Bytecodes::_invokestatic) {
assert(method->method_holder()->is_initialized() ||
method->method_holder()->is_init_thread(JavaThread::current()),
method->method_holder()->is_reentrant_initialization(JavaThread::current()),
"invalid class initialization state for invoke_static");
if (!VM_Version::supports_fast_class_init_checks() && method->needs_clinit_barrier()) {
@@ -268,11 +269,20 @@ ResolvedMethodEntry* ConstantPoolCache::set_method_handle(int method_index, cons
// A losing writer waits on the lock until the winner writes the method and leaves
// the lock, so that when the losing writer returns, he can use the linked
// cache entry.
// Lock fields to write
Bytecodes::Code invoke_code = Bytecodes::_invokehandle;
MutexLocker ml(constant_pool()->pool_holder()->init_monitor());
ResolvedMethodEntry* method_entry = resolved_method_entry_at(method_index);
JavaThread* current = JavaThread::current();
objArrayHandle resolved_references(current, constant_pool()->resolved_references());
// Use the resolved_references() lock for this cpCache entry.
// resolved_references are created for all classes with Invokedynamic, MethodHandle
// or MethodType constant pool cache entries.
assert(resolved_references() != nullptr,
"a resolved_references array should have been created for this class");
ObjectLocker ol(resolved_references, current);
ResolvedMethodEntry* method_entry = resolved_method_entry_at(method_index);
if (method_entry->is_resolved(invoke_code)) {
return method_entry;
}
@@ -310,7 +320,6 @@ ResolvedMethodEntry* ConstantPoolCache::set_method_handle(int method_index, cons
// Store appendix, if any.
if (has_appendix) {
const int appendix_index = method_entry->resolved_references_index();
objArrayOop resolved_references = constant_pool()->resolved_references();
assert(appendix_index >= 0 && appendix_index < resolved_references->length(), "oob");
assert(resolved_references->obj_at(appendix_index) == nullptr, "init just once");
resolved_references->obj_at_put(appendix_index, appendix());
@@ -555,7 +564,14 @@ bool ConstantPoolCache::save_and_throw_indy_exc(
assert(PENDING_EXCEPTION->is_a(vmClasses::LinkageError_klass()),
"No LinkageError exception");
MutexLocker ml(THREAD, cpool->pool_holder()->init_monitor());
// Use the resolved_references() lock for this cpCache entry.
// resolved_references are created for all classes with Invokedynamic, MethodHandle
// or MethodType constant pool cache entries.
JavaThread* current = THREAD;
objArrayHandle resolved_references(current, cpool->resolved_references());
assert(resolved_references() != nullptr,
"a resolved_references array should have been created for this class");
ObjectLocker ol(resolved_references, current);
// if the indy_info is resolved or the indy_resolution_failed flag is set then another
// thread either succeeded in resolving the method or got a LinkageError
@@ -578,11 +594,21 @@ bool ConstantPoolCache::save_and_throw_indy_exc(
oop ConstantPoolCache::set_dynamic_call(const CallInfo &call_info, int index) {
ResourceMark rm;
MutexLocker ml(constant_pool()->pool_holder()->init_monitor());
// Use the resolved_references() lock for this cpCache entry.
// resolved_references are created for all classes with Invokedynamic, MethodHandle
// or MethodType constant pool cache entries.
JavaThread* current = JavaThread::current();
constantPoolHandle cp(current, constant_pool());
objArrayHandle resolved_references(current, cp->resolved_references());
assert(resolved_references() != nullptr,
"a resolved_references array should have been created for this class");
ObjectLocker ol(resolved_references, current);
assert(index >= 0, "Indy index must be positive at this point");
if (resolved_indy_entry_at(index)->method() != nullptr) {
return constant_pool()->resolved_reference_from_indy(index);
return cp->resolved_reference_from_indy(index);
}
if (resolved_indy_entry_at(index)->resolution_failed()) {
@@ -590,9 +616,7 @@ oop ConstantPoolCache::set_dynamic_call(const CallInfo &call_info, int index) {
// resolution. Ignore our success and throw their exception.
guarantee(index >= 0, "Invalid indy index");
int encoded_index = ResolutionErrorTable::encode_indy_index(index);
JavaThread* THREAD = JavaThread::current(); // For exception macros.
constantPoolHandle cp(THREAD, constant_pool());
ConstantPool::throw_resolution_error(cp, encoded_index, THREAD);
ConstantPool::throw_resolution_error(cp, encoded_index, current);
return nullptr;
}
@@ -616,7 +640,6 @@ oop ConstantPoolCache::set_dynamic_call(const CallInfo &call_info, int index) {
if (has_appendix) {
const int appendix_index = resolved_indy_entry_at(index)->resolved_references_index();
objArrayOop resolved_references = constant_pool()->resolved_references();
assert(appendix_index >= 0 && appendix_index < resolved_references->length(), "oob");
assert(resolved_references->obj_at(appendix_index) == nullptr, "init just once");
resolved_references->obj_at_put(appendix_index, appendix());

View File

@@ -86,6 +86,7 @@
#include "runtime/orderAccess.hpp"
#include "runtime/os.inline.hpp"
#include "runtime/reflection.hpp"
#include "runtime/synchronizer.hpp"
#include "runtime/threads.hpp"
#include "services/classLoadingService.hpp"
#include "services/finalizerService.hpp"
@@ -497,9 +498,6 @@ Array<int>* InstanceKlass::create_new_default_vtable_indices(int len, TRAPS) {
return vtable_indices;
}
static Monitor* create_init_monitor(const char* name) {
return new Monitor(Mutex::safepoint, name);
}
InstanceKlass::InstanceKlass() {
assert(CDSConfig::is_dumping_static_archive() || CDSConfig::is_using_archive(), "only for CDS");
@@ -517,7 +515,6 @@ InstanceKlass::InstanceKlass(const ClassFileParser& parser, KlassKind kind, Refe
_nest_host_index(0),
_init_state(allocated),
_reference_type(reference_type),
_init_monitor(create_init_monitor("InstanceKlassInitMonitor_lock")),
_init_thread(nullptr)
{
set_vtable_length(parser.vtable_size());
@@ -745,6 +742,28 @@ objArrayOop InstanceKlass::signers() const {
return java_lang_Class::signers(java_mirror());
}
oop InstanceKlass::init_lock() const {
// return the init lock from the mirror
oop lock = java_lang_Class::init_lock(java_mirror());
// Prevent reordering with any access of initialization state
OrderAccess::loadload();
assert(lock != nullptr || !is_not_initialized(), // initialized or in_error state
"only fully initialized state can have a null lock");
return lock;
}
// Set the initialization lock to null so the object can be GC'ed. Any racing
// threads to get this lock will see a null lock and will not lock.
// That's okay because they all check for initialized state after getting
// the lock and return.
void InstanceKlass::fence_and_clear_init_lock() {
// make sure previous stores are all done, notably the init_state.
OrderAccess::storestore();
java_lang_Class::clear_init_lock(java_mirror());
assert(!is_not_initialized(), "class must be initialized now");
}
// See "The Virtual Machine Specification" section 2.16.5 for a detailed explanation of the class initialization
// process. The step comments refers to the procedure described in that section.
// Note: implementation moved to static method to expose the this pointer.
@@ -772,49 +791,6 @@ void InstanceKlass::link_class(TRAPS) {
}
}
void InstanceKlass::check_link_state_and_wait(JavaThread* current) {
MonitorLocker ml(current, _init_monitor);
bool debug_logging_enabled = log_is_enabled(Debug, class, init);
// Another thread is linking this class, wait.
while (is_being_linked() && !is_init_thread(current)) {
if (debug_logging_enabled) {
ResourceMark rm(current);
log_debug(class, init)("Thread \"%s\" waiting for linking of %s by thread \"%s\"",
current->name(), external_name(), init_thread_name());
}
ml.wait();
}
// This thread is recursively linking this class, continue
if (is_being_linked() && is_init_thread(current)) {
if (debug_logging_enabled) {
ResourceMark rm(current);
log_debug(class, init)("Thread \"%s\" recursively linking %s",
current->name(), external_name());
}
return;
}
// If this class wasn't linked already, set state to being_linked
if (!is_linked()) {
if (debug_logging_enabled) {
ResourceMark rm(current);
log_debug(class, init)("Thread \"%s\" linking %s",
current->name(), external_name());
}
set_init_state(being_linked);
set_init_thread(current);
} else {
if (debug_logging_enabled) {
ResourceMark rm(current);
log_debug(class, init)("Thread \"%s\" found %s already linked",
current->name(), external_name());
}
}
}
// Called to verify that a class can link during initialization, without
// throwing a VerifyError.
bool InstanceKlass::link_class_or_fail(TRAPS) {
@@ -893,8 +869,9 @@ bool InstanceKlass::link_class_impl(TRAPS) {
// verification & rewriting
{
LockLinkState init_lock(this, jt);
HandleMark hm(THREAD);
Handle h_init_lock(THREAD, init_lock());
ObjectLocker ol(h_init_lock, jt);
// rewritten will have been set if loader constraint error found
// on an earlier link attempt
// don't verify or rewrite if already rewritten
@@ -952,7 +929,21 @@ bool InstanceKlass::link_class_impl(TRAPS) {
// In case itable verification is ever added.
// itable().verify(tty, true);
#endif
set_initialization_state_and_notify(linked, THREAD);
if (UseVtableBasedCHA && Universe::is_fully_initialized()) {
DeoptimizationScope deopt_scope;
{
// Now mark all code that assumes the class is not linked.
// Set state under the Compile_lock also.
MutexLocker ml(THREAD, Compile_lock);
set_init_state(linked);
CodeCache::mark_dependents_on(&deopt_scope, this);
}
// Perform the deopt handshake outside Compile_lock.
deopt_scope.deoptimize_marked();
} else {
set_init_state(linked);
}
if (JvmtiExport::should_post_class_prepare()) {
JvmtiExport::post_class_prepare(THREAD, this);
}
@@ -1082,7 +1073,6 @@ void InstanceKlass::initialize_impl(TRAPS) {
DTRACE_CLASSINIT_PROBE(required, -1);
bool wait = false;
bool throw_error = false;
JavaThread* jt = THREAD;
@@ -1091,24 +1081,27 @@ void InstanceKlass::initialize_impl(TRAPS) {
// refer to the JVM book page 47 for description of steps
// Step 1
{
MonitorLocker ml(jt, _init_monitor);
Handle h_init_lock(THREAD, init_lock());
ObjectLocker ol(h_init_lock, jt);
// Step 2
while (is_being_initialized() && !is_init_thread(jt)) {
// If we were to use wait() instead of waitInterruptibly() then
// we might end up throwing IE from link/symbol resolution sites
// that aren't expected to throw. This would wreak havoc. See 6320309.
while (is_being_initialized() && !is_reentrant_initialization(jt)) {
if (debug_logging_enabled) {
ResourceMark rm(jt);
log_debug(class, init)("Thread \"%s\" waiting for initialization of %s by thread \"%s\"",
jt->name(), external_name(), init_thread_name());
}
wait = true;
jt->set_class_to_be_initialized(this);
ml.wait();
ol.wait_uninterruptibly(jt);
jt->set_class_to_be_initialized(nullptr);
}
// Step 3
if (is_being_initialized() && is_init_thread(jt)) {
if (is_being_initialized() && is_reentrant_initialization(jt)) {
if (debug_logging_enabled) {
ResourceMark rm(jt);
log_debug(class, init)("Thread \"%s\" recursively initializing %s",
@@ -1136,7 +1129,19 @@ void InstanceKlass::initialize_impl(TRAPS) {
log_debug(class, init)("Thread \"%s\" found %s is in error state",
jt->name(), external_name());
}
throw_error = true;
DTRACE_CLASSINIT_PROBE_WAIT(erroneous, -1, wait);
ResourceMark rm(THREAD);
Handle cause(THREAD, get_initialization_error(THREAD));
stringStream ss;
ss.print("Could not initialize class %s", external_name());
if (cause.is_null()) {
THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), ss.as_string());
} else {
THROW_MSG_CAUSE(vmSymbols::java_lang_NoClassDefFoundError(),
ss.as_string(), cause);
}
} else {
// Step 6
@@ -1150,22 +1155,6 @@ void InstanceKlass::initialize_impl(TRAPS) {
}
}
// Throw error outside lock
if (throw_error) {
DTRACE_CLASSINIT_PROBE_WAIT(erroneous, -1, wait);
ResourceMark rm(THREAD);
Handle cause(THREAD, get_initialization_error(THREAD));
stringStream ss;
ss.print("Could not initialize class %s", external_name());
if (cause.is_null()) {
THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), ss.as_string());
} else {
THROW_MSG_CAUSE(vmSymbols::java_lang_NoClassDefFoundError(),
ss.as_string(), cause);
}
}
// Step 7
// Next, if C is a class rather than an interface, initialize it's super class and super
// interfaces.
@@ -1223,7 +1212,7 @@ void InstanceKlass::initialize_impl(TRAPS) {
// Step 9
if (!HAS_PENDING_EXCEPTION) {
set_initialization_state_and_notify(fully_initialized, THREAD);
set_initialization_state_and_notify(fully_initialized, CHECK);
debug_only(vtable().verify(tty, true);)
}
else {
@@ -1256,43 +1245,26 @@ void InstanceKlass::initialize_impl(TRAPS) {
}
void InstanceKlass::set_initialization_state_and_notify(ClassState state, JavaThread* current) {
MonitorLocker ml(current, _init_monitor);
if (state == linked && UseVtableBasedCHA && Universe::is_fully_initialized()) {
DeoptimizationScope deopt_scope;
{
// Now mark all code that assumes the class is not linked.
// Set state under the Compile_lock also.
MutexLocker ml(current, Compile_lock);
set_init_thread(nullptr); // reset _init_thread before changing _init_state
set_init_state(state);
CodeCache::mark_dependents_on(&deopt_scope, this);
}
// Perform the deopt handshake outside Compile_lock.
deopt_scope.deoptimize_marked();
void InstanceKlass::set_initialization_state_and_notify(ClassState state, TRAPS) {
Handle h_init_lock(THREAD, init_lock());
if (h_init_lock() != nullptr) {
ObjectLocker ol(h_init_lock, THREAD);
set_init_thread(nullptr); // reset _init_thread before changing _init_state
set_init_state(state);
fence_and_clear_init_lock();
ol.notify_all(CHECK);
} else {
assert(h_init_lock() != nullptr, "The initialization state should never be set twice");
set_init_thread(nullptr); // reset _init_thread before changing _init_state
set_init_state(state);
}
ml.notify_all();
}
// Update hierarchy. This is done before the new klass has been added to the SystemDictionary. The Compile_lock
// is grabbed, to ensure that the compiler is not using the class hierarchy.
void InstanceKlass::add_to_hierarchy(JavaThread* current) {
void InstanceKlass::add_to_hierarchy_impl(JavaThread* current) {
assert(!SafepointSynchronize::is_at_safepoint(), "must NOT be at safepoint");
// In case we are not using CHA based vtables we need to make sure the loaded
// deopt is completed before anyone links this class.
// Linking is done with _init_monitor held, by loading and deopting with it
// held we make sure the deopt is completed before linking.
if (!UseVtableBasedCHA) {
init_monitor()->lock();
}
DeoptimizationScope deopt_scope;
{
MutexLocker ml(current, Compile_lock);
@@ -1314,12 +1286,26 @@ void InstanceKlass::add_to_hierarchy(JavaThread* current) {
}
// Perform the deopt handshake outside Compile_lock.
deopt_scope.deoptimize_marked();
}
if (!UseVtableBasedCHA) {
init_monitor()->unlock();
void InstanceKlass::add_to_hierarchy(JavaThread* current) {
if (UseVtableBasedCHA || !Universe::is_fully_initialized()) {
add_to_hierarchy_impl(current);
} else {
// In case we are not using CHA based vtables we need to make sure the loaded
// deopt is completed before anyone links this class.
// Linking is done with init_lock held, by loading and deopting with it
// held we make sure the deopt is completed before linking.
Handle h_init_lock(current, init_lock());
ObjectLocker ol(h_init_lock, current);
add_to_hierarchy_impl(current);
// This doesn't need a notify because the wait is only on the class initialization path.
}
}
InstanceKlass* InstanceKlass::implementor() const {
InstanceKlass* volatile* ik = adr_implementor();
if (ik == nullptr) {
@@ -2586,7 +2572,6 @@ void InstanceKlass::remove_unshareable_info() {
_nest_host = nullptr;
init_shared_package_entry();
_dep_context_last_cleaned = 0;
_init_monitor = nullptr;
remove_unshareable_flags();
}
@@ -2690,9 +2675,6 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl
if (DiagnoseSyncOnValueBasedClasses && has_value_based_class_annotation()) {
set_is_value_based();
}
// restore the monitor
_init_monitor = create_init_monitor("InstanceKlassInitMonitorRestored_lock");
}
// Check if a class or any of its supertypes has a version older than 50.
@@ -2788,9 +2770,6 @@ void InstanceKlass::release_C_heap_structures(bool release_sub_metadata) {
methods_do(method_release_C_heap_structures);
}
// Destroy the init_monitor
delete _init_monitor;
// Deallocate oop map cache
if (_oop_map_cache != nullptr) {
delete _oop_map_cache;
@@ -3482,7 +3461,7 @@ nmethod* InstanceKlass::lookup_osr_nmethod(const Method* m, int bci, int comp_le
#define BULLET " - "
static const char* state_names[] = {
"allocated", "loaded", "being_linked", "linked", "being_initialized", "fully_initialized", "initialization_error"
"allocated", "loaded", "linked", "being_initialized", "fully_initialized", "initialization_error"
};
static void print_vtable(intptr_t* start, int len, outputStream* st) {
@@ -4132,17 +4111,13 @@ void JNIid::verify(Klass* holder) {
}
void InstanceKlass::set_init_state(ClassState state) {
if (state > loaded) {
assert_lock_strong(_init_monitor);
}
#ifdef ASSERT
bool good_state = is_shared() ? (_init_state <= state)
: (_init_state < state);
bool link_failed = _init_state == being_linked && state == loaded;
assert(good_state || state == allocated || link_failed, "illegal state transition");
assert(good_state || state == allocated, "illegal state transition");
#endif
assert(_init_thread == nullptr, "should be cleared before state change");
Atomic::store(&_init_state, state);
_init_state = state;
}
#if INCLUDE_JVMTI

View File

@@ -152,7 +152,6 @@ class InstanceKlass: public Klass {
enum ClassState : u1 {
allocated, // allocated (but not yet linked)
loaded, // loaded and inserted in class hierarchy (but not linked yet)
being_linked, // currently running verifier and rewriter
linked, // successfully linked/verified (but not initialized yet)
being_initialized, // currently running class initializer
fully_initialized, // initialized (successful final state)
@@ -226,14 +225,20 @@ class InstanceKlass: public Klass {
volatile u2 _idnum_allocated_count; // JNI/JVMTI: increments with the addition of methods, old ids don't change
// _is_marked_dependent can be set concurrently, thus cannot be part of the
// _misc_flags.
bool _is_marked_dependent; // used for marking during flushing and deoptimization
// Class states are defined as ClassState (see above).
// Place the _init_state here to utilize the unused 2-byte after
// _idnum_allocated_count.
volatile ClassState _init_state; // state of class
u1 _reference_type; // reference type
u1 _reference_type; // reference type
// State is set either at parse time or while executing, atomically to not disturb other state
InstanceKlassFlags _misc_flags;
Monitor* _init_monitor; // mutual exclusion to _init_state and _init_thread.
JavaThread* volatile _init_thread; // Pointer to current thread doing initialization (to handle recursive initialization)
OopMapCache* volatile _oop_map_cache; // OopMapCache for all methods in the klass (allocated lazily)
@@ -497,41 +502,23 @@ public:
TRAPS);
JavaThread* init_thread() { return Atomic::load(&_init_thread); }
// We can safely access the name as long as we hold the _init_monitor.
const char* init_thread_name() {
assert(_init_monitor->owned_by_self(), "Must hold _init_monitor here");
return init_thread()->name_raw();
}
public:
// initialization state
bool is_loaded() const { return init_state() >= loaded; }
bool is_linked() const { return init_state() >= linked; }
bool is_being_linked() const { return init_state() == being_linked; }
bool is_initialized() const { return init_state() == fully_initialized; }
bool is_not_initialized() const { return init_state() < being_initialized; }
bool is_being_initialized() const { return init_state() == being_initialized; }
bool is_in_error_state() const { return init_state() == initialization_error; }
bool is_init_thread(JavaThread *thread) { return thread == init_thread(); }
ClassState init_state() const { return Atomic::load(&_init_state); }
bool is_loaded() const { return _init_state >= loaded; }
bool is_linked() const { return _init_state >= linked; }
bool is_initialized() const { return _init_state == fully_initialized; }
bool is_not_initialized() const { return _init_state < being_initialized; }
bool is_being_initialized() const { return _init_state == being_initialized; }
bool is_in_error_state() const { return _init_state == initialization_error; }
bool is_reentrant_initialization(Thread *thread) { return thread == _init_thread; }
ClassState init_state() const { return _init_state; }
const char* init_state_name() const;
bool is_rewritten() const { return _misc_flags.rewritten(); }
class LockLinkState : public StackObj {
InstanceKlass* _ik;
JavaThread* _current;
public:
LockLinkState(InstanceKlass* ik, JavaThread* current) : _ik(ik), _current(current) {
ik->check_link_state_and_wait(current);
}
~LockLinkState() {
if (!_ik->is_linked()) {
// Reset to loaded if linking failed.
_ik->set_initialization_state_and_notify(loaded, _current);
}
}
};
// is this a sealed class
bool is_sealed() const;
@@ -829,7 +816,7 @@ public:
// initialization
void call_class_initializer(TRAPS);
void set_initialization_state_and_notify(ClassState state, JavaThread* current);
void set_initialization_state_and_notify(ClassState state, TRAPS);
// OopMapCache support
OopMapCache* oop_map_cache() { return _oop_map_cache; }
@@ -841,6 +828,10 @@ public:
void set_jni_ids(JNIid* ids) { _jni_ids = ids; }
JNIid* jni_id_for(int offset);
private:
void add_to_hierarchy_impl(JavaThread* current);
public:
// maintenance of deoptimization dependencies
inline DependencyContext dependencies();
void mark_dependent_nmethods(DeoptimizationScope* deopt_scope, KlassDepChange& changes);
@@ -1055,7 +1046,7 @@ public:
public:
u2 idnum_allocated_count() const { return _idnum_allocated_count; }
private:
private:
// initialization state
void set_init_state(ClassState state);
void set_rewritten() { _misc_flags.set_rewritten(true); }
@@ -1072,6 +1063,12 @@ public:
jmethodID update_jmethod_id(jmethodID* jmeths, Method* method, int idnum);
public:
// Lock for (1) initialization; (2) access to the ConstantPool of this class.
// Must be one per class and it has to be a VM internal object so java code
// cannot lock it (like the mirror).
// It has to be an object not a Mutex because it's held through java calls.
oop init_lock() const;
// Returns the array class for the n'th dimension
virtual ArrayKlass* array_klass(int n, TRAPS);
virtual ArrayKlass* array_klass_or_null(int n);
@@ -1081,10 +1078,9 @@ public:
virtual ArrayKlass* array_klass_or_null();
static void clean_initialization_error_table();
Monitor* init_monitor() const { return _init_monitor; }
private:
void check_link_state_and_wait(JavaThread* current);
void fence_and_clear_init_lock();
bool link_class_impl (TRAPS);
bool verify_code (TRAPS);
void initialize_impl (TRAPS);

View File

@@ -54,6 +54,7 @@ uint32_t Symbol::pack_hash_and_refcount(short hash, int refcount) {
}
Symbol::Symbol(const u1* name, int length, int refcount) {
assert(length <= max_length(), "SymbolTable should have caught this!");
_hash_and_refcount = pack_hash_and_refcount((short)os::random(), refcount);
_length = (u2)length;
// _body[0..1] are allocated in the header just by coincidence in the current

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@@ -130,6 +130,7 @@ class Symbol : public MetaspaceObj {
return (int)heap_word_size(byte_size(length));
}
// Constructor is private for use only by SymbolTable.
Symbol(const u1* name, int length, int refcount);
static short extract_hash(uint32_t value) { return (short)(value >> 16); }

View File

@@ -1950,6 +1950,22 @@ bool AbstractLockNode::find_unlocks_for_region(const RegionNode* region, LockNod
}
// Check that all locks/unlocks associated with object come from balanced regions.
bool AbstractLockNode::is_balanced() {
Node* obj = obj_node();
for (uint j = 0; j < obj->outcnt(); j++) {
Node* n = obj->raw_out(j);
if (n->is_AbstractLock() &&
n->as_AbstractLock()->obj_node()->eqv_uncast(obj)) {
BoxLockNode* n_box = n->as_AbstractLock()->box_node()->as_BoxLock();
if (n_box->is_unbalanced()) {
return false;
}
}
}
return true;
}
const char* AbstractLockNode::_kind_names[] = {"Regular", "NonEscObj", "Coarsened", "Nested"};
const char * AbstractLockNode::kind_as_string() const {
@@ -2056,6 +2072,8 @@ Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
int unlocks = 0;
if (Verbose) {
tty->print_cr("=== Locks coarsening ===");
tty->print("Obj: ");
obj_node()->dump();
}
for (int i = 0; i < lock_ops.length(); i++) {
AbstractLockNode* lock = lock_ops.at(i);
@@ -2064,6 +2082,8 @@ Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
else
unlocks++;
if (Verbose) {
tty->print("Box %d: ", i);
box_node()->dump();
tty->print(" %d: ", i);
lock->dump();
}

View File

@@ -1154,6 +1154,10 @@ public:
void set_coarsened() { _kind = Coarsened; set_eliminated_lock_counter(); }
void set_nested() { _kind = Nested; set_eliminated_lock_counter(); }
// Check that all locks/unlocks associated with object come from balanced regions.
// They can become unbalanced after coarsening optimization or on OSR entry.
bool is_balanced();
// locking does not modify its arguments
virtual bool may_modify(const TypeOopPtr* t_oop, PhaseValues* phase){ return false; }

View File

@@ -574,18 +574,23 @@ bool ConnectionGraph::can_reduce_check_users(Node* n, uint nesting) const {
// CmpP/N used by the If controlling the cast.
if (use->in(0)->is_IfTrue() || use->in(0)->is_IfFalse()) {
Node* iff = use->in(0)->in(0);
if (iff->Opcode() == Op_If && iff->in(1)->is_Bool() && iff->in(1)->in(1)->is_Cmp()) {
// We may have Opaque4 node between If and Bool nodes.
// Bail out in such case - we need to preserve Opaque4 for correct
// processing predicates after loop opts.
bool can_reduce = (iff->Opcode() == Op_If) && iff->in(1)->is_Bool() && iff->in(1)->in(1)->is_Cmp();
if (can_reduce) {
Node* iff_cmp = iff->in(1)->in(1);
int opc = iff_cmp->Opcode();
if ((opc == Op_CmpP || opc == Op_CmpN) && !can_reduce_cmp(n, iff_cmp)) {
can_reduce = (opc == Op_CmpP || opc == Op_CmpN) && can_reduce_cmp(n, iff_cmp);
}
if (!can_reduce) {
#ifndef PRODUCT
if (TraceReduceAllocationMerges) {
tty->print_cr("Can NOT reduce Phi %d on invocation %d. CastPP %d doesn't have simple control.", n->_idx, _invocation, use->_idx);
n->dump(5);
}
#endif
return false;
if (TraceReduceAllocationMerges) {
tty->print_cr("Can NOT reduce Phi %d on invocation %d. CastPP %d doesn't have simple control.", n->_idx, _invocation, use->_idx);
n->dump(5);
}
#endif
return false;
}
}
}
@@ -651,7 +656,12 @@ Node* ConnectionGraph::specialize_cmp(Node* base, Node* curr_ctrl) {
if (curr_ctrl == nullptr || curr_ctrl->is_Region()) {
con = _igvn->zerocon(t->basic_type());
} else {
Node* curr_cmp = curr_ctrl->in(0)->in(1)->in(1); // true/false -> if -> bool -> cmp
// can_reduce_check_users() verified graph: true/false -> if -> bool -> cmp
assert(curr_ctrl->in(0)->Opcode() == Op_If, "unexpected node %s", curr_ctrl->in(0)->Name());
Node* bol = curr_ctrl->in(0)->in(1);
assert(bol->is_Bool(), "unexpected node %s", bol->Name());
Node* curr_cmp = bol->in(1);
assert(curr_cmp->Opcode() == Op_CmpP || curr_cmp->Opcode() == Op_CmpN, "unexpected node %s", curr_cmp->Name());
con = curr_cmp->in(1)->is_Con() ? curr_cmp->in(1) : curr_cmp->in(2);
}
@@ -3501,12 +3511,11 @@ bool ConnectionGraph::not_global_escape(Node *n) {
// and locked code region (identified by BoxLockNode) is balanced:
// all compiled code paths have corresponding Lock/Unlock pairs.
bool ConnectionGraph::can_eliminate_lock(AbstractLockNode* alock) {
BoxLockNode* box = alock->box_node()->as_BoxLock();
if (!box->is_unbalanced() && not_global_escape(alock->obj_node())) {
if (alock->is_balanced() && not_global_escape(alock->obj_node())) {
if (EliminateNestedLocks) {
// We can mark whole locking region as Local only when only
// one object is used for locking.
box->set_local();
alock->box_node()->as_BoxLock()->set_local();
}
return true;
}

View File

@@ -755,6 +755,7 @@ bool IfNode::cmpi_folds(PhaseIterGVN* igvn, bool fold_ne) {
bool IfNode::is_ctrl_folds(Node* ctrl, PhaseIterGVN* igvn) {
return ctrl != nullptr &&
ctrl->is_Proj() &&
ctrl->outcnt() == 1 && // No side-effects
ctrl->in(0) != nullptr &&
ctrl->in(0)->Opcode() == Op_If &&
ctrl->in(0)->outcnt() == 2 &&
@@ -1328,7 +1329,7 @@ Node* IfNode::fold_compares(PhaseIterGVN* igvn) {
if (cmpi_folds(igvn)) {
Node* ctrl = in(0);
if (is_ctrl_folds(ctrl, igvn) && ctrl->outcnt() == 1) {
if (is_ctrl_folds(ctrl, igvn)) {
// A integer comparison immediately dominated by another integer
// comparison
ProjNode* success = nullptr;

View File

@@ -5463,42 +5463,72 @@ void LibraryCallKit::create_new_uncommon_trap(CallStaticJavaNode* uncommon_trap_
uncommon_trap_call->set_req(0, top()); // not used anymore, kill it
}
// Common checks for array sorting intrinsics arguments.
// Returns `true` if checks passed.
bool LibraryCallKit::check_array_sort_arguments(Node* elementType, Node* obj, BasicType& bt) {
// check address of the class
if (elementType == nullptr || elementType->is_top()) {
return false; // dead path
}
const TypeInstPtr* elem_klass = gvn().type(elementType)->isa_instptr();
if (elem_klass == nullptr) {
return false; // dead path
}
// java_mirror_type() returns non-null for compile-time Class constants only
ciType* elem_type = elem_klass->java_mirror_type();
if (elem_type == nullptr) {
return false;
}
bt = elem_type->basic_type();
// Disable the intrinsic if the CPU does not support SIMD sort
if (!Matcher::supports_simd_sort(bt)) {
return false;
}
// check address of the array
if (obj == nullptr || obj->is_top()) {
return false; // dead path
}
const TypeAryPtr* obj_t = _gvn.type(obj)->isa_aryptr();
if (obj_t == nullptr || obj_t->elem() == Type::BOTTOM) {
return false; // failed input validation
}
return true;
}
//------------------------------inline_array_partition-----------------------
bool LibraryCallKit::inline_array_partition() {
address stubAddr = StubRoutines::select_array_partition_function();
if (stubAddr == nullptr) {
return false; // Intrinsic's stub is not implemented on this platform
}
assert(callee()->signature()->size() == 9, "arrayPartition has 8 parameters (one long)");
Node* elementType = null_check(argument(0));
// no receiver because it is a static method
Node* elementType = argument(0);
Node* obj = argument(1);
Node* offset = argument(2);
Node* offset = argument(2); // long
Node* fromIndex = argument(4);
Node* toIndex = argument(5);
Node* indexPivot1 = argument(6);
Node* indexPivot2 = argument(7);
// PartitionOperation: argument(8) is ignored
Node* pivotIndices = nullptr;
BasicType bt = T_ILLEGAL;
if (!check_array_sort_arguments(elementType, obj, bt)) {
return false;
}
null_check(obj);
// If obj is dead, only null-path is taken.
if (stopped()) {
return true;
}
// Set the original stack and the reexecute bit for the interpreter to reexecute
// the bytecode that invokes DualPivotQuicksort.partition() if deoptimization happens.
{ PreserveReexecuteState preexecs(this);
jvms()->set_should_reexecute(true);
const TypeInstPtr* elem_klass = gvn().type(elementType)->isa_instptr();
ciType* elem_type = elem_klass->const_oop()->as_instance()->java_mirror_type();
BasicType bt = elem_type->basic_type();
// Disable the intrinsic if the CPU does not support SIMD sort
if (!Matcher::supports_simd_sort(bt)) {
return false;
}
address stubAddr = nullptr;
stubAddr = StubRoutines::select_array_partition_function();
// stub not loaded
if (stubAddr == nullptr) {
return false;
}
// get the address of the array
const TypeAryPtr* obj_t = _gvn.type(obj)->isa_aryptr();
if (obj_t == nullptr || obj_t->elem() == Type::BOTTOM ) {
return false; // failed input validation
}
Node* obj_adr = make_unsafe_address(obj, offset);
// create the pivotIndices array of type int and size = 2
@@ -5531,31 +5561,29 @@ bool LibraryCallKit::inline_array_partition() {
//------------------------------inline_array_sort-----------------------
bool LibraryCallKit::inline_array_sort() {
address stubAddr = StubRoutines::select_arraysort_function();
if (stubAddr == nullptr) {
return false; // Intrinsic's stub is not implemented on this platform
}
assert(callee()->signature()->size() == 7, "arraySort has 6 parameters (one long)");
Node* elementType = null_check(argument(0));
// no receiver because it is a static method
Node* elementType = argument(0);
Node* obj = argument(1);
Node* offset = argument(2);
Node* offset = argument(2); // long
Node* fromIndex = argument(4);
Node* toIndex = argument(5);
// SortOperation: argument(6) is ignored
const TypeInstPtr* elem_klass = gvn().type(elementType)->isa_instptr();
ciType* elem_type = elem_klass->const_oop()->as_instance()->java_mirror_type();
BasicType bt = elem_type->basic_type();
// Disable the intrinsic if the CPU does not support SIMD sort
if (!Matcher::supports_simd_sort(bt)) {
BasicType bt = T_ILLEGAL;
if (!check_array_sort_arguments(elementType, obj, bt)) {
return false;
}
address stubAddr = nullptr;
stubAddr = StubRoutines::select_arraysort_function();
//stub not loaded
if (stubAddr == nullptr) {
return false;
}
// get address of the array
const TypeAryPtr* obj_t = _gvn.type(obj)->isa_aryptr();
if (obj_t == nullptr || obj_t->elem() == Type::BOTTOM ) {
return false; // failed input validation
null_check(obj);
// If obj is dead, only null-path is taken.
if (stopped()) {
return true;
}
Node* obj_adr = make_unsafe_address(obj, offset);
@@ -7554,8 +7582,6 @@ bool LibraryCallKit::inline_intpoly_montgomeryMult_P256() {
OptoRuntime::intpoly_montgomeryMult_P256_Type(),
stubAddr, stubName, TypePtr::BOTTOM,
a_start, b_start, r_start);
Node* result = _gvn.transform(new ProjNode(call, TypeFunc::Parms));
set_result(result);
return true;
}

View File

@@ -279,6 +279,7 @@ class LibraryCallKit : public GraphKit {
JVMState* arraycopy_restore_alloc_state(AllocateArrayNode* alloc, int& saved_reexecute_sp);
void arraycopy_move_allocation_here(AllocateArrayNode* alloc, Node* dest, JVMState* saved_jvms_before_guards, int saved_reexecute_sp,
uint new_idx);
bool check_array_sort_arguments(Node* elementType, Node* obj, BasicType& bt);
bool inline_array_sort();
bool inline_array_partition();
typedef enum { LS_get_add, LS_get_set, LS_cmp_swap, LS_cmp_swap_weak, LS_cmp_exchange } LoadStoreKind;

View File

@@ -46,7 +46,7 @@ private:
Eliminated // All lock/unlock in region were eliminated
} _kind;
#ifdef ASSERT
#ifndef PRODUCT
const char* _kind_name[6] = {
"Regular",
"Local",
@@ -124,7 +124,9 @@ public:
#ifndef PRODUCT
virtual void format( PhaseRegAlloc *, outputStream *st ) const;
virtual void dump_spec(outputStream *st) const { st->print(" Lock %d",_slot); }
virtual void dump_spec(outputStream *st) const {
st->print(" Lock slot: %d, Kind: %s", _slot, _kind_name[(int)_kind]);
}
#endif
};

View File

@@ -795,18 +795,25 @@ Node *PhaseIdealLoop::conditional_move( Node *region ) {
// Avoid duplicated float compare.
if (phis > 1 && (cmp_op == Op_CmpF || cmp_op == Op_CmpD)) return nullptr;
// Ignore cost if CMOVE can be moved outside the loop.
if (used_inside_loop && cost >= ConditionalMoveLimit) {
return nullptr;
float infrequent_prob = PROB_UNLIKELY_MAG(3);
// Ignore cost and blocks frequency if CMOVE can be moved outside the loop.
if (used_inside_loop) {
if (cost >= ConditionalMoveLimit) return nullptr; // Too much goo
// BlockLayoutByFrequency optimization moves infrequent branch
// from hot path. No point in CMOV'ing in such case (110 is used
// instead of 100 to take into account not exactness of float value).
if (BlockLayoutByFrequency) {
infrequent_prob = MAX2(infrequent_prob, (float)BlockLayoutMinDiamondPercentage/110.0f);
}
}
// Check for highly predictable branch. No point in CMOV'ing if
// we are going to predict accurately all the time.
constexpr float infrequent_prob = PROB_UNLIKELY_MAG(2);
if (C->use_cmove() && (cmp_op == Op_CmpF || cmp_op == Op_CmpD)) {
//keep going
} else if (iff->_prob < infrequent_prob || iff->_prob > (1.0f - infrequent_prob)) {
} else if (iff->_prob < infrequent_prob ||
iff->_prob > (1.0f - infrequent_prob))
return nullptr;
}
// --------------
// Now replace all Phis with CMOV's
@@ -2987,52 +2994,101 @@ RegionNode* PhaseIdealLoop::insert_region_before_proj(ProjNode* proj) {
return reg;
}
//------------------------------ insert_cmpi_loop_exit -------------------------------------
// Clone a signed compare loop exit from an unsigned compare and
// insert it before the unsigned cmp on the stay-in-loop path.
// All new nodes inserted in the dominator tree between the original
// if and it's projections. The original if test is replaced with
// a constant to force the stay-in-loop path.
// Idea
// ----
// Partial Peeling tries to rotate the loop in such a way that it can later be turned into a counted loop. Counted loops
// require a signed loop exit test. When calling this method, we've only found a suitable unsigned test to partial peel
// with. Therefore, we try to split off a signed loop exit test from the unsigned test such that it can be used as new
// loop exit while keeping the unsigned test unchanged and preserving the same behavior as if we've used the unsigned
// test alone instead:
//
// This is done to make sure that the original if and it's projections
// still dominate the same set of control nodes, that the ctrl() relation
// from data nodes to them is preserved, and that their loop nesting is
// preserved.
// Before Partial Peeling:
// Loop:
// <peeled section>
// Split off signed loop exit test
// <-- CUT HERE -->
// Unchanged unsigned loop exit test
// <rest of unpeeled section>
// goto Loop
//
// before
// if(i <u limit) unsigned compare loop exit
// After Partial Peeling:
// <cloned peeled section>
// Cloned split off signed loop exit test
// Loop:
// Unchanged unsigned loop exit test
// <rest of unpeeled section>
// <peeled section>
// Split off signed loop exit test
// goto Loop
//
// Details
// -------
// Before:
// if (i <u limit) Unsigned loop exit condition
// / |
// v v
// exit-proj stay-in-loop-proj
//
// after
// if(stay-in-loop-const) original if
// / |
// / v
// / if(i < limit) new signed test
// Split off a signed loop exit test (i.e. with CmpI) from an unsigned loop exit test (i.e. with CmpU) and insert it
// before the CmpU on the stay-in-loop path and keep both tests:
//
// if (i <u limit) Signed loop exit test
// / |
// / if (i <u limit) Unsigned loop exit test
// / / |
// / / v
// / / if(i <u limit) new cloned unsigned test
// / / / |
// v v v |
// region |
// | |
// dum-if |
// / | |
// ether | |
// v v
// v v v
// exit-region stay-in-loop-proj
//
// Implementation
// --------------
// We need to make sure that the new signed loop exit test is properly inserted into the graph such that the unsigned
// loop exit test still dominates the same set of control nodes, the ctrl() relation from data nodes to both loop
// exit tests is preserved, and their loop nesting is correct.
//
// To achieve that, we clone the unsigned loop exit test completely (leave it unchanged), insert the signed loop exit
// test above it and kill the original unsigned loop exit test by setting it's condition to a constant
// (i.e. stay-in-loop-const in graph below) such that IGVN can fold it later:
//
// if (stay-in-loop-const) Killed original unsigned loop exit test
// / |
// / v
// / if (i < limit) Split off signed loop exit test
// / / |
// / / v
// / / if (i <u limit) Cloned unsigned loop exit test
// / / / |
// v v v |
// exit-region |
// | |
// dummy-if |
// / | |
// dead | |
// v v
// exit-proj stay-in-loop-proj
//
IfNode* PhaseIdealLoop::insert_cmpi_loop_exit(IfNode* if_cmpu, IdealLoopTree *loop) {
// Note: The dummy-if is inserted to create a region to merge the loop exits between the original to be killed unsigned
// loop exit test and its exit projection while keeping the exit projection (also see insert_region_before_proj()).
//
// Requirements
// ------------
// Note that we can only split off a signed loop exit test from the unsigned loop exit test when the behavior is exactly
// the same as before with only a single unsigned test. This is only possible if certain requirements are met.
// Otherwise, we need to bail out (see comments in the code below).
IfNode* PhaseIdealLoop::insert_cmpi_loop_exit(IfNode* if_cmpu, IdealLoopTree* loop) {
const bool Signed = true;
const bool Unsigned = false;
BoolNode* bol = if_cmpu->in(1)->as_Bool();
if (bol->_test._test != BoolTest::lt) return nullptr;
if (bol->_test._test != BoolTest::lt) {
return nullptr;
}
CmpNode* cmpu = bol->in(1)->as_Cmp();
if (cmpu->Opcode() != Op_CmpU) return nullptr;
assert(cmpu->Opcode() == Op_CmpU, "must be unsigned comparison");
int stride = stride_of_possible_iv(if_cmpu);
if (stride == 0) return nullptr;
if (stride == 0) {
return nullptr;
}
Node* lp_proj = stay_in_loop(if_cmpu, loop);
guarantee(lp_proj != nullptr, "null loop node");
@@ -3044,14 +3100,93 @@ IfNode* PhaseIdealLoop::insert_cmpi_loop_exit(IfNode* if_cmpu, IdealLoopTree *lo
// We therefore can't add a single exit condition.
return nullptr;
}
// The loop exit condition is !(i <u limit) ==> (i < 0 || i >= limit).
// Split out the exit condition (i < 0) for stride < 0 or (i >= limit) for stride > 0.
Node* limit = nullptr;
// The unsigned loop exit condition is
// !(i <u limit)
// = i >=u limit
//
// First, we note that for any x for which
// 0 <= x <= INT_MAX
// we can convert x to an unsigned int and still get the same guarantee:
// 0 <= (uint) x <= INT_MAX = (uint) INT_MAX
// 0 <=u (uint) x <=u INT_MAX = (uint) INT_MAX (LEMMA)
//
// With that in mind, if
// limit >= 0 (COND)
// then the unsigned loop exit condition
// i >=u limit (ULE)
// is equivalent to
// i < 0 || i >= limit (SLE-full)
// because either i is negative and therefore always greater than MAX_INT when converting to unsigned
// (uint) i >=u MAX_INT >= limit >= 0
// or otherwise
// i >= limit >= 0
// holds due to (LEMMA).
//
// For completeness, a counterexample with limit < 0:
// Assume i = -3 and limit = -2:
// i < 0
// -2 < 0
// is true and thus also "i < 0 || i >= limit". But
// i >=u limit
// -3 >=u -2
// is false.
Node* limit = cmpu->in(2);
const TypeInt* type_limit = _igvn.type(limit)->is_int();
if (type_limit->_lo < 0) {
return nullptr;
}
// We prove below that we can extract a single signed loop exit condition from (SLE-full), depending on the stride:
// stride < 0:
// i < 0 (SLE = SLE-negative)
// stride > 0:
// i >= limit (SLE = SLE-positive)
// such that we have the following graph before Partial Peeling with stride > 0 (similar for stride < 0):
//
// Loop:
// <peeled section>
// i >= limit (SLE-positive)
// <-- CUT HERE -->
// i >=u limit (ULE)
// <rest of unpeeled section>
// goto Loop
//
// We exit the loop if:
// (SLE) is true OR (ULE) is true
// However, if (SLE) is true then (ULE) also needs to be true to ensure the exact same behavior. Otherwise, we wrongly
// exit a loop that should not have been exited if we did not apply Partial Peeling. More formally, we need to ensure:
// (SLE) IMPLIES (ULE)
// This indeed holds when (COND) is given:
// - stride > 0:
// i >= limit // (SLE = SLE-positive)
// i >= limit >= 0 // (COND)
// i >=u limit >= 0 // (LEMMA)
// which is the unsigned loop exit condition (ULE).
// - stride < 0:
// i < 0 // (SLE = SLE-negative)
// (uint) i >u MAX_INT // (NEG) all negative values are greater than MAX_INT when converted to unsigned
// MAX_INT >= limit >= 0 // (COND)
// MAX_INT >=u limit >= 0 // (LEMMA)
// and thus from (NEG) and (LEMMA):
// i >=u limit
// which is the unsigned loop exit condition (ULE).
//
//
// After Partial Peeling, we have the following structure for stride > 0 (similar for stride < 0):
// <cloned peeled section>
// i >= limit (SLE-positive)
// Loop:
// i >=u limit (ULE)
// <rest of unpeeled section>
// <peeled section>
// i >= limit (SLE-positive)
// goto Loop
Node* rhs_cmpi;
if (stride > 0) {
limit = cmpu->in(2);
rhs_cmpi = limit; // For i >= limit
} else {
limit = _igvn.makecon(TypeInt::ZERO);
set_ctrl(limit, C->root());
rhs_cmpi = _igvn.makecon(TypeInt::ZERO); // For i < 0
set_ctrl(rhs_cmpi, C->root());
}
// Create a new region on the exit path
RegionNode* reg = insert_region_before_proj(lp_exit);
@@ -3059,7 +3194,7 @@ IfNode* PhaseIdealLoop::insert_cmpi_loop_exit(IfNode* if_cmpu, IdealLoopTree *lo
// Clone the if-cmpu-true-false using a signed compare
BoolTest::mask rel_i = stride > 0 ? bol->_test._test : BoolTest::ge;
ProjNode* cmpi_exit = insert_if_before_proj(cmpu->in(1), Signed, rel_i, limit, lp_continue);
ProjNode* cmpi_exit = insert_if_before_proj(cmpu->in(1), Signed, rel_i, rhs_cmpi, lp_continue);
reg->add_req(cmpi_exit);
// Clone the if-cmpu-true-false

View File

@@ -870,6 +870,10 @@ public:
assert(verify_jvms(jvms), "jvms must match");
return in(_jvmadj + jvms->monitor_box_offset(idx));
}
Node* scalarized_obj(const JVMState* jvms, uint idx) const {
assert(verify_jvms(jvms), "jvms must match");
return in(_jvmadj + jvms->scloff() + idx);
}
void set_local(const JVMState* jvms, uint idx, Node *c) {
assert(verify_jvms(jvms), "jvms must match");
set_req(_jvmadj + jvms->locoff() + idx, c);

View File

@@ -2045,7 +2045,7 @@ void PhaseMacroExpand::mark_eliminated_box(Node* box, Node* obj) {
//-----------------------mark_eliminated_locking_nodes-----------------------
void PhaseMacroExpand::mark_eliminated_locking_nodes(AbstractLockNode *alock) {
if (alock->box_node()->as_BoxLock()->is_unbalanced()) {
if (!alock->is_balanced()) {
return; // Can't do any more elimination for this locking region
}
if (EliminateNestedLocks) {

View File

@@ -2984,6 +2984,9 @@ StoreNode* MergePrimitiveArrayStores::run() {
type2aelembytes(bt) != _store->memory_size()) {
return nullptr;
}
if (_store->is_unsafe_access()) {
return nullptr;
}
// The _store must be the "last" store in a chain. If we find a use we could merge with
// then that use or a store further down is the "last" store.
@@ -3017,11 +3020,13 @@ bool MergePrimitiveArrayStores::is_compatible_store(const StoreNode* other_store
int opc = _store->Opcode();
assert(opc == Op_StoreB || opc == Op_StoreC || opc == Op_StoreI, "precondition");
assert(_store->adr_type()->isa_aryptr() != nullptr, "must be array store");
assert(!_store->is_unsafe_access(), "no unsafe accesses");
if (other_store == nullptr ||
_store->Opcode() != other_store->Opcode() ||
other_store->adr_type() == nullptr ||
other_store->adr_type()->isa_aryptr() == nullptr) {
other_store->adr_type()->isa_aryptr() == nullptr ||
other_store->is_unsafe_access()) {
return false;
}

View File

@@ -974,6 +974,27 @@ bool PhaseOutput::contains_as_owner(GrowableArray<MonitorValue*> *monarray, Obje
return false;
}
// Determine if there is a scalar replaced object description represented by 'ov'.
bool PhaseOutput::contains_as_scalarized_obj(JVMState* jvms, MachSafePointNode* sfn,
GrowableArray<ScopeValue*>* objs,
ObjectValue* ov) const {
for (int i = 0; i < jvms->scl_size(); i++) {
Node* n = sfn->scalarized_obj(jvms, i);
// Other kinds of nodes that we may encounter here, for instance constants
// representing values of fields of objects scalarized, aren't relevant for
// us, since they don't map to ObjectValue.
if (!n->is_SafePointScalarObject()) {
continue;
}
ObjectValue* other = (ObjectValue*) sv_for_node_id(objs, n->_idx);
if (ov == other) {
return true;
}
}
return false;
}
//--------------------------Process_OopMap_Node--------------------------------
void PhaseOutput::Process_OopMap_Node(MachNode *mach, int current_offset) {
// Handle special safepoint nodes for synchronization
@@ -1137,7 +1158,10 @@ void PhaseOutput::Process_OopMap_Node(MachNode *mach, int current_offset) {
for (int j = 0; j< merge->possible_objects()->length(); j++) {
ObjectValue* ov = merge->possible_objects()->at(j)->as_ObjectValue();
bool is_root = locarray->contains(ov) || exparray->contains(ov) || contains_as_owner(monarray, ov);
bool is_root = locarray->contains(ov) ||
exparray->contains(ov) ||
contains_as_owner(monarray, ov) ||
contains_as_scalarized_obj(jvms, sfn, objs, ov);
ov->set_root(is_root);
}
}

View File

@@ -209,6 +209,9 @@ public:
bool starts_bundle(const Node *n) const;
bool contains_as_owner(GrowableArray<MonitorValue*> *monarray, ObjectValue *ov) const;
bool contains_as_scalarized_obj(JVMState* jvms, MachSafePointNode* sfn,
GrowableArray<ScopeValue*>* objs,
ObjectValue* ov) const;
// Dump formatted assembly
#if defined(SUPPORT_OPTO_ASSEMBLY)

View File

@@ -1414,8 +1414,8 @@ const TypeFunc* OptoRuntime::intpoly_montgomeryMult_P256_Type() {
// result type needed
fields = TypeTuple::fields(1);
fields[TypeFunc::Parms + 0] = TypeInt::INT; // carry bits in output
const TypeTuple* range = TypeTuple::make(TypeFunc::Parms+1, fields);
fields[TypeFunc::Parms + 0] = nullptr; // void
const TypeTuple* range = TypeTuple::make(TypeFunc::Parms, fields);
return TypeFunc::make(domain, range);
}
@@ -1434,7 +1434,7 @@ const TypeFunc* OptoRuntime::intpoly_assign_Type() {
// result type needed
fields = TypeTuple::fields(1);
fields[TypeFunc::Parms + 0] = NULL; // void
fields[TypeFunc::Parms + 0] = nullptr; // void
const TypeTuple* range = TypeTuple::make(TypeFunc::Parms, fields);
return TypeFunc::make(domain, range);
}

View File

@@ -3717,27 +3717,55 @@ void SuperWord::adjust_pre_loop_limit_to_align_main_loop_vectors() {
TRACE_ALIGN_VECTOR_NODE(mask_AW);
TRACE_ALIGN_VECTOR_NODE(adjust_pre_iter);
// 4: Compute (3a, b):
// 4: The computation of the new pre-loop limit could overflow (for 3a) or
// underflow (for 3b) the int range. This is problematic in combination
// with Range Check Elimination (RCE), which determines a "safe" range
// where a RangeCheck will always succeed. RCE adjusts the pre-loop limit
// such that we only enter the main-loop once we have reached the "safe"
// range, and adjusts the main-loop limit so that we exit the main-loop
// before we leave the "safe" range. After RCE, the range of the main-loop
// can only be safely narrowed, and should never be widened. Hence, the
// pre-loop limit can only be increased (for stride > 0), but an add
// overflow might decrease it, or decreased (for stride < 0), but a sub
// underflow might increase it. To prevent that, we perform the Sub / Add
// and Max / Min with long operations.
old_limit = new ConvI2LNode(old_limit);
orig_limit = new ConvI2LNode(orig_limit);
adjust_pre_iter = new ConvI2LNode(adjust_pre_iter);
phase()->register_new_node(old_limit, pre_ctrl);
phase()->register_new_node(orig_limit, pre_ctrl);
phase()->register_new_node(adjust_pre_iter, pre_ctrl);
TRACE_ALIGN_VECTOR_NODE(old_limit);
TRACE_ALIGN_VECTOR_NODE(orig_limit);
TRACE_ALIGN_VECTOR_NODE(adjust_pre_iter);
// 5: Compute (3a, b):
// new_limit = old_limit + adjust_pre_iter (stride > 0)
// new_limit = old_limit - adjust_pre_iter (stride < 0)
//
Node* new_limit = nullptr;
if (stride < 0) {
new_limit = new SubINode(old_limit, adjust_pre_iter);
new_limit = new SubLNode(old_limit, adjust_pre_iter);
} else {
new_limit = new AddINode(old_limit, adjust_pre_iter);
new_limit = new AddLNode(old_limit, adjust_pre_iter);
}
phase()->register_new_node(new_limit, pre_ctrl);
TRACE_ALIGN_VECTOR_NODE(new_limit);
// 5: Compute (15a, b):
// 6: Compute (15a, b):
// Prevent pre-loop from going past the original limit of the loop.
Node* constrained_limit =
(stride > 0) ? (Node*) new MinINode(new_limit, orig_limit)
: (Node*) new MaxINode(new_limit, orig_limit);
(stride > 0) ? (Node*) new MinLNode(phase()->C, new_limit, orig_limit)
: (Node*) new MaxLNode(phase()->C, new_limit, orig_limit);
phase()->register_new_node(constrained_limit, pre_ctrl);
TRACE_ALIGN_VECTOR_NODE(constrained_limit);
// 6: Hack the pre-loop limit
// 7: We know that the result is in the int range, there is never truncation
constrained_limit = new ConvL2INode(constrained_limit);
phase()->register_new_node(constrained_limit, pre_ctrl);
TRACE_ALIGN_VECTOR_NODE(constrained_limit);
// 8: Hack the pre-loop limit
igvn().replace_input_of(pre_opaq, 1, constrained_limit);
}

View File

@@ -2339,7 +2339,7 @@ JvmtiModuleClosure::get_all_modules(JvmtiEnv* env, jint* module_count_ptr, jobje
}
// Iterate over all the modules loaded to the system.
ClassLoaderDataGraph::modules_do(&do_module);
ClassLoaderDataGraph::modules_do_keepalive(&do_module);
jint len = _tbl->length();
guarantee(len > 0, "at least one module must be present");

View File

@@ -105,7 +105,7 @@ JvmtiGetLoadedClasses::getLoadedClasses(JvmtiEnv *env, jint* classCountPtr, jcla
// Iterate through all classes in ClassLoaderDataGraph
// and collect them using the LoadedClassesClosure
MutexLocker mcld(ClassLoaderDataGraph_lock);
ClassLoaderDataGraph::loaded_classes_do(&closure);
ClassLoaderDataGraph::loaded_classes_do_keepalive(&closure);
}
return closure.get_result(env, classCountPtr, classesPtr);

View File

@@ -947,7 +947,6 @@ void frame::oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool quer
InterpreterFrameClosure blk(this, max_locals, m->max_stack(), f);
// process locals & expression stack
ResourceMark rm(thread);
InterpreterOopMap mask;
if (query_oop_map_cache) {
m->mask_for(m, bci, &mask);

View File

@@ -1442,7 +1442,7 @@ bool ObjectMonitor::check_owner(TRAPS) {
static inline bool is_excluded(const Klass* monitor_klass) {
assert(monitor_klass != nullptr, "invariant");
NOT_JFR_RETURN_(false);
JFR_ONLY(return vmSymbols::jfr_chunk_rotation_monitor() == monitor_klass->name();)
JFR_ONLY(return vmSymbols::jdk_jfr_internal_HiddenWait() == monitor_klass->name();)
}
static void post_monitor_wait_event(EventJavaMonitorWait* event,

View File

@@ -1333,7 +1333,7 @@ methodHandle SharedRuntime::resolve_helper(bool is_virtual, bool is_optimized, T
if (invoke_code == Bytecodes::_invokestatic) {
assert(callee_method->method_holder()->is_initialized() ||
callee_method->method_holder()->is_init_thread(current),
callee_method->method_holder()->is_reentrant_initialization(current),
"invalid class initialization state for invoke_static");
if (!VM_Version::supports_fast_class_init_checks() && callee_method->needs_clinit_barrier()) {
// In order to keep class initialization check, do not patch call

View File

@@ -821,6 +821,16 @@ int ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) {
return ret_code;
}
void ObjectSynchronizer::waitUninterruptibly(Handle obj, jlong millis, TRAPS) {
if (millis < 0) {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
}
ObjectSynchronizer::inflate(THREAD,
obj(),
inflate_cause_wait)->wait(millis, false, THREAD);
}
void ObjectSynchronizer::notify(Handle obj, TRAPS) {
JavaThread* current = THREAD;

View File

@@ -119,6 +119,11 @@ public:
static bool quick_notify(oopDesc* obj, JavaThread* current, bool All);
static bool quick_enter(oop obj, JavaThread* current, BasicLock* Lock);
// Special internal-use-only method for use by JVM infrastructure
// that needs to wait() on a java-level object but that can't risk
// throwing unexpected InterruptedExecutionExceptions.
static void waitUninterruptibly(Handle obj, jlong Millis, TRAPS);
// Inflate light weight monitor to heavy weight monitor
static ObjectMonitor* inflate(Thread* current, oop obj, const InflateCause cause);
// Used to inflate a monitor as if it was done from the thread JavaThread.
@@ -225,6 +230,7 @@ class ObjectLocker : public StackObj {
// Monitor behavior
void wait(TRAPS) { ObjectSynchronizer::wait(_obj, 0, CHECK); } // wait forever
void wait_uninterruptibly(TRAPS) { ObjectSynchronizer::waitUninterruptibly(_obj, 0, CHECK); } // wait forever
void notify_all(TRAPS) { ObjectSynchronizer::notifyall(_obj, CHECK); }
};

View File

@@ -205,8 +205,9 @@ void javaVFrame::print_lock_info_on(outputStream* st, int frame_count) {
Klass* k = obj->klass();
st->print_cr("\t- %s <" INTPTR_FORMAT "> (a %s)", "parking to wait for ", p2i(obj), k->external_name());
}
else if (thread()->osthread()->get_state() == CONDVAR_WAIT) {
// We are waiting on the native class initialization monitor.
else if (thread()->osthread()->get_state() == OBJECT_WAIT) {
// We are waiting on an Object monitor but Object.wait() isn't the
// top-frame, so we should be waiting on a Class initialization monitor.
InstanceKlass* k = thread()->class_to_be_initialized();
if (k != nullptr) {
st->print_cr("\t- waiting on the Class initialization monitor for %s", k->external_name());

View File

@@ -246,6 +246,7 @@
nonstatic_field(InstanceKlass, _nonstatic_oop_map_size, int) \
volatile_nonstatic_field(InstanceKlass, _init_state, InstanceKlass::ClassState) \
volatile_nonstatic_field(InstanceKlass, _init_thread, JavaThread*) \
nonstatic_field(InstanceKlass, _is_marked_dependent, bool) \
nonstatic_field(InstanceKlass, _itable_len, int) \
nonstatic_field(InstanceKlass, _nest_host_index, u2) \
nonstatic_field(InstanceKlass, _reference_type, u1) \
@@ -2163,7 +2164,6 @@
\
declare_constant(InstanceKlass::allocated) \
declare_constant(InstanceKlass::loaded) \
declare_constant(InstanceKlass::being_linked) \
declare_constant(InstanceKlass::linked) \
declare_constant(InstanceKlass::being_initialized) \
declare_constant(InstanceKlass::fully_initialized) \

View File

@@ -1089,6 +1089,14 @@ u4 DumperSupport::get_static_fields_size(InstanceKlass* ik, u2& field_count) {
}
}
// Also provide a pointer to the init_lock if present, so there aren't unreferenced int[0]
// arrays.
oop init_lock = ik->init_lock();
if (init_lock != nullptr) {
field_count++;
size += sizeof(address);
}
// We write the value itself plus a name and a one byte type tag per field.
return checked_cast<u4>(size + field_count * (sizeof(address) + 1));
}
@@ -1126,6 +1134,14 @@ void DumperSupport::dump_static_fields(AbstractDumpWriter* writer, Klass* k) {
prev = prev->previous_versions();
}
}
// Add init lock to the end if the class is not yet initialized
oop init_lock = ik->init_lock();
if (init_lock != nullptr) {
writer->write_symbolID(vmSymbols::init_lock_name()); // name
writer->write_u1(sig2tag(vmSymbols::int_array_signature())); // type
writer->write_objectID(init_lock);
}
}
// dump the raw values of the instance fields of the given object

View File

@@ -44,6 +44,9 @@
#include "utilities/events.hpp"
#include "utilities/exceptions.hpp"
// Limit exception message components to 64K (the same max as Symbols)
#define MAX_LEN 65535
// Implementation of ThreadShadow
void check_ThreadShadow() {
const ByteSize offset1 = byte_offset_of(ThreadShadow, _pending_exception);
@@ -116,10 +119,11 @@ bool Exceptions::special_exception(JavaThread* thread, const char* file, int lin
const char* exc_value = h_exception.not_null() ? h_exception->print_value_string() :
h_name != nullptr ? h_name->as_C_string() :
"null";
log_info(exceptions)("Thread cannot call Java so instead of throwing exception <%s%s%s> (" PTR_FORMAT ") \n"
log_info(exceptions)("Thread cannot call Java so instead of throwing exception <%.*s%s%.*s> (" PTR_FORMAT ") \n"
"at [%s, line %d]\nfor thread " PTR_FORMAT ",\n"
"throwing pre-allocated exception: %s",
exc_value, message ? ": " : "", message ? message : "",
MAX_LEN, exc_value, message ? ": " : "",
MAX_LEN, message ? message : "",
p2i(h_exception()), file, line, p2i(thread),
Universe::vm_exception()->print_value_string());
// We do not care what kind of exception we get for a thread which
@@ -145,10 +149,11 @@ void Exceptions::_throw(JavaThread* thread, const char* file, int line, Handle h
// tracing (do this up front - so it works during boot strapping)
// Note, the print_value_string() argument is not called unless logging is enabled!
log_info(exceptions)("Exception <%s%s%s> (" PTR_FORMAT ") \n"
log_info(exceptions)("Exception <%.*s%s%.*s> (" PTR_FORMAT ") \n"
"thrown [%s, line %d]\nfor thread " PTR_FORMAT,
h_exception->print_value_string(),
message ? ": " : "", message ? message : "",
MAX_LEN, h_exception->print_value_string(),
message ? ": " : "",
MAX_LEN, message ? message : "",
p2i(h_exception()), file, line, p2i(thread));
// for AbortVMOnException flag
@@ -568,13 +573,13 @@ void Exceptions::log_exception(Handle exception, const char* message) {
ResourceMark rm;
const char* detail_message = java_lang_Throwable::message_as_utf8(exception());
if (detail_message != nullptr) {
log_info(exceptions)("Exception <%s: %s>\n thrown in %s",
exception->print_value_string(),
detail_message,
message);
log_info(exceptions)("Exception <%.*s: %.*s>\n thrown in %.*s",
MAX_LEN, exception->print_value_string(),
MAX_LEN, detail_message,
MAX_LEN, message);
} else {
log_info(exceptions)("Exception <%s>\n thrown in %s",
exception->print_value_string(),
message);
log_info(exceptions)("Exception <%.*s>\n thrown in %.*s",
MAX_LEN, exception->print_value_string(),
MAX_LEN, message);
}
}

View File

@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "memory/allocation.hpp"
#include "utilities/checkedCast.hpp"
#include "utilities/debug.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/utf8.hpp"
@@ -431,12 +432,16 @@ int UNICODE::utf8_size(jbyte c) {
template<typename T>
int UNICODE::utf8_length(const T* base, int length) {
int result = 0;
size_t result = 0;
for (int index = 0; index < length; index++) {
T c = base[index];
result += utf8_size(c);
int sz = utf8_size(c);
if (result + sz > INT_MAX-1) {
break;
}
result += sz;
}
return result;
return checked_cast<int>(result);
}
template<typename T>

View File

@@ -237,6 +237,10 @@ public class Object {
/**
* {@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

View File

@@ -86,7 +86,7 @@ import java.lang.classfile.instruction.TypeCheckInstruction;
import static java.util.Objects.requireNonNull;
import static jdk.internal.classfile.impl.BytecodeHelpers.handleDescToHandleInfo;
import jdk.internal.classfile.impl.TransformingCodeBuilder;
import jdk.internal.javac.PreviewFeature;
/**
@@ -171,7 +171,7 @@ public sealed interface CodeBuilder
default CodeBuilder transforming(CodeTransform transform, Consumer<CodeBuilder> handler) {
var resolved = transform.resolve(this);
resolved.startHandler().run();
handler.accept(new TransformingCodeBuilder(this, resolved.consumer()));
handler.accept(new ChainedCodeBuilder(this, resolved.consumer()));
resolved.endHandler().run();
return this;
}

View File

@@ -1,6 +1,6 @@
<!doctype html>
<!--
Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2013, 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
@@ -26,7 +26,6 @@
<html lang="en">
<head>
<title>Value-based Classes</title>
<link rel="stylesheet" type="text/css" href="../../../../stylesheet.css" title="Style">
</head>
<body>
<h1 id="ValueBased">{@index "Value-based Classes"}</h1>

View File

@@ -1,6 +1,6 @@
<!doctype html>
<!--
Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2005, 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
@@ -26,7 +26,6 @@
<html lang="en">
<head>
<title>Java Thread Primitive Deprecation</title>
<link rel="stylesheet" type="text/css" href="../../../../stylesheet.css" title="Style">
</head>
<body>
<h1>Java Thread Primitive Deprecation</h1>

View File

@@ -222,7 +222,7 @@ import java.util.stream.Stream;
* <pre>
* MemoryLayout.structLayout(
* ValueLayout.JAVA_INT.withName("x"),
* MemoryLayout.paddingLayout(32),
* MemoryLayout.paddingLayout(4),
* ValueLayout.JAVA_LONG.withName("y")
* );
* </pre>

View File

@@ -369,7 +369,7 @@ import jdk.internal.foreign.layout.UnionLayoutImpl;
* int size = ...
* MemorySegment points = ...
* for (int i = 0 ; i < size ; i++) {
* ... POINT_ARR_X.get(segment, 0L, (long)i) ...
* ... POINT_ARR_X.get(points, 0L, (long)i) ...
* }
* }
*

View File

@@ -630,6 +630,12 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* {@snippet lang=java :
* asSlice(offset, newSize, 1);
* }
* <p>
* If this segment is {@linkplain MemorySegment#isReadOnly() read-only},
* the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}.
* <p>
* The returned memory segment shares a region of backing memory with this segment.
* Hence, no memory will be allocated or freed by this method.
*
* @see #asSlice(long, long, long)
*
@@ -646,6 +652,12 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* Returns a slice of this memory segment, at the given offset, with the provided
* alignment constraint. The returned segment's address is the address of this
* segment plus the given offset; its size is specified by the given argument.
* <p>
* If this segment is {@linkplain MemorySegment#isReadOnly() read-only},
* the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}.
* <p>
* The returned memory segment shares a region of backing memory with this segment.
* Hence, no memory will be allocated or freed by this method.
*
* @param offset The new segment base offset (relative to the address of this segment),
* specified in bytes
@@ -670,6 +682,12 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* {@snippet lang=java :
* asSlice(offset, layout.byteSize(), layout.byteAlignment());
* }
* <p>
* If this segment is {@linkplain MemorySegment#isReadOnly() read-only},
* the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}.
* <p>
* The returned memory segment shares a region of backing memory with this segment.
* Hence, no memory will be allocated or freed by this method.
*
* @see #asSlice(long, long, long)
*
@@ -693,6 +711,12 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* {@snippet lang=java :
* asSlice(offset, byteSize() - offset);
* }
* <p>
* If this segment is {@linkplain MemorySegment#isReadOnly() read-only},
* the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}.
* <p>
* The returned memory segment shares a region of backing memory with this segment.
* Hence, no memory will be allocated or freed by this method.
*
* @see #asSlice(long, long)
*
@@ -706,6 +730,12 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
/**
* Returns a new memory segment that has the same address and scope as this segment,
* but with the provided size.
* <p>
* If this segment is {@linkplain MemorySegment#isReadOnly() read-only},
* the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}.
* <p>
* The returned memory segment shares a region of backing memory with this segment.
* Hence, no memory will be allocated or freed by this method.
*
* @param newSize the size of the returned segment
* @return a new memory segment that has the same address and scope as
@@ -741,6 +771,12 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* That is, the cleanup action receives a segment that is associated with the global
* scope, and is accessible from any thread. The size of the segment accepted by the
* cleanup action is {@link #byteSize()}.
* <p>
* If this segment is {@linkplain MemorySegment#isReadOnly() read-only},
* the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}.
* <p>
* The returned memory segment shares a region of backing memory with this segment.
* Hence, no memory will be allocated or freed by this method.
*
* @apiNote The cleanup action (if present) should take care not to leak the received
* segment to external clients that might access the segment after its
@@ -786,6 +822,12 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* That is, the cleanup action receives a segment that is associated with the global
* scope, and is accessible from any thread. The size of the segment accepted by the
* cleanup action is {@code newSize}.
* <p>
* If this segment is {@linkplain MemorySegment#isReadOnly() read-only},
* the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}.
* <p>
* The returned memory segment shares a region of backing memory with this segment.
* Hence, no memory will be allocated or freed by this method.
*
* @apiNote The cleanup action (if present) should take care not to leak the received
* segment to external clients that might access the segment after its

View File

@@ -39,7 +39,6 @@ import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Objects;
import jdk.internal.constant.ConstantUtils;
import jdk.internal.constant.MethodTypeDescImpl;
import jdk.internal.constant.ReferenceClassDescImpl;
import sun.security.action.GetBooleanAction;
@@ -47,10 +46,7 @@ import sun.security.action.GetBooleanAction;
import static java.lang.classfile.ClassFile.*;
import java.lang.classfile.attribute.StackMapFrameInfo;
import java.lang.classfile.attribute.StackMapTableAttribute;
import java.lang.constant.ConstantDescs;
import static java.lang.constant.ConstantDescs.*;
import java.lang.constant.DirectMethodHandleDesc;
import java.lang.constant.DynamicConstantDesc;
/**
* ProxyGenerator contains the code to generate a dynamic proxy class
@@ -65,7 +61,10 @@ final class ProxyGenerator {
ClassFile.of(ClassFile.StackMapsOption.DROP_STACK_MAPS);
private static final ClassDesc
CD_ClassLoader = ReferenceClassDescImpl.ofValidated("Ljava/lang/ClassLoader;"),
CD_Class_array = ReferenceClassDescImpl.ofValidated("[Ljava/lang/Class;"),
CD_ClassNotFoundException = ReferenceClassDescImpl.ofValidated("Ljava/lang/ClassNotFoundException;"),
CD_NoClassDefFoundError = ReferenceClassDescImpl.ofValidated("Ljava/lang/NoClassDefFoundError;"),
CD_IllegalAccessException = ReferenceClassDescImpl.ofValidated("Ljava/lang/IllegalAccessException;"),
CD_InvocationHandler = ReferenceClassDescImpl.ofValidated("Ljava/lang/reflect/InvocationHandler;"),
CD_Method = ReferenceClassDescImpl.ofValidated("Ljava/lang/reflect/Method;"),
@@ -81,8 +80,9 @@ final class ProxyGenerator {
MTD_void_String = MethodTypeDescImpl.ofValidated(CD_void, CD_String),
MTD_void_Throwable = MethodTypeDescImpl.ofValidated(CD_void, CD_Throwable),
MTD_Class = MethodTypeDescImpl.ofValidated(CD_Class),
MTD_Class_array = MethodTypeDescImpl.ofValidated(CD_Class_array),
MTD_Method_String_Class_array = MethodTypeDescImpl.ofValidated(CD_Method, ConstantDescs.CD_String, CD_Class_array),
MTD_Class_String_boolean_ClassLoader = MethodTypeDescImpl.ofValidated(CD_Class, CD_String, CD_boolean, CD_ClassLoader),
MTD_ClassLoader = MethodTypeDescImpl.ofValidated(CD_ClassLoader),
MTD_Method_String_Class_array = MethodTypeDescImpl.ofValidated(CD_Method, CD_String, CD_Class_array),
MTD_MethodHandles$Lookup = MethodTypeDescImpl.ofValidated(CD_MethodHandles_Lookup),
MTD_MethodHandles$Lookup_MethodHandles$Lookup = MethodTypeDescImpl.ofValidated(CD_MethodHandles_Lookup, CD_MethodHandles_Lookup),
MTD_Object_Object_Method_ObjectArray = MethodTypeDescImpl.ofValidated(CD_Object, CD_Object, CD_Method, CD_Object_array),
@@ -107,34 +107,33 @@ final class ProxyGenerator {
"jdk.proxy.ProxyGenerator.saveGeneratedFiles"));
/* Preloaded ProxyMethod objects for methods in java.lang.Object */
private static final ProxyMethod HASH_CODE_METHOD;
private static final ProxyMethod EQUALS_METHOD;
private static final ProxyMethod TO_STRING_METHOD;
private static final Method OBJECT_HASH_CODE_METHOD;
private static final Method OBJECT_EQUALS_METHOD;
private static final Method OBJECT_TO_STRING_METHOD;
static {
try {
HASH_CODE_METHOD = new ProxyMethod(Object.class.getMethod("hashCode"));
EQUALS_METHOD = new ProxyMethod(Object.class.getMethod("equals", Object.class));
TO_STRING_METHOD = new ProxyMethod(Object.class.getMethod("toString"));
OBJECT_HASH_CODE_METHOD = Object.class.getMethod("hashCode");
OBJECT_EQUALS_METHOD = Object.class.getMethod("equals", Object.class);
OBJECT_TO_STRING_METHOD = Object.class.getMethod("toString");
} catch (NoSuchMethodException e) {
throw new NoSuchMethodError(e.getMessage());
}
}
private final ConstantPoolBuilder cp;
private final List<StackMapFrameInfo.VerificationTypeInfo> throwableStack;
private final List<StackMapFrameInfo.VerificationTypeInfo> classLoaderLocal, throwableStack;
private final NameAndTypeEntry exInit;
private final ClassEntry object, proxy, ute;
private final ClassEntry objectCE, proxyCE, uteCE, classCE;
private final FieldRefEntry handlerField;
private final InterfaceMethodRefEntry invoke;
private final MethodRefEntry uteInit;
private final DirectMethodHandleDesc bsm;
private final InterfaceMethodRefEntry invocationHandlerInvoke;
private final MethodRefEntry uteInit, classGetMethod, classForName, throwableGetMessage;
/**
* Name of proxy class
* ClassEntry for this proxy class
*/
private ClassEntry classEntry;
private final ClassEntry thisClassCE;
/**
* Proxy interfaces
@@ -153,6 +152,12 @@ final class ProxyGenerator {
*/
private final Map<String, List<ProxyMethod>> proxyMethods = new LinkedHashMap<>();
/**
* Ordinal of next ProxyMethod object added to proxyMethods.
* Indexes are reserved for hashcode(0), equals(1), toString(2).
*/
private int proxyMethodCount = 3;
/**
* Construct a ProxyGenerator to generate a proxy class with the
* specified name and for the given interfaces.
@@ -163,18 +168,23 @@ final class ProxyGenerator {
private ProxyGenerator(ClassLoader loader, String className, List<Class<?>> interfaces,
int accessFlags) {
this.cp = ConstantPoolBuilder.of();
this.classEntry = cp.classEntry(ReferenceClassDescImpl.ofValidatedBinaryName(className));
this.thisClassCE = cp.classEntry(ReferenceClassDescImpl.ofValidatedBinaryName(className));
this.interfaces = interfaces;
this.accessFlags = accessFlags;
this.throwableStack = List.of(StackMapFrameInfo.ObjectVerificationTypeInfo.of(cp.classEntry(CD_Throwable)));
var throwable = cp.classEntry(CD_Throwable);
this.classLoaderLocal = List.of(StackMapFrameInfo.ObjectVerificationTypeInfo.of(cp.classEntry(CD_ClassLoader)));
this.throwableStack = List.of(StackMapFrameInfo.ObjectVerificationTypeInfo.of(throwable));
this.exInit = cp.nameAndTypeEntry(INIT_NAME, MTD_void_String);
this.object = cp.classEntry(CD_Object);
this.proxy = cp.classEntry(CD_Proxy);
this.handlerField = cp.fieldRefEntry(proxy, cp.nameAndTypeEntry(NAME_HANDLER_FIELD, CD_InvocationHandler));
this.invoke = cp.interfaceMethodRefEntry(CD_InvocationHandler, "invoke", MTD_Object_Object_Method_ObjectArray);
this.ute = cp.classEntry(CD_UndeclaredThrowableException);
this.uteInit = cp.methodRefEntry(ute, cp.nameAndTypeEntry(INIT_NAME, MTD_void_Throwable));
this.bsm = ConstantDescs.ofConstantBootstrap(classEntry.asSymbol(), "$getMethod", CD_Method, CD_Class, CD_String, CD_MethodType);
this.objectCE = cp.classEntry(CD_Object);
this.proxyCE = cp.classEntry(CD_Proxy);
this.classCE = cp.classEntry(CD_Class);
this.handlerField = cp.fieldRefEntry(proxyCE, cp.nameAndTypeEntry(NAME_HANDLER_FIELD, CD_InvocationHandler));
this.invocationHandlerInvoke = cp.interfaceMethodRefEntry(CD_InvocationHandler, "invoke", MTD_Object_Object_Method_ObjectArray);
this.uteCE = cp.classEntry(CD_UndeclaredThrowableException);
this.uteInit = cp.methodRefEntry(uteCE, cp.nameAndTypeEntry(INIT_NAME, MTD_void_Throwable));
this.classGetMethod = cp.methodRefEntry(classCE, cp.nameAndTypeEntry("getMethod", MTD_Method_String_Class_array));
this.classForName = cp.methodRefEntry(classCE, cp.nameAndTypeEntry("forName", MTD_Class_String_boolean_ClassLoader));
this.throwableGetMessage = cp.methodRefEntry(throwable, cp.nameAndTypeEntry("getMessage", MTD_String));
}
/**
@@ -441,9 +451,9 @@ final class ProxyGenerator {
* java.lang.Object take precedence over duplicate methods in the
* proxy interfaces.
*/
addProxyMethod(HASH_CODE_METHOD);
addProxyMethod(EQUALS_METHOD);
addProxyMethod(TO_STRING_METHOD);
addProxyMethod(new ProxyMethod(OBJECT_HASH_CODE_METHOD, "m0"));
addProxyMethod(new ProxyMethod(OBJECT_EQUALS_METHOD, "m1"));
addProxyMethod(new ProxyMethod(OBJECT_TO_STRING_METHOD, "m2"));
/*
* Accumulate all of the methods from the proxy interfaces.
@@ -464,20 +474,23 @@ final class ProxyGenerator {
checkReturnTypes(sigmethods);
}
return CF_CONTEXT.build(classEntry, cp, clb -> {
clb.withSuperclass(proxy);
return CF_CONTEXT.build(thisClassCE, cp, clb -> {
clb.withSuperclass(proxyCE);
clb.withFlags(accessFlags);
clb.withInterfaces(toClassEntries(cp, interfaces));
generateConstructor(clb);
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
for (ProxyMethod pm : sigmethods) {
// add static field for the Method object
clb.withField(pm.methodFieldName, CD_Method, ACC_PRIVATE | ACC_STATIC | ACC_FINAL);
// Generate code for proxy method
pm.generateMethod(this, clb);
pm.generateMethod(clb);
}
}
generateBootstrapMethod(clb);
generateStaticInitializer(clb);
generateLookupAccessor(clb);
});
}
@@ -520,7 +533,7 @@ final class ProxyGenerator {
}
}
sigmethods.add(new ProxyMethod(m, sig, m.getSharedParameterTypes(), returnType,
exceptionTypes, fromClass));
exceptionTypes, fromClass, "m" + proxyMethodCount++));
}
/**
@@ -542,32 +555,56 @@ final class ProxyGenerator {
clb.withMethodBody(INIT_NAME, MTD_void_InvocationHandler, ACC_PUBLIC, cob -> cob
.aload(0)
.aload(1)
.invokespecial(cp.methodRefEntry(proxy, cp.nameAndTypeEntry(INIT_NAME, MTD_void_InvocationHandler)))
.invokespecial(cp.methodRefEntry(proxyCE,
cp.nameAndTypeEntry(INIT_NAME, MTD_void_InvocationHandler)))
.return_());
}
/**
* Generate CONDY bootstrap method for the proxy class to retrieve {@link Method} instances.
* Generate the class initializer.
* Discussion: Currently, for Proxy to work with SecurityManager,
* we rely on the parameter classes of the methods to be computed
* from Proxy instead of via user code paths like bootstrap method
* lazy evaluation. That might change if we can pass in the live
* Method objects directly..
*/
private void generateBootstrapMethod(ClassBuilder clb) {
clb.withMethodBody(bsm.methodName(), bsm.invocationType(), ClassFile.ACC_PRIVATE | ClassFile.ACC_STATIC, cob -> {
cob.aload(3) //interface Class
.aload(4) //interface method name String
.aload(5) //interface MethodType
.invokevirtual(CD_MethodType, "parameterArray", MTD_Class_array)
.invokevirtual(ConstantDescs.CD_Class, "getMethod", MTD_Method_String_Class_array)
.areturn();
Label failLabel = cob.newBoundLabel();
ClassEntry nsme = cp.classEntry(CD_NoSuchMethodError);
cob.exceptionCatch(cob.startLabel(), failLabel, failLabel, CD_NoSuchMethodException)
.new_(nsme)
private void generateStaticInitializer(ClassBuilder clb) {
clb.withMethodBody(CLASS_INIT_NAME, MTD_void, ACC_STATIC, cob -> {
// Put ClassLoader at local variable index 0, used by
// Class.forName(String, boolean, ClassLoader) calls
cob.ldc(thisClassCE)
.invokevirtual(cp.methodRefEntry(classCE,
cp.nameAndTypeEntry("getClassLoader", MTD_ClassLoader)))
.astore(0);
var ts = cob.newBoundLabel();
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
for (ProxyMethod pm : sigmethods) {
pm.codeFieldInitialization(cob);
}
}
cob.return_();
var c1 = cob.newBoundLabel();
var nsmError = cp.classEntry(CD_NoSuchMethodError);
cob.exceptionCatch(ts, c1, c1, CD_NoSuchMethodException)
.new_(nsmError)
.dup_x1()
.swap()
.invokevirtual(cp.methodRefEntry(CD_Throwable, "getMessage", MTD_String))
.invokespecial(cp.methodRefEntry(nsme, exInit))
.athrow()
.with(StackMapTableAttribute.of(List.of(
StackMapFrameInfo.of(failLabel, List.of(), throwableStack))));
.invokevirtual(throwableGetMessage)
.invokespecial(cp.methodRefEntry(nsmError, exInit))
.athrow();
var c2 = cob.newBoundLabel();
var ncdfError = cp.classEntry(CD_NoClassDefFoundError);
cob.exceptionCatch(ts, c1, c2, CD_ClassNotFoundException)
.new_(ncdfError)
.dup_x1()
.swap()
.invokevirtual(throwableGetMessage)
.invokespecial(cp.methodRefEntry(ncdfError, exInit))
.athrow();
cob.with(StackMapTableAttribute.of(List.of(
StackMapFrameInfo.of(c1, classLoaderLocal, throwableStack),
StackMapFrameInfo.of(c2, classLoaderLocal, throwableStack))));
});
}
@@ -587,7 +624,7 @@ final class ProxyGenerator {
ClassEntry iae = cp.classEntry(CD_IllegalAccessException);
cob.aload(cob.parameterSlot(0))
.invokevirtual(cp.methodRefEntry(mhl, cp.nameAndTypeEntry("lookupClass", MTD_Class)))
.ldc(proxy)
.ldc(proxyCE)
.if_acmpne(failLabel)
.aload(cob.parameterSlot(0))
.invokevirtual(cp.methodRefEntry(mhl, cp.nameAndTypeEntry("hasFullPrivilegeAccess", MTD_boolean)))
@@ -613,24 +650,29 @@ final class ProxyGenerator {
* being generated: a method whose implementation will encode and
* dispatch invocations to the proxy instance's invocation handler.
*/
private static class ProxyMethod {
private class ProxyMethod {
private final Method method;
private final String shortSignature;
private final Class<?> fromClass;
private final Class<?>[] parameterTypes;
private final Class<?> returnType;
private final String methodFieldName;
private Class<?>[] exceptionTypes;
private final FieldRefEntry methodField;
private ProxyMethod(Method method, String sig, Class<?>[] parameterTypes,
Class<?> returnType, Class<?>[] exceptionTypes,
Class<?> fromClass) {
Class<?> fromClass, String methodFieldName) {
this.method = method;
this.shortSignature = sig;
this.parameterTypes = parameterTypes;
this.returnType = returnType;
this.exceptionTypes = exceptionTypes;
this.fromClass = fromClass;
this.methodFieldName = methodFieldName;
this.methodField = cp.fieldRefEntry(thisClassCE,
cp.nameAndTypeEntry(methodFieldName, CD_Method));
}
/**
@@ -639,17 +681,16 @@ final class ProxyGenerator {
* @param method The method for which to create a proxy
* @param methodFieldName the fieldName to generate
*/
private ProxyMethod(Method method) {
private ProxyMethod(Method method, String methodFieldName) {
this(method, method.toShortSignature(),
method.getSharedParameterTypes(), method.getReturnType(),
method.getSharedExceptionTypes(), method.getDeclaringClass());
method.getSharedExceptionTypes(), method.getDeclaringClass(), methodFieldName);
}
/**
* Generate this method, including the code and exception table entry.
*/
private void generateMethod(ProxyGenerator pg, ClassBuilder clb) {
var cp = pg.cp;
private void generateMethod(ClassBuilder clb) {
var pTypes = new ClassDesc[parameterTypes.length];
for (int i = 0; i < pTypes.length; i++) {
pTypes[i] = toClassDesc(parameterTypes[i]);
@@ -661,17 +702,14 @@ final class ProxyGenerator {
clb.withMethod(method.getName(), desc, accessFlags, mb ->
mb.with(ExceptionsAttribute.of(toClassEntries(cp, List.of(exceptionTypes))))
.withCode(cob -> {
cob.aload(0)
.getfield(pg.handlerField)
.aload(0)
.ldc(DynamicConstantDesc.of(pg.bsm,
toClassDesc(fromClass),
method.getName(),
desc));
cob.aload(cob.receiverSlot())
.getfield(handlerField)
.aload(cob.receiverSlot())
.getstatic(methodField);
if (parameterTypes.length > 0) {
// Create an array and fill with the parameters converting primitives to wrappers
cob.loadConstant(parameterTypes.length)
.anewarray(pg.object);
.anewarray(objectCE);
for (int i = 0; i < parameterTypes.length; i++) {
cob.dup()
.loadConstant(i);
@@ -682,7 +720,7 @@ final class ProxyGenerator {
cob.aconst_null();
}
cob.invokeinterface(pg.invoke);
cob.invokeinterface(invocationHandlerInvoke);
if (returnType == void.class) {
cob.pop()
@@ -698,14 +736,14 @@ final class ProxyGenerator {
cob.athrow(); // just rethrow the exception
var c2 = cob.newBoundLabel();
cob.exceptionCatchAll(cob.startLabel(), c1, c2)
.new_(pg.ute)
.new_(uteCE)
.dup_x1()
.swap()
.invokespecial(pg.uteInit)
.invokespecial(uteInit)
.athrow()
.with(StackMapTableAttribute.of(List.of(
StackMapFrameInfo.of(c1, List.of(), pg.throwableStack),
StackMapFrameInfo.of(c2, List.of(), pg.throwableStack))));
StackMapFrameInfo.of(c1, List.of(), throwableStack),
StackMapFrameInfo.of(c2, List.of(), throwableStack))));
}
}));
}
@@ -720,7 +758,7 @@ final class ProxyGenerator {
if (type.isPrimitive()) {
cob.loadLocal(TypeKind.from(type).asLoadable(), slot);
PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
cob.invokestatic(prim.wrapperMethodRef(cob.constantPool()));
cob.invokestatic(prim.wrapperMethodRef(cp));
} else {
cob.aload(slot);
}
@@ -736,7 +774,7 @@ final class ProxyGenerator {
PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
cob.checkcast(prim.wrapperClass)
.invokevirtual(prim.unwrapMethodRef(cob.constantPool()))
.invokevirtual(prim.unwrapMethodRef(cp))
.return_(TypeKind.from(type).asLoadable());
} else {
cob.checkcast(toClassDesc(type))
@@ -744,6 +782,57 @@ final class ProxyGenerator {
}
}
/**
* Generate code for initializing the static field that stores
* the Method object for this proxy method. A class loader is
* anticipated at local variable index 0.
* The generated code must be run in an AccessController.doPrivileged
* block if a SecurityManager is present, as otherwise the code
* cannot pass {@code null} ClassLoader to forName.
*/
private void codeFieldInitialization(CodeBuilder cob) {
var cp = cob.constantPool();
codeClassForName(cob, fromClass);
cob.ldc(method.getName())
.loadConstant(parameterTypes.length)
.anewarray(classCE);
// Construct an array with the parameter types mapping primitives to Wrapper types
for (int i = 0; i < parameterTypes.length; i++) {
cob.dup()
.loadConstant(i);
if (parameterTypes[i].isPrimitive()) {
PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(parameterTypes[i]);
cob.getstatic(prim.typeFieldRef(cp));
} else {
codeClassForName(cob, parameterTypes[i]);
}
cob.aastore();
}
// lookup the method
cob.invokevirtual(classGetMethod)
.putstatic(methodField);
}
/*
* =============== Code Generation Utility Methods ===============
*/
/**
* Generate code to invoke the Class.forName with the name of the given
* class to get its Class object at runtime. The code is written to
* the supplied stream. Note that the code generated by this method
* may cause the checked ClassNotFoundException to be thrown. A class
* loader is anticipated at local variable index 0.
*/
private void codeClassForName(CodeBuilder cob, Class<?> cl) {
cob.ldc(cl.getName())
.iconst_0() // false
.aload(0)// classLoader
.invokestatic(classForName);
}
@Override
public String toString() {
return method.toShortString();
@@ -810,5 +899,9 @@ final class ProxyGenerator {
public MethodRefEntry unwrapMethodRef(ConstantPoolBuilder cp) {
return cp.methodRefEntry(wrapperClass, unwrapMethodName, unwrapMethodType);
}
public FieldRefEntry typeFieldRef(ConstantPoolBuilder cp) {
return cp.fieldRefEntry(wrapperClass, "TYPE", CD_Class);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
@@ -293,7 +293,7 @@ public interface Gatherer<T, A, R> {
*
* @implSpec This method always returns the same instance.
*
* @see Gatherer#finisher()
* @see Gatherer#combiner()
* @return the instance of the default combiner
* @param <A> the type of the state of the returned combiner
*/

View File

@@ -68,24 +68,19 @@ public abstract sealed class AbstractPoolEntry {
*/
private static final int TAG_SMEAR = 0x13C4B2D1;
private static final int INT_PHI = 0x9E3779B9;
static final int NON_ZERO = 0x40000000;
public static int hash1(int tag, int x1) {
return phiMix(tag * TAG_SMEAR + x1);
return (tag * TAG_SMEAR + x1) | NON_ZERO;
}
public static int hash2(int tag, int x1, int x2) {
return phiMix(tag * TAG_SMEAR + x1 + 31*x2);
return (tag * TAG_SMEAR + x1 + 31 * x2) | NON_ZERO;
}
// Ensure that hash is never zero
public static int hashString(int stringHash) {
return phiMix(stringHash | (1 << 30));
}
public static int phiMix(int x) {
int h = x * INT_PHI;
return h ^ (h >> 16);
return stringHash | NON_ZERO;
}
public static Utf8Entry rawUtf8EntryFromStandardAttributeName(String name) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -51,13 +51,13 @@ public final class BlockCodeBuilderImpl
public void start() {
topLocal = topLocal(parent);
terminalMaxLocals = topLocal(terminal);
terminal.with((LabelTarget) startLabel);
terminalMaxLocals = terminal.curTopLocal();
parent.with((LabelTarget) startLabel);
}
public void end() {
terminal.with((LabelTarget) endLabel);
if (terminalMaxLocals != topLocal(terminal)) {
parent.with((LabelTarget) endLabel);
if (terminalMaxLocals != terminal.curTopLocal()) {
throw new IllegalStateException("Interference in local variable slot management");
}
}
@@ -73,10 +73,8 @@ public final class BlockCodeBuilderImpl
private int topLocal(CodeBuilder parent) {
return switch (parent) {
case BlockCodeBuilderImpl b -> b.topLocal;
case ChainedCodeBuilder b -> topLocal(b.terminal);
case DirectCodeBuilder b -> b.curTopLocal();
case BufferedCodeBuilder b -> b.curTopLocal();
case TransformingCodeBuilder b -> topLocal(b.delegate);
case ChainedCodeBuilder b -> b.terminal.curTopLocal();
case TerminalCodeBuilder b -> b.curTopLocal();
};
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -76,9 +76,7 @@ public final class BootstrapMethodEntryImpl implements BootstrapMethodEntry {
static int computeHashCode(MethodHandleEntryImpl handle,
List<? extends LoadableConstantEntry> arguments) {
int hash = handle.hashCode();
hash = 31 * hash + arguments.hashCode();
return AbstractPoolEntry.phiMix(hash);
return (31 * handle.hashCode() + arguments.hashCode()) | AbstractPoolEntry.NON_ZERO;
}
@Override

View File

@@ -988,77 +988,77 @@ public abstract sealed class BoundAttribute<T extends Attribute<T>>
public static AttributeMapper<?> standardAttribute(Utf8Entry name) {
// critical bootstrap path, so no lambdas nor method handles here
return switch (name.hashCode()) {
case 0x78147009 ->
case 0x46699ff2 ->
name.equalsString(NAME_ANNOTATION_DEFAULT) ? annotationDefault() : null;
case 0x665e3a3a ->
case 0x5208e184 ->
name.equalsString(NAME_BOOTSTRAP_METHODS) ? bootstrapMethods() : null;
case 0xcb7e162 ->
case 0xcb60907a ->
name.equalsString(NAME_CHARACTER_RANGE_TABLE) ? characterRangeTable() : null;
case 0x21e41e7e ->
case 0x4020220d ->
name.equalsString(NAME_CODE) ? code() : null;
case 0x5a306b41 ->
case 0xc20dd1fe ->
name.equalsString(NAME_COMPILATION_ID) ? compilationId() : null;
case 0x3e191c7c ->
case 0xcab1940d ->
name.equalsString(NAME_CONSTANT_VALUE) ? constantValue() : null;
case 0x5e88ed0c ->
case 0x558641d3 ->
name.equalsString(NAME_DEPRECATED) ? deprecated() : null;
case 0x7284695e ->
case 0x51d443cd ->
name.equalsString(NAME_ENCLOSING_METHOD) ? enclosingMethod() : null;
case 0x21df25db ->
case 0x687c1624 ->
name.equalsString(NAME_EXCEPTIONS) ? exceptions() : null;
case 0x11392da9 ->
case 0x7adb2910 ->
name.equalsString(NAME_INNER_CLASSES) ? innerClasses() : null;
case 0x167536fc ->
case 0x653f0551 ->
name.equalsString(NAME_LINE_NUMBER_TABLE) ? lineNumberTable() : null;
case 0x46939abc ->
case 0x64c75927 ->
name.equalsString(NAME_LOCAL_VARIABLE_TABLE) ? localVariableTable() : null;
case 0x63ee67f4 ->
case 0x6697f98d ->
name.equalsString(NAME_LOCAL_VARIABLE_TYPE_TABLE) ? localVariableTypeTable() : null;
case 0x2b597e15 ->
case 0xdbb0cdcb ->
name.equalsString(NAME_METHOD_PARAMETERS) ? methodParameters() : null;
case 0x19f20ade ->
case 0xc9b0928c ->
name.equalsString(NAME_MODULE) ? module() : null;
case 0x47f6395e ->
case 0x41cd27e8 ->
name.equalsString(NAME_MODULE_HASHES) ? moduleHashes() : null;
case 0x54db809 ->
case 0x7deb0a13 ->
name.equalsString(NAME_MODULE_MAIN_CLASS) ? moduleMainClass() : null;
case 0x1abd1c2c ->
case 0x6706ff99 ->
name.equalsString(NAME_MODULE_PACKAGES) ? modulePackages() : null;
case 0x6ba46dd ->
case 0x60272858 ->
name.equalsString(NAME_MODULE_RESOLUTION) ? moduleResolution() : null;
case 0x46f7d91d ->
case 0x5646d73d ->
name.equalsString(NAME_MODULE_TARGET) ? moduleTarget() : null;
case 0x5137f53 ->
case 0x50336c40 ->
name.equalsString(NAME_NEST_HOST) ? nestHost() : null;
case 0x4a8fa3b6 ->
case 0x4735ab81 ->
name.equalsString(NAME_NEST_MEMBERS) ? nestMembers() : null;
case 0x55c73cb6 ->
case 0x7100d9fe ->
name.equalsString(NAME_PERMITTED_SUBCLASSES) ? permittedSubclasses() : null;
case 0x3fe76d4e ->
case 0xd1ab5871 ->
name.equalsString(NAME_RECORD) ? record() : null;
case 0x180d6925 ->
case 0x7588550f ->
name.equalsString(NAME_RUNTIME_INVISIBLE_ANNOTATIONS) ? runtimeInvisibleAnnotations() : null;
case 0x7be22752 ->
case 0xcc74da30 ->
name.equalsString(NAME_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS) ? runtimeInvisibleParameterAnnotations() : null;
case 0x5299824 ->
case 0xf67697f5 ->
name.equalsString(NAME_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS) ? runtimeInvisibleTypeAnnotations() : null;
case 0x3534786e ->
case 0xe0837d2a ->
name.equalsString(NAME_RUNTIME_VISIBLE_ANNOTATIONS) ? runtimeVisibleAnnotations() : null;
case 0xb4b4ac6 ->
case 0xc945a075 ->
name.equalsString(NAME_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS) ? runtimeVisibleParameterAnnotations() : null;
case 0x6926482 ->
case 0x611a3a90 ->
name.equalsString(NAME_RUNTIME_VISIBLE_TYPE_ANNOTATIONS) ? runtimeVisibleTypeAnnotations() : null;
case 0x16a42b7c ->
case 0xf76fb898 ->
name.equalsString(NAME_SIGNATURE) ? signature() : null;
case 0x400ab245 ->
case 0x6b41b047 ->
name.equalsString(NAME_SOURCE_DEBUG_EXTENSION) ? sourceDebugExtension() : null;
case 0x2af490d4 ->
case 0x748c2857 ->
name.equalsString(NAME_SOURCE_FILE) ? sourceFile() : null;
case 0x303e0c58 ->
case 0x6bf13a96 ->
name.equalsString(NAME_SOURCE_ID) ? sourceId() : null;
case 0x19c7d0cd ->
case 0xfa85ee5a ->
name.equalsString(NAME_STACK_MAP_TABLE) ? stackMapTable() : null;
case 0x3dc79b7a ->
case 0xf2670725 ->
name.equalsString(NAME_SYNTHETIC) ? synthetic() : null;
default -> null;
};

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -43,7 +43,7 @@ import java.util.Optional;
import java.util.function.Consumer;
public final class BufferedCodeBuilder
implements TerminalCodeBuilder, LabelContext {
implements TerminalCodeBuilder {
private final SplitConstantPool constantPool;
private final ClassFileImpl context;
private final List<CodeElement> elements = new ArrayList<>();

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -33,13 +33,11 @@ import java.lang.classfile.constantpool.Utf8Entry;
public final class ChainedClassBuilder
implements ClassBuilder, Consumer<ClassElement> {
private final ClassBuilder downstream;
private final DirectClassBuilder terminal;
private final Consumer<ClassElement> consumer;
public ChainedClassBuilder(ClassBuilder downstream,
Consumer<ClassElement> consumer) {
this.downstream = downstream;
this.consumer = consumer;
this.terminal = switch (downstream) {
case ChainedClassBuilder cb -> cb.terminal;
@@ -60,10 +58,11 @@ public final class ChainedClassBuilder
@Override
public ClassBuilder withField(Utf8Entry name, Utf8Entry descriptor, Consumer<? super FieldBuilder> handler) {
return downstream.with(new BufferedFieldBuilder(terminal.constantPool, terminal.context,
consumer.accept(new BufferedFieldBuilder(terminal.constantPool, terminal.context,
name, descriptor, null)
.run(handler)
.toModel());
return this;
}
@Override
@@ -72,16 +71,18 @@ public final class ChainedClassBuilder
field.fieldName(), field.fieldType(),
field);
builder.transform(field, transform);
return downstream.with(builder.toModel());
consumer.accept(builder.toModel());
return this;
}
@Override
public ClassBuilder withMethod(Utf8Entry name, Utf8Entry descriptor, int flags,
Consumer<? super MethodBuilder> handler) {
return downstream.with(new BufferedMethodBuilder(terminal.constantPool, terminal.context,
consumer.accept(new BufferedMethodBuilder(terminal.constantPool, terminal.context,
name, descriptor, null)
.run(handler)
.toModel());
return this;
}
@Override
@@ -89,7 +90,8 @@ public final class ChainedClassBuilder
BufferedMethodBuilder builder = new BufferedMethodBuilder(terminal.constantPool, terminal.context,
method.methodName(), method.methodType(), method);
builder.transform(method, transform);
return downstream.with(builder.toModel());
consumer.accept(builder.toModel());
return this;
}
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -36,13 +36,11 @@ import java.lang.classfile.MethodModel;
import java.lang.classfile.constantpool.ConstantPoolBuilder;
public final class ChainedMethodBuilder implements MethodBuilder {
final MethodBuilder downstream;
final TerminalMethodBuilder terminal;
final Consumer<MethodElement> consumer;
public ChainedMethodBuilder(MethodBuilder downstream,
Consumer<MethodElement> consumer) {
this.downstream = downstream;
this.consumer = consumer;
this.terminal = switch (downstream) {
case ChainedMethodBuilder cb -> cb.terminal;
@@ -58,16 +56,18 @@ public final class ChainedMethodBuilder implements MethodBuilder {
@Override
public MethodBuilder withCode(Consumer<? super CodeBuilder> handler) {
return downstream.with(terminal.bufferedCodeBuilder(null)
consumer.accept(terminal.bufferedCodeBuilder(null)
.run(handler)
.toModel());
return this;
}
@Override
public MethodBuilder transformCode(CodeModel code, CodeTransform transform) {
BufferedCodeBuilder builder = terminal.bufferedCodeBuilder(code);
builder.transform(code, transform);
return downstream.with(builder.toModel());
consumer.accept(builder.toModel());
return this;
}
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -75,7 +75,7 @@ import static java.lang.classfile.Opcode.LDC_W;
public final class DirectCodeBuilder
extends AbstractDirectBuilder<CodeModel>
implements TerminalCodeBuilder, LabelContext {
implements TerminalCodeBuilder {
private final List<CharacterRange> characterRanges = new ArrayList<>();
final List<AbstractPseudoInstruction.ExceptionCatchImpl> handlers = new ArrayList<>();
private final List<LocalVariable> localVariables = new ArrayList<>();

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -27,7 +27,7 @@ package jdk.internal.classfile.impl;
import java.lang.classfile.Label;
public sealed interface LabelContext
permits BufferedCodeBuilder, CodeImpl, DirectCodeBuilder {
permits TerminalCodeBuilder, CodeImpl {
Label newLabel();
Label getLabel(int bci);
void setLabelTarget(Label label, int bci);

View File

@@ -1047,7 +1047,7 @@ public final class StackMapGenerator {
void setLocalsFromArg(String name, MethodTypeDesc methodDesc, boolean isStatic, Type thisKlass) {
int localsSize = 0;
// Pre-emptively create a locals array that encompass all parameter slots
checkLocal(methodDesc.parameterCount() + (isStatic ? 0 : -1));
checkLocal(methodDesc.parameterCount() + (isStatic ? -1 : 0));
if (!isStatic) {
localsSize++;
if (OBJECT_INITIALIZER_NAME.equals(name) && !CD_Object.equals(thisKlass.sym)) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -26,7 +26,7 @@ package jdk.internal.classfile.impl;
import java.lang.classfile.CodeBuilder;
public sealed interface TerminalCodeBuilder extends CodeBuilder
permits DirectCodeBuilder, BufferedCodeBuilder, TransformingCodeBuilder {
public sealed interface TerminalCodeBuilder extends CodeBuilder, LabelContext
permits DirectCodeBuilder, BufferedCodeBuilder {
int curTopLocal();
}

View File

@@ -1,91 +0,0 @@
/*
* Copyright (c) 2022, 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 jdk.internal.classfile.impl;
import java.lang.classfile.CodeBuilder;
import java.lang.classfile.CodeModel;
import java.util.Optional;
import java.util.function.Consumer;
import java.lang.classfile.CodeElement;
import java.lang.classfile.Label;
import java.lang.classfile.TypeKind;
import java.lang.classfile.constantpool.ConstantPoolBuilder;
public final class TransformingCodeBuilder implements TerminalCodeBuilder {
final CodeBuilder delegate;
final Consumer<CodeElement> consumer;
public TransformingCodeBuilder(CodeBuilder delegate, Consumer<CodeElement> consumer) {
this.delegate = delegate;
this.consumer = consumer;
}
@Override
public CodeBuilder with(CodeElement e) {
consumer.accept(e);
return this;
}
@Override
public Optional<CodeModel> original() {
return delegate.original();
}
@Override
public Label newLabel() {
return delegate.newLabel();
}
@Override
public Label startLabel() {
return delegate.startLabel();
}
@Override
public Label endLabel() {
return delegate.endLabel();
}
@Override
public int receiverSlot() {
return delegate.receiverSlot();
}
@Override
public int parameterSlot(int paramNo) {
return delegate.parameterSlot(paramNo);
}
@Override
public int allocateLocal(TypeKind typeKind) {
return delegate.allocateLocal(typeKind);
}
@Override
public ConstantPoolBuilder constantPool() {
return delegate.constantPool();
}
}

View File

@@ -159,7 +159,7 @@ public abstract sealed class AbstractMemorySegmentImpl
() -> cleanup.accept(SegmentFactories.makeNativeSegmentUnchecked(address(), newSize)) :
null;
return SegmentFactories.makeNativeSegmentUnchecked(address(), newSize,
(MemorySessionImpl)scope, action);
(MemorySessionImpl)scope, readOnly, action);
}
private AbstractMemorySegmentImpl asSliceNoCheck(long offset, long newSize) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 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
@@ -57,14 +57,18 @@ public class SegmentFactories {
// associated with MemorySegment::ofAddress.
@ForceInline
public static MemorySegment makeNativeSegmentUnchecked(long min, long byteSize, MemorySessionImpl sessionImpl, Runnable action) {
public static MemorySegment makeNativeSegmentUnchecked(long min,
long byteSize,
MemorySessionImpl sessionImpl,
boolean readOnly,
Runnable action) {
ensureInitialized();
if (action == null) {
sessionImpl.checkValidState();
} else {
sessionImpl.addCloseAction(action);
}
return new NativeMemorySegmentImpl(min, byteSize, false, sessionImpl);
return new NativeMemorySegmentImpl(min, byteSize, readOnly, sessionImpl);
}
@ForceInline

View File

@@ -165,6 +165,7 @@ module java.base {
java.desktop,
java.logging,
java.management,
java.management.rmi,
java.naming,
java.rmi,
jdk.charsets,

View File

@@ -1,5 +1,5 @@
#
# Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2007, 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
@@ -35,7 +35,7 @@ native Agent Library <libname>. Beispiel: -agentlib:jdwp\n sieh
# Translators please note do not translate the options themselves
java.launcher.X.usage=\n -Xbatch Deaktiviert die Hintergrundkompilierung\n -Xbootclasspath/a:<durch {0} getrennte Verzeichnisse und ZIP-/JAR-Dateien>\n An das Ende des Bootstrap Classpaths anhängen\n -Xcheck:jni Führt zusätzliche Prüfungen für JNI-Funktionen aus\n -Xcomp Erzwingt die Kompilierung von Methoden beim ersten Aufruf\n -Xdebug Führt keine Aktion aus. Ist veraltet und wird in einem zukünftigen Release entfernt.\n -Xdiag Zeigt zusätzliche Diagnosemeldungen an\n -Xfuture Aktiviert strengste Prüfungen, als möglicher zukünftiger Standardwert erwartet.\n Diese Option ist veraltet und kann in einem\n zukünftigen Release entfernt werden.\n -Xint Nur Ausführung im interpretierten Modus\n -Xinternalversion\n Zeigt detailliertere JVM-Versionsinformationen an als die\n Option -version\n -Xlog:<Optionen> Konfiguriert oder aktiviert Logging mit dem einheitlichen Java Virtual\n Machine-(JVM-)Logging-Framework. Verwenden Sie -Xlog:help\n für weitere Einzelheiten.\n -Xloggc:<Datei> Protokolliert den GC-Status in einer Datei mit Zeitstempeln.\n Diese Option ist veraltet und kann in einem\n zukünftigen Release entfernt werden. Wird durch -Xlog:gc:<Datei> ersetzt.\n -Xmixed Ausführung im gemischten Modus (Standard)\n -Xmn<Größe> Legt die anfängliche und maximale Größe (in Byte) des Heaps\n für die Young Generation (Nursery) fest\n -Xms<Größe> Legt die anfängliche Java-Heap-Größe fest\n -Xmx<Größe> Legt die maximale Java-Heap-Größe fest\n -Xnoclassgc Deaktiviert die Klassen-Garbage Collection\n -Xrs Reduziert die Verwendung von BS-Signalen durch Java/VM (siehe Dokumentation)\n -Xshare:auto Verwendet freigegebene Klassendaten, wenn möglich (Standard)\n -Xshare:off Versucht nicht, freigegebene Klassendaten zu verwenden\n -Xshare:on Erfordert die Verwendung freigegebener Klassendaten, verläuft sonst nicht erfolgreich.\n Diese Testoption kann zeitweise zu\n Fehlern führen. Sie darf nicht in Produktionsumgebungen verwendet werden.\n -XshowSettings Zeigt alle Einstellungen an und fährt fort\n -XshowSettings:all\n Zeigt alle Einstellungen als Verbose-Ausgabe an und fährt fort\n -XshowSettings:locale\n Zeigt alle gebietsschemabezogenen Einstellungen an und fährt fort\n -XshowSettings:properties\n Zeigt alle Eigenschaftseinstellungen an und fährt fort\n -XshowSettings:vm\n Zeigt alle VM-bezogenen Einstellungen an und fährt fort\n -XshowSettings:security\n Zeigt alle Sicherheitseinstellungen an und fährt fort\n -XshowSettings:security:all\n Zeigt alle Sicherheitseinstellungen an und fährt fort\n -XshowSettings:security:properties\n Zeigt Sicherheitseigenschaften an und fährt fort\n -XshowSettings:security:providers\n Zeigt statische Sicherheitsprovidereinstellungen an und fährt fort\n -XshowSettings:security:tls\n Zeigt TLS-bezogene Sicherheitseinstellungen an und fährt fort\n -XshowSettings:system\n (Nur Linux) Zeigt die Konfiguration des Hostsystems oder Containers an\n und fährt fort\n -Xss<Größe> Legt die Stackgröße des Java-Threads fest\n Die tatsächliche \
Größe kann auf ein Vielfaches der\n Systemseitengröße aufgerundet werden, wenn für das Betriebssystem erforderlich.\n -Xverify Legt den Modus der Bytecodeverifizierung fest\n Beachten Sie, dass die Option -Xverify:none veraltet ist und\n in einem zukünftigen Release entfernt werden kann.\n --add-reads <Modul>=<Zielmodul>(,<Zielmodul>)*\n Aktualisiert <Modul>, damit <Zielmodul> gelesen wird, ungeachtet\n der Moduldeklaration. \n <Zielmodul> kann ALL-UNNAMED sein, um alle unbenannten\n Module zu lesen.\n --add-exports <Modul>/<Package>=<Zielmodul>(,<Zielmodul>)*\n Aktualisiert <Modul>, um <Package> in <Zielmodul> zu exportieren,\n ungeachtet der Moduldeklaration.\n <Zielmodul> kann ALL-UNNAMED sein, um in alle\n unbenannten Module zu exportieren.\n --add-opens <Modul>/<Package>=<Zielmodul>(,<Zielmodul>)*\n Aktualisiert <Modul>, um <Package> in\n <Zielmodul> zu öffnen, ungeachtet der Moduldeklaration.\n --limit-modules <Modulname>[,<Modulname>...]\n Grenzt die Gesamtmenge der beobachtbaren Module ein\n --patch-module <Modul>=<Datei>({0}<Datei>)*\n Überschreibt oder erweitert ein Modul mit Klassen und Ressourcen\n in JAR-Dateien oder Verzeichnissen.\n --source <Version>\n Legt die Version der Quelle im Quelldateimodus fest.\n --finalization=<Wert>\n Steuert, ob die JVM Objekte finalisiert.\n Dabei ist <Wert> entweder "enabled" oder "disabled".\n Die Finalisierung ist standardmäßig aktiviert.\n\nDiese zusätzlichen Optionen können jederzeit ohne vorherige Ankündigung geändert werden.\n
Größe kann auf ein Vielfaches der\n Systemseitengröße aufgerundet werden, wenn für das Betriebssystem erforderlich.\n -Xverify Legt den Modus der Bytecodeverifizierung fest\n Beachten Sie, dass die Option -Xverify:none veraltet ist und\n in einem zukünftigen Release entfernt werden kann.\n --add-reads <Modul>=<Zielmodul>(,<Zielmodul>)*\n Aktualisiert <Modul>, damit <Zielmodul> gelesen wird, ungeachtet\n der Moduldeklaration. \n <Zielmodul> kann ALL-UNNAMED sein, um alle unbenannten\n Module zu lesen.\n --add-exports <Modul>/<Package>=<Zielmodul>(,<Zielmodul>)*\n Aktualisiert <Modul>, um <Package> in <Zielmodul> zu exportieren,\n ungeachtet der Moduldeklaration.\n <Zielmodul> kann ALL-UNNAMED sein, um in alle\n unbenannten Module zu exportieren.\n --add-opens <Modul>/<Package>=<Zielmodul>(,<Zielmodul>)*\n Aktualisiert <Modul>, um <Package> in\n <Zielmodul> zu öffnen, ungeachtet der Moduldeklaration.\n --limit-modules <Modulname>[,<Modulname>...]\n Grenzt die Gesamtmenge der beobachtbaren Module ein\n --patch-module <Modul>=<Datei>({0}<Datei>)*\n Überschreibt oder erweitert ein Modul mit Klassen und Ressourcen\n in JAR-Dateien oder Verzeichnissen.\n --source <Version>\n Legt die Version der Quelle im Quelldateimodus fest.\n --finalization=<Wert>\n Steuert, ob die JVM Objekte finalisiert.\n Dabei ist <Wert> entweder "enabled" oder "disabled".\n Die Finalisierung ist standardmäßig aktiviert.\n --sun-misc-unsafe-memory-access=<value>\n Verwendung der nicht unterstützten API sun.misc.Unsafe zulassen oder verweigern\n <value> ist "allow", "warn", "debug" oder "deny".\n Der Standardwert ist "allow".\n\nDiese zusätzlichen Optionen können jederzeit ohne vorherige Ankündigung geändert werden.\n
# Translators please note do not translate the options themselves
java.launcher.X.macosx.usage=\nDie folgenden Optionen sind für macOS spezifisch:\n -XstartOnFirstThread\n Führt die main()-Methode für den ersten (AppKit-)Thread aus\n -Xdock:name=<Anwendungsname>\n Setzt den im Dock angezeigten Standardanwendungsnamen außer Kraft\n -Xdock:icon=<Pfad zu Symboldatei>\n Setzt das im Dock angezeigte Standardsymbol außer Kraft\n\n
@@ -52,6 +52,7 @@ java.launcher.jar.error1=Fehler: Beim Versuch, Datei {0} zu öffnen, ist ein une
java.launcher.jar.error2=Manifest in {0} nicht gefunden
java.launcher.jar.error3=kein Hauptmanifestattribut, in {0}
java.launcher.jar.error4=Fehler beim Laden des Java-Agents in {0}
java.launcher.jar.error5=Fehler: Beim Versuch, Datei {0} zu schließen, ist ein unerwarteter Fehler aufgetreten
java.launcher.jar.error.illegal.ena.value=Fehler: Ungültiger Wert "{0}" für das Manifestattribut "Enable-Native-Access". Nur ''ALL-UNNAMED'' ist zulässig
java.launcher.init.error=Initialisierungsfehler
java.launcher.javafx.error1=Fehler: Die JavaFX-Methode launchApplication hat die falsche Signatur, sie\nmuss als statisch deklariert werden und einen Wert vom Typ VOID zurückgeben

View File

@@ -1,5 +1,5 @@
#
# Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2007, 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
@@ -37,7 +37,7 @@ java.launcher.opt.footer = \ -cp <ディレクトリおよびzip/jarファイ
# Translators please note do not translate the options themselves
java.launcher.X.usage=\n -Xbatch バックグラウンド・コンパイルを無効にします\n -Xbootclasspath/a:<directories and zip/jar files separated by {0}>\n ブートストラップ・クラス・パスの最後に追加します\n -Xcheck:jni JNI関数に対する追加のチェックを実行します\n -Xcomp 初回呼出し時にメソッドのコンパイルを強制します\n -Xdebug 何も実行されません。将来のリリースで削除されるため、非推奨になりました。\n -Xdiag 追加の診断メッセージを表示します\n -Xfuture 将来のデフォルトを見越して、最も厳密なチェックを有効にします\n このオプションは非推奨であり、将来のリリースで削除される\n 可能性があります。\n -Xint インタプリタ・モードの実行のみ\n -Xinternalversion\n -versionオプションより詳細なJVMバージョン情報を\n 表示します\n -Xlog:<opts> Java Virtual Machine (JVM)統合ロギング・フレームワークでの\n ロギングを構成または有効化します。詳細は、-Xlog:helpを\n 使用してください。\n -Xloggc:<file> タイムスタンプが付いたファイルにGCステータスのログを記録します\n このオプションは非推奨であり、将来のリリースで削除される\n 可能性があります。-Xlog:gc:<file>で置換されています。\n -Xmixed 混合モードの実行(デフォルト)\n -Xmn<size> 若い世代(ナーサリ)のヒープの初期サイズおよび最大サイズ\n (バイト単位)を設定します\n -Xms<size> Javaの初期ヒープ・サイズを設定します\n -Xmx<size> Javaの最大ヒープ・サイズを設定します\n -Xnoclassgc クラスのガベージ・コレクションを無効にします\n -Xrs Java/VMによるOSシグナルの使用を削減します(ドキュメントを参照)\n -Xshare:auto 可能であれば共有クラス・データを使用します(デフォルト)\n -Xshare:off \
共有クラス・データの使用を試みません\n -Xshare:on 共有クラス・データの使用を必須にし、できなければ失敗します。\n これはテスト・オプションであり、断続的な失敗につながる\n 可能性があります。本番環境では使用しないでください。\n -XshowSettings すべての設定を表示して続行します\n -XshowSettings:all\n すべての設定を詳細に表示して続行します\n -XshowSettings:locale\n すべてのロケール関連の設定を表示して続行します\n -XshowSettings:properties\n すべてのプロパティ設定を表示して続行します\n -XshowSettings:vm\n すべてのVM関連の設定を表示して続行します\n -XshowSettings:security\n すべてのセキュリティ設定を表示して続行します\n -XshowSettings:security:all\n すべてのセキュリティ設定を表示して続行します\n -XshowSettings:security:properties\n セキュリティ・プロパティを表示して続行します\n -XshowSettings:security:providers\n 静的セキュリティ・プロバイダ設定を表示して続行します\n -XshowSettings:security:tls\n TLS関連のセキュリティ設定を表示して続行します\n -XshowSettings:system\n (Linuxのみ)ホスト・システムまたはコンテナを表示します\n 構成して続行します\n -Xss<size> javaスレッドのスタック・サイズを設定します\n 実際のサイズは、次の倍数に切り上げられる場合があります: \n オペレーティング・システムの要件に応じたシステム・ページ・サイズ。\n -Xverify バイトコード・ベリファイアのモードを設定します\n オプション-Xverify:noneは非推奨になり、\n 将来のリリースで削除される可能性があります。\n --add-reads <module>=<target-module>(,<target-module>)*\n モジュール宣言に関係なく、<module>を更新して<target-module>を\n \
読み取ります。 \n <target-module>をALL-UNNAMEDに設定すると、すべての名前のないモジュールを\n 読み取ることができます。\n --add-exports <module>/<package>=<target-module>(,<target-module>)*\n モジュール宣言に関係なく、<module>を更新して<package>を<target-module>に\n エクスポートします。\n <target-module>をALL-UNNAMEDに設定すると、すべての名前のないモジュールに\n エクスポートできます。\n --add-opens <module>/<package>=<target-module>(,<target-module>)*\n モジュール宣言に関係なく、<module>を更新して<package>を\n <target-module>に開きます。\n --limit-modules <module name>[,<module name>...]\n 参照可能なモジュールの領域を制限します\n --patch-module <module>=<file>({0}<file>)*\n JARファイルまたはディレクトリのクラスおよびリソースで\n モジュールをオーバーライドまたは拡張します。\n --source <version>\n ソースファイル・モードでソースのバージョンを設定します。\n --finalization=<value>\n JVMがオブジェクトのファイナライズを実行するかどうかを制御します\n <value>は"enabled"または"disabled"のいずれかです。\n ファイナライズはデフォルトで有効になっています。\n\nこの追加オプションは予告なしに変更されることがあります。\n
読み取ります。 \n <target-module>をALL-UNNAMEDに設定すると、すべての名前のないモジュールを\n 読み取ることができます。\n --add-exports <module>/<package>=<target-module>(,<target-module>)*\n モジュール宣言に関係なく、<module>を更新して<package>を<target-module>に\n エクスポートします。\n <target-module>をALL-UNNAMEDに設定すると、すべての名前のないモジュールに\n エクスポートできます。\n --add-opens <module>/<package>=<target-module>(,<target-module>)*\n モジュール宣言に関係なく、<module>を更新して<package>を\n <target-module>に開きます。\n --limit-modules <module name>[,<module name>...]\n 参照可能なモジュールの領域を制限します\n --patch-module <module>=<file>({0}<file>)*\n JARファイルまたはディレクトリのクラスおよびリソースで\n モジュールをオーバーライドまたは拡張します。\n --source <version>\n ソースファイル・モードでソースのバージョンを設定します。\n --finalization=<value>\n JVMがオブジェクトのファイナライズを実行するかどうかを制御します\n <value>は"enabled"または"disabled"のいずれかです。\n ファイナライズはデフォルトで有効になっています。\n --sun-misc-unsafe-memory-access=<value>\n サポートされていないAPI sun.misc.Unsafeの使用を許可または拒否します\n <value>は"allow"、"warn"、"debug"または"deny"のいずれかです。\n デフォルト値は、"allow"です。\n\nこの追加オプションは予告なしに変更されることがあります。\n
# Translators please note do not translate the options themselves
java.launcher.X.macosx.usage=\n次のオプションはmacOS固有です:\n -XstartOnFirstThread\n main()メソッドを最初(AppKit)のスレッドで実行する\n -Xdock:name=<application name>\n Dockに表示されるデフォルト・アプリケーション名をオーバーライドする\n -Xdock:icon=<path to icon file>\n Dockに表示されるデフォルト・アイコンをオーバーライドする\n\n
@@ -54,6 +54,7 @@ java.launcher.jar.error1=エラー: ファイル{0}を開こうとしている
java.launcher.jar.error2={0}にマニフェストが見つかりません
java.launcher.jar.error3={0}にメイン・マニフェスト属性がありません
java.launcher.jar.error4={0}内のJavaエージェントのロード中にエラーが発生しました
java.launcher.jar.error5=エラー: ファイル{0}を閉じるときに、予期しないエラーが発生しました
java.launcher.jar.error.illegal.ena.value=エラー: Enable-Native-Accessマニフェスト属性の値"{0}"が不正です。''ALL-UNNAMED''のみ許可されます
java.launcher.init.error=初期化エラー
java.launcher.javafx.error1=エラー: JavaFX launchApplicationメソッドに誤ったシグネチャがあり、\nstaticを宣言してvoid型の値を返す必要があります

View File

@@ -1,5 +1,5 @@
#
# Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2007, 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
@@ -35,7 +35,7 @@ java.launcher.opt.footer = \ -cp <目录和 zip/jar 文件的类搜索路径>
# Translators please note do not translate the options themselves
java.launcher.X.usage=\n -Xbatch 禁用后台编译\n -Xbootclasspath/a:<以 {0} 分隔的目录和 zip/jar 文件>\n 附加在引导类路径末尾\n -Xcheck:jni 对 JNI 函数执行其他检查\n -Xcomp 强制在首次调用时编译方法\n -Xdebug 不执行任何操作;已过时,将在未来发行版中删除。\n -Xdiag 显示附加诊断消息\n -Xfuture 启用最严格的检查,预期将来的默认值。\n 此选项已过时,可能会在\n 未来发行版中删除。\n -Xint 仅解释模式执行\n -Xinternalversion\n 显示比 -version 选项更详细的\n JVM 版本信息\n -Xlog:<opts> 配置或启用采用 Java 虚拟\n 机 (Java Virtual Machine, JVM) 统一记录框架进行事件记录。使用 -Xlog:help\n 可了解详细信息。\n -Xloggc:<file> 将 GC 状态记录在文件中(带时间戳)。\n 此选项已过时,可能会在\n 将来的发行版中删除。它将替换为 -Xlog:gc:<file>。\n -Xmixed 混合模式执行(默认值)\n -Xmn<size> 为年轻代(新生代)设置初始和最大堆大小\n (以字节为单位)\n -Xms<size> 设置初始 Java 堆大小\n -Xmx<size> 设置最大 Java 堆大小\n -Xnoclassgc 禁用类垃圾收集\n -Xrs 减少 Java/VM 对操作系统信号的使用(请参见文档)\n -Xshare:auto 在可能的情况下使用共享类数据(默认值)\n -Xshare:off 不尝试使用共享类数据\n -Xshare:on 要求使用共享类数据,否则将失败。\n 这是一个测试选项,可能导致间歇性\n 故障。不应在生产环境中使用它。\n -XshowSettings 显示所有设置并继续\n -XshowSettings:all\n 详细显示所有设置并继续\n -XshowSettings:locale\n 显示所有与区域设置相关的设置并继续\n -XshowSettings:properties\n 显示所有属性设置并继续\n -XshowSettings:vm\n 显示所有与 vm 相关的设置并继续\n -XshowSettings:security\n 显示所有安全设置并继续\n -XshowSettings:security:all\n 显示所有安全设置并继续\n -XshowSettings:security:properties\n \
显示安全属性并继续\n -XshowSettings:security:providers\n 显示静态安全提供方设置并继续\n -XshowSettings:security:tls\n 显示与 TLS 相关的安全设置并继续\n -XshowSettings:system\n (仅 Linux显示主机系统或容器\n 配置并继续\n -Xss<size> 设置 Java 线程堆栈大小\n 实际大小可以舍入到\n 操作系统要求的系统页面大小的倍数。\n -Xverify 设置字节码验证器的模式\n 请注意,选项 -Xverify:none 已过时,\n 可能会在未来发行版中删除。\n --add-reads <module>=<target-module>(,<target-module>)*\n 更新 <module> 以读取 <target-module>,而无论\n 模块如何声明。 \n <target-module> 可以是 ALL-UNNAMED将读取所有未命名\n 模块。\n --add-exports <module>/<package>=<target-module>(,<target-module>)*\n 更新 <module> 以将 <package> 导出到 <target-module>\n 而无论模块如何声明。\n <target-module> 可以是 ALL-UNNAMED将导出到所有\n 未命名模块。\n --add-opens <module>/<package>=<target-module>(,<target-module>)*\n 更新 <module> 以在 <target-module> 中打开\n <package>,而无论模块如何声明。\n --limit-modules <module name>[,<module name>...]\n 限制可观察模块的领域\n --patch-module <module>=<file>({0}<file>)*\n 使用 JAR 文件或目录中的类和资源\n 覆盖或增强模块。\n --source <version>\n 设置源文件模式中源的版本。\n --finalization=<value>\n 控制 JVM 是否执行对象最终处理,\n 其中 <value> 为 "enabled" 或 "disabled" 之一。\n 默认情况下,最终处理处于启用状态。\n\n这些额外选项如有更改, 恕不另行通知。\n
显示安全属性并继续\n -XshowSettings:security:providers\n 显示静态安全提供方设置并继续\n -XshowSettings:security:tls\n 显示与 TLS 相关的安全设置并继续\n -XshowSettings:system\n (仅 Linux显示主机系统或容器\n 配置并继续\n -Xss<size> 设置 Java 线程堆栈大小\n 实际大小可以舍入到\n 操作系统要求的系统页面大小的倍数。\n -Xverify 设置字节码验证器的模式\n 请注意,选项 -Xverify:none 已过时,\n 可能会在未来发行版中删除。\n --add-reads <module>=<target-module>(,<target-module>)*\n 更新 <module> 以读取 <target-module>,而无论\n 模块如何声明。 \n <target-module> 可以是 ALL-UNNAMED将读取所有未命名\n 模块。\n --add-exports <module>/<package>=<target-module>(,<target-module>)*\n 更新 <module> 以将 <package> 导出到 <target-module>\n 而无论模块如何声明。\n <target-module> 可以是 ALL-UNNAMED将导出到所有\n 未命名模块。\n --add-opens <module>/<package>=<target-module>(,<target-module>)*\n 更新 <module> 以在 <target-module> 中打开\n <package>,而无论模块如何声明。\n --limit-modules <module name>[,<module name>...]\n 限制可观察模块的领域\n --patch-module <module>=<file>({0}<file>)*\n 使用 JAR 文件或目录中的类和资源\n 覆盖或增强模块。\n --source <version>\n 设置源文件模式中源的版本。\n --finalization=<value>\n 控制 JVM 是否执行对象最终处理,\n 其中 <value> 为 "enabled" 或 "disabled" 之一。\n 默认情况下,最终处理处于启用状态。\n --sun-misc-unsafe-memory-access=<value>\n 允许或拒绝使用不受支持的 API sun.misc.Unsafe\n <value> 为 "allow"、"warn"、"debug" 或 "deny" 之一。\n 默认值为 "allow"。\n\n这些额外选项如有更改, 恕不另行通知。\n
# Translators please note do not translate the options themselves
java.launcher.X.macosx.usage=\n以下选项是特定于 macOS 的选项:\n -XstartOnFirstThread\n 在第一个 (AppKit) 线程上运行 main() 方法\n -Xdock:name=<application name>\n 覆盖停靠栏中显示的默认应用程序名称\n -Xdock:icon=<path to icon file>\n 覆盖停靠栏中显示的默认图标\n\n
@@ -52,6 +52,7 @@ java.launcher.jar.error1=错误: 尝试打开文件{0}时出现意外错误
java.launcher.jar.error2=在{0}中找不到清单
java.launcher.jar.error3={0}中没有主清单属性
java.launcher.jar.error4=在 {0} 中加载 Java 代理时出错
java.launcher.jar.error5=错误:尝试关闭文件 {0} 时出现意外错误
java.launcher.jar.error.illegal.ena.value=错误Enable-Native-Access 清单属性的值 "{0}" 非法。仅允许使用 ''ALL-UNNAMED''
java.launcher.init.error=初始化错误
java.launcher.javafx.error1=错误: JavaFX launchApplication 方法具有错误的签名, 必须\n将方法声明为静态方法并返回空类型的值

View File

@@ -806,14 +806,19 @@ class DatagramChannelImpl
}
}
/**
* Receives a datagram into a direct buffer.
*/
private int receiveIntoNativeBuffer(ByteBuffer bb, int rem, int pos,
boolean connected)
throws IOException
{
NIO_ACCESS.acquireSession(bb);
try {
long bufAddress = NIO_ACCESS.getBufferAddress(bb);
int n = receive0(fd,
((DirectBuffer)bb).address() + pos, rem,
bufAddress + pos,
rem,
sourceSockAddr.address(),
connected);
if (n > 0)
@@ -991,6 +996,9 @@ class DatagramChannelImpl
}
}
/**
* Send a datagram contained in a direct buffer.
*/
private int sendFromNativeBuffer(FileDescriptor fd, ByteBuffer bb,
InetSocketAddress target)
throws IOException
@@ -1003,9 +1011,13 @@ class DatagramChannelImpl
int written;
NIO_ACCESS.acquireSession(bb);
try {
long bufAddress = NIO_ACCESS.getBufferAddress(bb);
int addressLen = targetSocketAddress(target);
written = send0(fd, ((DirectBuffer)bb).address() + pos, rem,
targetSockAddr.address(), addressLen);
written = send0(fd,
bufAddress + pos,
rem,
targetSockAddr.address(),
addressLen);
} catch (PortUnreachableException pue) {
if (isConnected())
throw pue;
@@ -1933,6 +1945,11 @@ class DatagramChannelImpl
@Override
public void kill() {
// wait for any read/write operations to complete before trying to close
readLock.lock();
readLock.unlock();
writeLock.lock();
writeLock.unlock();
synchronized (stateLock) {
if (state == ST_CLOSING) {
tryFinishClose();

View File

@@ -654,6 +654,9 @@ class ServerSocketChannelImpl
@Override
public void kill() {
// wait for any accept operation to complete before trying to close
acceptLock.lock();
acceptLock.unlock();
synchronized (stateLock) {
if (state == ST_CLOSING) {
tryFinishClose();

Some files were not shown because too many files have changed in this diff Show More