86 lines
4.6 KiB
Diff
86 lines
4.6 KiB
Diff
|
|
From 72853c670c97aae4eab64a5e9edb3c7176beaf6a Mon Sep 17 00:00:00 2001
|
||
|
|
Date: Fri, 22 Jan 2021 16:36:41 +0800
|
||
|
|
Subject: 8168926: C2: Bytecode escape analyzer crashes due to
|
||
|
|
stack overflow
|
||
|
|
|
||
|
|
Summary: <C2>:8168926: C2: Bytecode escape analyzer crashes due to stack overflow
|
||
|
|
LLT: N/A
|
||
|
|
Bug url: https://bugs.openjdk.java.net/browse/JDK-8168926
|
||
|
|
---
|
||
|
|
hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp | 30 ++++++++++++++++++--
|
||
|
|
hotspot/src/share/vm/ci/ciMethod.hpp | 12 +++++---
|
||
|
|
2 files changed, 35 insertions(+), 7 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp
|
||
|
|
index 2b9e0e514..34bdbe94d 100644
|
||
|
|
--- a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp
|
||
|
|
+++ b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp
|
||
|
|
@@ -894,9 +894,33 @@ void BCEscapeAnalyzer::iterate_one_block(ciBlock *blk, StateInfo &state, Growabl
|
||
|
|
ciMethod* target = s.get_method(ignored_will_link, &declared_signature);
|
||
|
|
ciKlass* holder = s.get_declared_method_holder();
|
||
|
|
assert(declared_signature != NULL, "cannot be null");
|
||
|
|
- // Push appendix argument, if one.
|
||
|
|
- if (s.has_appendix()) {
|
||
|
|
- state.apush(unknown_obj);
|
||
|
|
+ // If the current bytecode has an attached appendix argument,
|
||
|
|
+ // push an unknown object to represent that argument. (Analysis
|
||
|
|
+ // of dynamic call sites, especially invokehandle calls, needs
|
||
|
|
+ // the appendix argument on the stack, in addition to "regular" arguments
|
||
|
|
+ // pushed onto the stack by bytecode instructions preceding the call.)
|
||
|
|
+ //
|
||
|
|
+ // The escape analyzer does _not_ use the ciBytecodeStream::has_appendix(s)
|
||
|
|
+ // method to determine whether the current bytecode has an appendix argument.
|
||
|
|
+ // The has_appendix() method obtains the appendix from the
|
||
|
|
+ // ConstantPoolCacheEntry::_f1 field, which can happen concurrently with
|
||
|
|
+ // resolution of dynamic call sites. Callees in the
|
||
|
|
+ // ciBytecodeStream::get_method() call above also access the _f1 field;
|
||
|
|
+ // interleaving the get_method() and has_appendix() calls in the current
|
||
|
|
+ // method with call site resolution can lead to an inconsistent view of
|
||
|
|
+ // the current method's argument count. In particular, some interleaving(s)
|
||
|
|
+ // can cause the method's argument count to not include the appendix, which
|
||
|
|
+ // then leads to stack over-/underflow in the escape analyzer.
|
||
|
|
+ //
|
||
|
|
+ // Instead of pushing the argument if has_appendix() is true, the escape analyzer
|
||
|
|
+ // pushes an appendix for all call sites targeted by invokedynamic and invokehandle
|
||
|
|
+ // instructions, except if the call site is the _invokeBasic intrinsic
|
||
|
|
+ // (that intrinsic is always targeted by an invokehandle instruction but does
|
||
|
|
+ // not have an appendix argument).
|
||
|
|
+ if (target->is_loaded() &&
|
||
|
|
+ Bytecodes::has_optional_appendix(s.cur_bc_raw()) &&
|
||
|
|
+ target->intrinsic_id() != vmIntrinsics::_invokeBasic) {
|
||
|
|
+ state.apush(unknown_obj);
|
||
|
|
}
|
||
|
|
// Pass in raw bytecode because we need to see invokehandle instructions.
|
||
|
|
invoke(state, s.cur_bc_raw(), target, holder);
|
||
|
|
diff --git a/hotspot/src/share/vm/ci/ciMethod.hpp b/hotspot/src/share/vm/ci/ciMethod.hpp
|
||
|
|
index 307452422..99d8dbe67 100644
|
||
|
|
--- a/hotspot/src/share/vm/ci/ciMethod.hpp
|
||
|
|
+++ b/hotspot/src/share/vm/ci/ciMethod.hpp
|
||
|
|
@@ -133,15 +133,19 @@ class ciMethod : public ciMetadata {
|
||
|
|
check_is_loaded();
|
||
|
|
return _signature->size() + (_flags.is_static() ? 0 : 1);
|
||
|
|
}
|
||
|
|
- // Report the number of elements on stack when invoking this method.
|
||
|
|
- // This is different than the regular arg_size because invokedynamic
|
||
|
|
- // has an implicit receiver.
|
||
|
|
+ // Report the number of elements on stack when invoking the current method.
|
||
|
|
+ // If the method is loaded, arg_size() gives precise information about the
|
||
|
|
+ // number of stack elements (using the method's signature and its flags).
|
||
|
|
+ // However, if the method is not loaded, the number of stack elements must
|
||
|
|
+ // be determined differently, as the method's flags are not yet available.
|
||
|
|
+ // The invoke_arg_size() method assumes in that case that all bytecodes except
|
||
|
|
+ // invokestatic and invokedynamic have a receiver that is also pushed onto the
|
||
|
|
+ // stack by the caller of the current method.
|
||
|
|
int invoke_arg_size(Bytecodes::Code code) const {
|
||
|
|
if (is_loaded()) {
|
||
|
|
return arg_size();
|
||
|
|
} else {
|
||
|
|
int arg_size = _signature->size();
|
||
|
|
- // Add a receiver argument, maybe:
|
||
|
|
if (code != Bytecodes::_invokestatic &&
|
||
|
|
code != Bytecodes::_invokedynamic) {
|
||
|
|
arg_size++;
|
||
|
|
--
|
||
|
|
2.19.0
|
||
|
|
|