diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
index abdda7dfa30..86784d07b25 100644
--- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
@@ -723,7 +723,7 @@ void MacroAssembler::emit_static_call_stub() {
isb();
mov_metadata(rmethod, (Metadata*)NULL);
- // Jump to the entry point of the i2c stub.
+ // Jump to the entry point of the c2i stub.
movptr(rscratch1, 0);
br(rscratch1);
}
diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
index 288d8c21730..7764c791a14 100644
--- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
@@ -1013,22 +1013,65 @@ static void gen_continuation_enter(MacroAssembler* masm,
int& exception_offset,
OopMapSet*oop_maps,
int& frame_complete,
- int& stack_slots) {
+ int& stack_slots,
+ int& interpreted_entry_offset,
+ int& compiled_entry_offset) {
//verify_oop_args(masm, method, sig_bt, regs);
- Address resolve(SharedRuntime::get_resolve_static_call_stub(),
- relocInfo::static_call_type);
+ Address resolve(SharedRuntime::get_resolve_static_call_stub(), relocInfo::static_call_type);
- stack_slots = 2; // will be overwritten
address start = __ pc();
Label call_thaw, exit;
+ // i2i entry used at interp_only_mode only
+ interpreted_entry_offset = __ pc() - start;
+ {
+
+#ifdef ASSERT
+ Label is_interp_only;
+ __ ldrw(rscratch1, Address(rthread, JavaThread::interp_only_mode_offset()));
+ __ cbnzw(rscratch1, is_interp_only);
+ __ stop("enterSpecial interpreter entry called when not in interp_only_mode");
+ __ bind(is_interp_only);
+#endif
+
+ // Read interpreter arguments into registers (this is an ad-hoc i2c adapter)
+ __ ldr(c_rarg1, Address(esp, Interpreter::stackElementSize*2));
+ __ ldr(c_rarg2, Address(esp, Interpreter::stackElementSize*1));
+ __ ldr(c_rarg3, Address(esp, Interpreter::stackElementSize*0));
+ __ push_cont_fastpath(rthread);
+
+ __ enter();
+ stack_slots = 2; // will be adjusted in setup
+ OopMap* map = continuation_enter_setup(masm, stack_slots);
+ // The frame is complete here, but we only record it for the compiled entry, so the frame would appear unsafe,
+ // but that's okay because at the very worst we'll miss an async sample, but we're in interp_only_mode anyway.
+
+ fill_continuation_entry(masm);
+
+ __ cmp(c_rarg2, (u1)0);
+ __ br(Assembler::NE, call_thaw);
+
+ address mark = __ pc();
+ __ trampoline_call1(resolve, NULL, false);
+
+ oop_maps->add_gc_map(__ pc() - start, map);
+ __ post_call_nop();
+
+ __ b(exit);
+
+ CodeBuffer* cbuf = masm->code_section()->outer();
+ CompiledStaticCall::emit_to_interp_stub(*cbuf, mark);
+ }
+
+ // compiled entry
+ __ align(CodeEntryAlignment);
+ compiled_entry_offset = __ pc() - start;
+
__ enter();
-
+ stack_slots = 2; // will be adjusted in setup
OopMap* map = continuation_enter_setup(masm, stack_slots);
-
- // Frame is now completed as far as size and linkage.
- frame_complete =__ pc() - start;
+ frame_complete = __ pc() - start;
fill_continuation_entry(masm);
@@ -1036,7 +1079,6 @@ static void gen_continuation_enter(MacroAssembler* masm,
__ br(Assembler::NE, call_thaw);
address mark = __ pc();
-
__ trampoline_call1(resolve, NULL, false);
oop_maps->add_gc_map(__ pc() - start, map);
@@ -1079,7 +1121,7 @@ static void gen_continuation_enter(MacroAssembler* masm,
}
CodeBuffer* cbuf = masm->code_section()->outer();
- address stub = CompiledStaticCall::emit_to_interp_stub(*cbuf, mark);
+ CompiledStaticCall::emit_to_interp_stub(*cbuf, mark);
}
static void gen_special_dispatch(MacroAssembler* masm,
@@ -1169,11 +1211,12 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
if (method->is_continuation_enter_intrinsic()) {
vmIntrinsics::ID iid = method->intrinsic_id();
intptr_t start = (intptr_t)__ pc();
- int vep_offset = ((intptr_t)__ pc()) - start;
+ int vep_offset = 0;
int exception_offset = 0;
int frame_complete = 0;
int stack_slots = 0;
OopMapSet* oop_maps = new OopMapSet();
+ int interpreted_entry_offset = -1;
gen_continuation_enter(masm,
method,
in_sig_bt,
@@ -1181,7 +1224,9 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
exception_offset,
oop_maps,
frame_complete,
- stack_slots);
+ stack_slots,
+ interpreted_entry_offset,
+ vep_offset);
__ flush();
nmethod* nm = nmethod::new_native_nmethod(method,
compile_id,
@@ -1193,7 +1238,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
in_ByteSize(-1),
oop_maps,
exception_offset);
- ContinuationEntry::set_enter_code(nm);
+ ContinuationEntry::set_enter_code(nm, interpreted_entry_offset);
return nm;
}
diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp
index 937f0278af6..9b00600096e 100644
--- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp
+++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp
@@ -1276,7 +1276,9 @@ static void gen_continuation_enter(MacroAssembler* masm,
int& exception_offset,
OopMapSet* oop_maps,
int& frame_complete,
- int& stack_slots) {
+ int& stack_slots,
+ int& interpreted_entry_offset,
+ int& compiled_entry_offset) {
// enterSpecial(Continuation c, boolean isContinue, boolean isVirtualThread)
int pos_cont_obj = 0;
@@ -1298,8 +1300,68 @@ static void gen_continuation_enter(MacroAssembler* masm,
// Utility methods kill rax, make sure there are no collisions
assert_different_registers(rax, reg_cont_obj, reg_is_cont, reg_is_virtual);
+ AddressLiteral resolve(SharedRuntime::get_resolve_static_call_stub(),
+ relocInfo::static_call_type);
+
address start = __ pc();
+ Label L_thaw, L_exit;
+
+ // i2i entry used at interp_only_mode only
+ interpreted_entry_offset = __ pc() - start;
+ {
+#ifdef ASSERT
+ Label is_interp_only;
+ __ cmpb(Address(r15_thread, JavaThread::interp_only_mode_offset()), 0);
+ __ jcc(Assembler::notEqual, is_interp_only);
+ __ stop("enterSpecial interpreter entry called when not in interp_only_mode");
+ __ bind(is_interp_only);
+#endif
+
+ __ pop(rax); // return address
+ // Read interpreter arguments into registers (this is an ad-hoc i2c adapter)
+ __ movptr(c_rarg1, Address(rsp, Interpreter::stackElementSize*2));
+ __ movl(c_rarg2, Address(rsp, Interpreter::stackElementSize*1));
+ __ movl(c_rarg3, Address(rsp, Interpreter::stackElementSize*0));
+ __ andptr(rsp, -16); // Ensure compiled code always sees stack at proper alignment
+ __ push(rax); // return address
+ __ push_cont_fastpath();
+
+ __ enter();
+
+ stack_slots = 2; // will be adjusted in setup
+ OopMap* map = continuation_enter_setup(masm, stack_slots);
+ // The frame is complete here, but we only record it for the compiled entry, so the frame would appear unsafe,
+ // but that's okay because at the very worst we'll miss an async sample, but we're in interp_only_mode anyway.
+
+ __ verify_oop(reg_cont_obj);
+
+ fill_continuation_entry(masm, reg_cont_obj, reg_is_virtual);
+
+ // If continuation, call to thaw. Otherwise, resolve the call and exit.
+ __ testptr(reg_is_cont, reg_is_cont);
+ __ jcc(Assembler::notZero, L_thaw);
+
+ // --- Resolve path
+
+ // Make sure the call is patchable
+ __ align(BytesPerWord, __ offset() + NativeCall::displacement_offset);
+ // Emit stub for static call
+ CodeBuffer* cbuf = masm->code_section()->outer();
+ address stub = CompiledStaticCall::emit_to_interp_stub(*cbuf, __ pc());
+ if (stub == nullptr) {
+ fatal("CodeCache is full at gen_continuation_enter");
+ }
+ __ call(resolve);
+ oop_maps->add_gc_map(__ pc() - start, map);
+ __ post_call_nop();
+
+ __ jmp(L_exit);
+ }
+
+ // compiled entry
+ __ align(CodeEntryAlignment);
+ compiled_entry_offset = __ pc() - start;
__ enter();
stack_slots = 2; // will be adjusted in setup
@@ -1312,8 +1374,6 @@ static void gen_continuation_enter(MacroAssembler* masm,
fill_continuation_entry(masm, reg_cont_obj, reg_is_virtual);
- Label L_thaw, L_exit;
-
// If isContinue, call to thaw. Otherwise, call Continuation.enter(Continuation c, boolean isContinue)
__ testptr(reg_is_cont, reg_is_cont);
__ jccb(Assembler::notZero, L_thaw);
@@ -1334,8 +1394,6 @@ static void gen_continuation_enter(MacroAssembler* masm,
// SharedRuntime::find_callee_info_helper() which calls
// LinkResolver::resolve_continuation_enter() which resolves the call to
// Continuation.enter(Continuation c, boolean isContinue).
- AddressLiteral resolve(SharedRuntime::get_resolve_static_call_stub(),
- relocInfo::static_call_type);
__ call(resolve);
oop_maps->add_gc_map(__ pc() - start, map);
@@ -1474,17 +1532,20 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
if (method->is_continuation_enter_intrinsic()) {
vmIntrinsics::ID iid = method->intrinsic_id();
intptr_t start = (intptr_t)__ pc();
- int vep_offset = ((intptr_t)__ pc()) - start;
+ int vep_offset = 0;
int exception_offset = 0;
int frame_complete = 0;
int stack_slots = 0;
OopMapSet* oop_maps = new OopMapSet();
+ int interpreted_entry_offset = -1;
gen_continuation_enter(masm,
in_regs,
exception_offset,
oop_maps,
frame_complete,
- stack_slots);
+ stack_slots,
+ interpreted_entry_offset,
+ vep_offset);
__ flush();
nmethod* nm = nmethod::new_native_nmethod(method,
compile_id,
@@ -1496,7 +1557,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
in_ByteSize(-1),
oop_maps,
exception_offset);
- ContinuationEntry::set_enter_code(nm);
+ ContinuationEntry::set_enter_code(nm, interpreted_entry_offset);
return nm;
}
diff --git a/src/hotspot/share/code/compiledIC.cpp b/src/hotspot/share/code/compiledIC.cpp
index e26d27f10e8..f0329ba2142 100644
--- a/src/hotspot/share/code/compiledIC.cpp
+++ b/src/hotspot/share/code/compiledIC.cpp
@@ -39,6 +39,7 @@
#include "oops/method.inline.hpp"
#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
+#include "runtime/continuationEntry.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/icache.hpp"
#include "runtime/safepoint.hpp"
@@ -653,6 +654,13 @@ void CompiledStaticCall::compute_entry(const methodHandle& m, bool caller_is_nme
}
}
+void CompiledStaticCall::compute_entry_for_continuation_entry(const methodHandle& m, StaticCallInfo& info) {
+ if (ContinuationEntry::is_interpreted_call(instruction_address())) {
+ info._to_interpreter = true;
+ info._entry = m()->get_c2i_entry();
+ }
+}
+
address CompiledDirectStaticCall::find_stub_for(address instruction) {
// Find reloc. information containing this call-site
RelocIterator iter((nmethod*)NULL, instruction);
diff --git a/src/hotspot/share/code/compiledIC.hpp b/src/hotspot/share/code/compiledIC.hpp
index 6cdaf20c22d..18bd3765507 100644
--- a/src/hotspot/share/code/compiledIC.hpp
+++ b/src/hotspot/share/code/compiledIC.hpp
@@ -345,6 +345,7 @@ class CompiledStaticCall : public ResourceObj {
// Compute entry point given a method
static void compute_entry(const methodHandle& m, bool caller_is_nmethod, StaticCallInfo& info);
+ void compute_entry_for_continuation_entry(const methodHandle& m, StaticCallInfo& info);
public:
// Clean static call (will force resolving on next use)
diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp
index 716b8a74bf3..5bf7b14e297 100644
--- a/src/hotspot/share/oops/method.cpp
+++ b/src/hotspot/share/oops/method.cpp
@@ -61,6 +61,7 @@
#include "prims/methodHandles.hpp"
#include "runtime/arguments.hpp"
#include "runtime/atomic.hpp"
+#include "runtime/continuationEntry.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/init.hpp"
@@ -1328,7 +1329,7 @@ void Method::set_code(const methodHandle& mh, CompiledMethod *code) {
assert(mh->_from_interpreted_entry == NULL, "initialized incorrectly"); // see link_method
// This is the entry used when we're in interpreter-only mode; see InterpreterMacroAssembler::jump_from_interpreted
- mh->_i2i_entry = mh->get_i2c_entry();
+ mh->_i2i_entry = ContinuationEntry::interpreted_entry();
// This must come last, as it is what's tested in LinkResolver::resolve_static_call
Atomic::release_store(&mh->_from_interpreted_entry , mh->get_i2c_entry());
} else if (!mh->is_method_handle_intrinsic()) {
diff --git a/src/hotspot/share/runtime/continuationEntry.cpp b/src/hotspot/share/runtime/continuationEntry.cpp
index 40e25fb3ee1..37ad342487c 100644
--- a/src/hotspot/share/runtime/continuationEntry.cpp
+++ b/src/hotspot/share/runtime/continuationEntry.cpp
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "code/compiledIC.hpp"
#include "code/nmethod.hpp"
#include "runtime/continuation.hpp"
#include "runtime/continuationEntry.inline.hpp"
@@ -34,10 +35,32 @@
int ContinuationEntry::_return_pc_offset = 0;
address ContinuationEntry::_return_pc = nullptr;
+CompiledMethod* ContinuationEntry::_enter_special = nullptr;
+int ContinuationEntry::_interpreted_entry_offset = 0;
-void ContinuationEntry::set_enter_code(CompiledMethod* cm) {
+void ContinuationEntry::set_enter_code(CompiledMethod* cm, int interpreted_entry_offset) {
assert(_return_pc_offset != 0, "");
_return_pc = cm->code_begin() + _return_pc_offset;
+
+ _enter_special = cm;
+ _interpreted_entry_offset = interpreted_entry_offset;
+ assert(_enter_special->code_contains(compiled_entry()), "entry not in enterSpecial");
+ assert(_enter_special->code_contains(interpreted_entry()), "entry not in enterSpecial");
+ assert(interpreted_entry() < compiled_entry(), "unexpected code layout");
+}
+
+address ContinuationEntry::compiled_entry() {
+ return _enter_special->verified_entry_point();
+}
+
+address ContinuationEntry::interpreted_entry() {
+ return _enter_special->code_begin() + _interpreted_entry_offset;
+}
+
+bool ContinuationEntry::is_interpreted_call(address call_address) {
+ assert(_enter_special->code_contains(call_address), "call not in enterSpecial");
+ assert(call_address >= interpreted_entry(), "unexpected location");
+ return call_address < compiled_entry();
}
ContinuationEntry* ContinuationEntry::from_frame(const frame& f) {
diff --git a/src/hotspot/share/runtime/continuationEntry.hpp b/src/hotspot/share/runtime/continuationEntry.hpp
index f32c9276359..feab7e8069c 100644
--- a/src/hotspot/share/runtime/continuationEntry.hpp
+++ b/src/hotspot/share/runtime/continuationEntry.hpp
@@ -53,10 +53,13 @@ public:
public:
static int _return_pc_offset; // friend gen_continuation_enter
- static void set_enter_code(CompiledMethod* nm); // friend SharedRuntime::generate_native_wrapper
+ static void set_enter_code(CompiledMethod* cm, int interpreted_entry_offset);
+ static bool is_interpreted_call(address call_address);
private:
static address _return_pc;
+ static CompiledMethod* _enter_special;
+ static int _interpreted_entry_offset;
private:
ContinuationEntry* _parent;
@@ -90,6 +93,11 @@ public:
intptr_t* entry_sp() const { return (intptr_t*)this; }
intptr_t* entry_fp() const;
+ static address compiled_entry();
+ static address interpreted_entry();
+
+ static CompiledMethod* enter_special() { return _enter_special; }
+
int argsize() const { return _argsize; }
void set_argsize(int value) { _argsize = value; }
diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp
index bc45f604b07..f6787ccff28 100644
--- a/src/hotspot/share/runtime/sharedRuntime.cpp
+++ b/src/hotspot/share/runtime/sharedRuntime.cpp
@@ -1343,6 +1343,9 @@ bool SharedRuntime::resolve_sub_helper_internal(methodHandle callee_method, cons
return true; // skip patching for JVMCI
}
CompiledStaticCall* ssc = caller_nm->compiledStaticCall_before(caller_frame.pc());
+ if (is_nmethod && caller_nm->method()->is_continuation_enter_intrinsic()) {
+ ssc->compute_entry_for_continuation_entry(callee_method, static_call_info);
+ }
if (ssc->is_clean()) ssc->set(static_call_info);
}
}
@@ -1557,10 +1560,32 @@ JRT_END
// resolve a static call and patch code
JRT_BLOCK_ENTRY(address, SharedRuntime::resolve_static_call_C(JavaThread* current ))
methodHandle callee_method;
+ bool enter_special = false;
JRT_BLOCK
callee_method = SharedRuntime::resolve_helper(false, false, CHECK_NULL);
current->set_vm_result_2(callee_method());
+
+ if (current->is_interp_only_mode()) {
+ RegisterMap reg_map(current, false);
+ frame stub_frame = current->last_frame();
+ assert(stub_frame.is_runtime_frame(), "must be a runtimeStub");
+ frame caller = stub_frame.sender(®_map);
+ enter_special = caller.cb() != NULL && caller.cb()->is_compiled()
+ && caller.cb()->as_compiled_method()->method()->is_continuation_enter_intrinsic();
+ }
JRT_BLOCK_END
+
+ if (current->is_interp_only_mode() && enter_special) {
+ // enterSpecial is compiled and calls this method to resolve the call to Continuation::enter
+ // but in interp_only_mode we need to go to the interpreted entry
+ // The c2i won't patch in this mode -- see fixup_callers_callsite
+ //
+ // This should probably be done in all cases, not just enterSpecial (see JDK-8218403),
+ // but that's part of a larger fix, and the situation is worse for enterSpecial, as it has no
+ // interpreted version.
+ return callee_method->get_c2i_entry();
+ }
+
// return compiled code entry point after potential safepoints
assert(callee_method->verified_code_entry() != NULL, " Jump to zero!");
return callee_method->verified_code_entry();
@@ -1991,6 +2016,9 @@ JRT_LEAF(void, SharedRuntime::fixup_callers_callsite(Method* method, address cal
// Get the return PC for the passed caller PC.
address return_pc = caller_pc + frame::pc_return_offset;
+ assert(!JavaThread::current()->is_interp_only_mode() || !nm->method()->is_continuation_enter_intrinsic()
+ || ContinuationEntry::is_interpreted_call(return_pc), "interp_only_mode but not in enterSpecial interpreted entry");
+
// There is a benign race here. We could be attempting to patch to a compiled
// entry point at the same time the callee is being deoptimized. If that is
// the case then entry_point may in fact point to a c2i and we'd patch the
@@ -2027,6 +2055,13 @@ JRT_LEAF(void, SharedRuntime::fixup_callers_callsite(Method* method, address cal
typ != relocInfo::static_stub_type) {
return;
}
+ if (nm->method()->is_continuation_enter_intrinsic()) {
+ assert(ContinuationEntry::is_interpreted_call(call->instruction_address()) == JavaThread::current()->is_interp_only_mode(),
+ "mode: %d", JavaThread::current()->is_interp_only_mode());
+ if (ContinuationEntry::is_interpreted_call(call->instruction_address())) {
+ return;
+ }
+ }
address destination = call->destination();
if (should_fixup_call_destination(destination, entry_point, caller_pc, moop, cb)) {
call->set_destination_mt_safe(entry_point);
@@ -3056,7 +3091,7 @@ void AdapterHandlerLibrary::create_native_wrapper(const methodHandle& method) {
CodeBuffer buffer(buf);
if (method->is_continuation_enter_intrinsic()) {
- buffer.initialize_stubs_size(64);
+ buffer.initialize_stubs_size(128);
}
struct { double data[20]; } locs_buf;
diff --git a/src/java.base/share/classes/java/lang/foreign/AbstractLayout.java b/src/java.base/share/classes/java/lang/foreign/AbstractLayout.java
index ecc03073c30..5b9bc1e8da6 100644
--- a/src/java.base/share/classes/java/lang/foreign/AbstractLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/AbstractLayout.java
@@ -120,12 +120,15 @@ abstract non-sealed class AbstractLayout implements MemoryLayout {
return this instanceof PaddingLayout;
}
+ // the following methods have to copy the same Javadoc as in MemoryLayout, or subclasses will just show
+ // the Object methods javadoc
+
/**
* {@return the hash code value for this layout}
*/
@Override
public int hashCode() {
- return name.hashCode() << Long.hashCode(alignment);
+ return Objects.hash(name, size, alignment);
}
/**
@@ -134,28 +137,27 @@ abstract non-sealed class AbstractLayout implements MemoryLayout {
* the same kind, have the same size, name and alignment constraints. Furthermore, depending on the layout kind, additional
* conditions must be satisfied:
*
- *
two value layouts are considered equal if they have the same byte order (see {@link ValueLayout#order()})
+ *
two value layouts are considered equal if they have the same {@linkplain ValueLayout#order() order},
+ * and {@linkplain ValueLayout#carrier() carrier}
*
two sequence layouts are considered equal if they have the same element count (see {@link SequenceLayout#elementCount()}), and
* if their element layouts (see {@link SequenceLayout#elementLayout()}) are also equal
*
two group layouts are considered equal if they are of the same kind (see {@link GroupLayout#isStruct()},
* {@link GroupLayout#isUnion()}) and if their member layouts (see {@link GroupLayout#memberLayouts()}) are also equal
*
*
- * @param that the object to be compared for equality with this layout.
+ * @param other the object to be compared for equality with this layout.
* @return {@code true} if the specified object is equal to this layout.
*/
@Override
- public boolean equals(Object that) {
- if (this == that) {
+ public boolean equals(Object other) {
+ if (this == other) {
return true;
}
- if (!(that instanceof AbstractLayout)) {
- return false;
- }
-
- return Objects.equals(name, ((AbstractLayout) that).name) &&
- Objects.equals(alignment, ((AbstractLayout) that).alignment);
+ return other instanceof AbstractLayout otherLayout &&
+ name.equals(otherLayout.name) &&
+ size == otherLayout.size &&
+ alignment == otherLayout.alignment;
}
/**
diff --git a/src/java.base/share/classes/java/lang/foreign/GroupLayout.java b/src/java.base/share/classes/java/lang/foreign/GroupLayout.java
index 053a96d8fa0..d012735ba9f 100644
--- a/src/java.base/share/classes/java/lang/foreign/GroupLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/GroupLayout.java
@@ -143,10 +143,9 @@ public final class GroupLayout extends AbstractLayout implements MemoryLayout {
if (!super.equals(other)) {
return false;
}
- if (!(other instanceof GroupLayout g)) {
- return false;
- }
- return kind.equals(g.kind) && elements.equals(g.elements);
+ return other instanceof GroupLayout otherGroup &&
+ kind == otherGroup.kind &&
+ elements.equals(otherGroup.elements);
}
/**
diff --git a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
index 54de6953088..b30a14e60a6 100644
--- a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
@@ -584,17 +584,18 @@ public sealed interface MemoryLayout permits AbstractLayout, SequenceLayout, Gro
* the same kind, have the same size, name and alignment constraints. Furthermore, depending on the layout kind, additional
* conditions must be satisfied:
*
- *
two value layouts are considered equal if they have the same byte order (see {@link ValueLayout#order()})
+ *
two value layouts are considered equal if they have the same {@linkplain ValueLayout#order() order},
+ * and {@linkplain ValueLayout#carrier() carrier}
*
two sequence layouts are considered equal if they have the same element count (see {@link SequenceLayout#elementCount()}), and
* if their element layouts (see {@link SequenceLayout#elementLayout()}) are also equal
*
two group layouts are considered equal if they are of the same kind (see {@link GroupLayout#isStruct()},
* {@link GroupLayout#isUnion()}) and if their member layouts (see {@link GroupLayout#memberLayouts()}) are also equal
*
*
- * @param that the object to be compared for equality with this layout.
+ * @param other the object to be compared for equality with this layout.
* @return {@code true} if the specified object is equal to this layout.
*/
- boolean equals(Object that);
+ boolean equals(Object other);
/**
* {@return the hash code value for this layout}
diff --git a/src/java.base/share/classes/java/lang/foreign/SequenceLayout.java b/src/java.base/share/classes/java/lang/foreign/SequenceLayout.java
index 8ea0e1a9fdc..d25ba35ead1 100644
--- a/src/java.base/share/classes/java/lang/foreign/SequenceLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/SequenceLayout.java
@@ -124,7 +124,6 @@ public final class SequenceLayout extends AbstractLayout implements MemoryLayout
* @param elementCounts an array of element counts, of which at most one can be {@code -1}.
* @return a sequence layout where element layouts in the flattened projection of this
* sequence layout (see {@link #flatten()}) are re-arranged into one or more nested sequence layouts.
- * @throws UnsupportedOperationException if this sequence layout does not have an element count.
* @throws IllegalArgumentException if two or more element counts are set to {@code -1}, or if one
* or more element count is {@code <= 0} (but other than {@code -1}) or, if, after any required inference,
* multiplying the element counts does not yield the same element count as the flattened projection of this
@@ -187,8 +186,6 @@ public final class SequenceLayout extends AbstractLayout implements MemoryLayout
* }
* @return a sequence layout with the same size as this layout (but, possibly, with different
* element count), whose element layout is not a sequence layout.
- * @throws UnsupportedOperationException if this sequence layout, or one of the nested sequence layouts being
- * flattened, does not have an element count.
*/
public SequenceLayout flatten() {
long count = elementCount();
@@ -214,10 +211,9 @@ public final class SequenceLayout extends AbstractLayout implements MemoryLayout
if (!super.equals(other)) {
return false;
}
- if (!(other instanceof SequenceLayout s)) {
- return false;
- }
- return elemCount == s.elemCount && elementLayout.equals(s.elementLayout);
+ return other instanceof SequenceLayout otherSeq &&
+ elemCount == otherSeq.elemCount &&
+ elementLayout.equals(otherSeq.elementLayout);
}
@Override
diff --git a/src/java.base/share/classes/java/lang/foreign/ValueLayout.java b/src/java.base/share/classes/java/lang/foreign/ValueLayout.java
index 4bf7f3e522a..0bbea651c38 100644
--- a/src/java.base/share/classes/java/lang/foreign/ValueLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/ValueLayout.java
@@ -93,6 +93,9 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
return new ValueLayout(carrier, Objects.requireNonNull(order), bitSize(), alignment, name());
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public String toString() {
char descriptor = carrier == MemoryAddress.class ? 'A' : carrier.descriptorString().charAt(0);
@@ -102,6 +105,9 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
return decorateLayoutString(String.format("%s%d", descriptor, bitSize()));
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public boolean equals(Object other) {
if (this == other) {
@@ -110,13 +116,9 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
if (!super.equals(other)) {
return false;
}
- if (!(other instanceof ValueLayout v)) {
- return false;
- }
- return carrier.equals(v.carrier) &&
- order.equals(v.order) &&
- bitSize() == v.bitSize() &&
- alignment == v.alignment;
+ return other instanceof ValueLayout otherValue &&
+ carrier.equals(otherValue.carrier) &&
+ order.equals(otherValue.order);
}
/**
@@ -171,7 +173,7 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
* @return a var handle which can be used to dereference a multi-dimensional array, featuring {@code shape.length + 1}
* {@code long} coordinates.
* @throws IllegalArgumentException if {@code shape[i] < 0}, for at least one index {@code i}.
- * @throws UnsupportedOperationException if the layout path has one or more elements with incompatible alignment constraints.
+ * @throws UnsupportedOperationException if {@code bitAlignment() > bitSize()}.
* @see MethodHandles#memorySegmentViewVarHandle
* @see MemoryLayout#varHandle(PathElement...)
* @see SequenceLayout
@@ -198,9 +200,12 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
return carrier;
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public int hashCode() {
- return Objects.hash(super.hashCode(), order, bitSize(), alignment);
+ return Objects.hash(super.hashCode(), order, carrier);
}
@Override
diff --git a/src/java.base/share/classes/java/util/Map.java b/src/java.base/share/classes/java/util/Map.java
index 72fb4a2b75d..50fc37d15c3 100644
--- a/src/java.base/share/classes/java/util/Map.java
+++ b/src/java.base/share/classes/java/util/Map.java
@@ -737,23 +737,18 @@ public interface Map {
*
* @param function the function to apply to each entry
* @throws UnsupportedOperationException if the {@code set} operation
- * is not supported by this map's entry set iterator.
+ * is not supported by this map's entry set iterator.
* @throws ClassCastException if the class of a replacement value
- * prevents it from being stored in this map
- * @throws NullPointerException if the specified function is null, or the
- * specified replacement value is null, and this map does not permit null
- * values
- * @throws ClassCastException if a replacement value is of an inappropriate
- * type for this map
+ * prevents it from being stored in this map
* (optional)
- * @throws NullPointerException if function or a replacement value is null,
- * and this map does not permit null keys or values
+ * @throws NullPointerException if the specified function is null, or if a
+ * replacement value is null and this map does not permit null values
* (optional)
* @throws IllegalArgumentException if some property of a replacement value
* prevents it from being stored in this map
* (optional)
* @throws ConcurrentModificationException if an entry is found to be
- * removed during iteration
+ * removed during iteration
* @since 1.8
*/
default void replaceAll(BiFunction super K, ? super V, ? extends V> function) {
diff --git a/src/java.xml/share/classes/com/sun/java_cup/internal/runtime/lr_parser.java b/src/java.xml/share/classes/com/sun/java_cup/internal/runtime/lr_parser.java
index 8da2d63d6f8..2aa71318d4e 100644
--- a/src/java.xml/share/classes/com/sun/java_cup/internal/runtime/lr_parser.java
+++ b/src/java.xml/share/classes/com/sun/java_cup/internal/runtime/lr_parser.java
@@ -137,7 +137,7 @@ import java.util.Stack;
* @see com.sun.java_cup.internal.runtime.virtual_parse_stack
* @author Frank Flannery
*
- * @LastModified: June 2022
+ * @LastModified: July 2022
*/
public abstract class lr_parser {
@@ -150,6 +150,10 @@ public abstract class lr_parser {
private int opCount = 0;
private int totalOpCount = 0;
private int lastSym;
+ private boolean overLimit = false;
+ public int grpLimit = 0;
+ public int opLimit = 0;
+ public int totalOpLimit = 0;
/*-----------------------------------------------------------*/
/*--- Constructor(s) ----------------------------------------*/
@@ -376,11 +380,13 @@ public abstract class lr_parser {
grpCount++;
}
opCount++; // function
+ totalOpCount++;
isLiteral = false;
} else if (contains(sym.OPERATORS, s.sym)) {
// axis nodetest is counted as one step, so not counted if last=DCOLON
if (lastSym != sym.DCOLON) {
opCount++;
+ totalOpCount++;
}
isLiteral = false;
}
@@ -390,6 +396,16 @@ public abstract class lr_parser {
}
lastSym = s.sym;
+ /*
+ * Sets the overLimit status as soon as the count of operators is over the
+ * limit, which in turn triggers the XPathParser to report an error.
+ */
+ if (grpLimit > 0 && grpCount > grpLimit
+ || opLimit > 0 && opCount > opLimit
+ || totalOpLimit > 0 && totalOpCount > totalOpLimit) {
+ overLimit = true;
+ }
+
return s;
}
@@ -591,12 +607,14 @@ public abstract class lr_parser {
/* do user initialization */
user_init();
isLiteral = false;
+ overLimit = false;
grpCount = 0;
opCount = 0;
lastSym = -1;
/* get the first token */
cur_token = scan();
+ if (overLimit) return null;
/* push dummy Symbol with start state to get us underway */
stack.removeAllElements();
@@ -671,12 +689,16 @@ public abstract class lr_parser {
lhs_sym = stack.peek();
}
}
+ if (overLimit) return null;
}
- totalOpCount += opCount;
return lhs_sym;
}
+ public boolean isOverLimit() {
+ return overLimit;
+ }
+
/**
* Returns the count of operators in XPath expressions.
*
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XPathParser.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XPathParser.java
index 16fdbe18fc9..174e1440479 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XPathParser.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XPathParser.java
@@ -43,12 +43,9 @@ import jdk.xml.internal.XMLSecurityManager.Limit;
* CUP v0.11b generated parser.
* This class was generated by CUP v0.11b on Nov 12, 2019.
*
- * @LastModified: Jan 2022
+ * @LastModified: July 2022
*/
public class XPathParser extends lr_parser {
- private int grpLimit = 0;
- private int opLimit = 0;
- private int totalOpLimit = 0;
/**
* Default constructor.
@@ -1118,29 +1115,37 @@ public class XPathParser extends lr_parser {
_expression = expression;
_lineNumber = lineNumber;
Symbol s = super.parse();
- int grpCount = getCount(ID_GROUP);
- int opCount = getCount(ID_OPERATOR);
- int totalOpCount = getCount(ID_TOTAL_OPERATOR);
+ /*
+ * While the Java CUP parser is used for parsing symbols, the error
+ * report mechanism has so far been kept within the Xalan implementation.
+ * An error, i.e. the count of operators is over the limit, is
+ * therefore handled here.
+ */
+ if (isOverLimit()) {
+ int grpCount = getCount(ID_GROUP);
+ int opCount = getCount(ID_OPERATOR);
+ int totalOpCount = getCount(ID_TOTAL_OPERATOR);
- String errCode = null;
- Object[] params = null;
- if (grpLimit > 0 && grpCount > grpLimit) {
- errCode = ErrorMsg.XPATH_GROUP_LIMIT;
- params = new Object[]{grpCount, grpLimit,
- _xmlSM.getStateLiteral(Limit.XPATH_GROUP_LIMIT)};
- } else if (opLimit > 0 && opCount > opLimit) {
- errCode = ErrorMsg.XPATH_OPERATOR_LIMIT;
- params = new Object[]{opCount, opLimit,
- _xmlSM.getStateLiteral(Limit.XPATH_OP_LIMIT)};
- } else if (totalOpLimit > 0 && totalOpCount > totalOpLimit) {
- errCode = ErrorMsg.XPATH_TOTAL_OPERATOR_LIMIT;
- params = new Object[]{totalOpCount, totalOpLimit,
- _xmlSM.getStateLiteral(Limit.XPATH_TOTALOP_LIMIT)};
- }
- if (errCode != null) {
- _parser.reportError(Constants.FATAL,
- new ErrorMsg(errCode, lineNumber, params));
- throw new RuntimeException(ErrorMsg.XPATH_LIMIT);
+ String errCode = null;
+ Object[] params = null;
+ if (grpLimit > 0 && grpCount > grpLimit) {
+ errCode = ErrorMsg.XPATH_GROUP_LIMIT;
+ params = new Object[]{grpCount, grpLimit,
+ _xmlSM.getStateLiteral(Limit.XPATH_GROUP_LIMIT)};
+ } else if (opLimit > 0 && opCount > opLimit) {
+ errCode = ErrorMsg.XPATH_OPERATOR_LIMIT;
+ params = new Object[]{opCount, opLimit,
+ _xmlSM.getStateLiteral(Limit.XPATH_OP_LIMIT)};
+ } else if (totalOpLimit > 0 && totalOpCount > totalOpLimit) {
+ errCode = ErrorMsg.XPATH_TOTAL_OPERATOR_LIMIT;
+ params = new Object[]{totalOpCount, totalOpLimit,
+ _xmlSM.getStateLiteral(Limit.XPATH_TOTALOP_LIMIT)};
+ }
+ if (errCode != null) {
+ _parser.reportError(Constants.FATAL,
+ new ErrorMsg(errCode, lineNumber, params));
+ throw new RuntimeException(ErrorMsg.XPATH_LIMIT);
+ }
}
return s;
} catch (IllegalCharException e) {
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
index 59f3e93e39d..94f06f8990f 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
@@ -1694,9 +1694,7 @@ public class Attr extends JCTree.Visitor {
// Attribute all cases and
// check that there are no duplicate case labels or default clauses.
- Set