mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
8156073: 2-slot LiveStackFrame locals (long and double) are incorrect
Reviewed-by: coleenp, mchung
This commit is contained in:
parent
95ff3ccdb4
commit
c38ccc4fb0
6 changed files with 67 additions and 63 deletions
|
@ -2269,6 +2269,7 @@ void java_lang_LiveStackFrameInfo::compute_offsets() {
|
||||||
compute_offset(_monitors_offset, k, vmSymbols::monitors_name(), vmSymbols::object_array_signature());
|
compute_offset(_monitors_offset, k, vmSymbols::monitors_name(), vmSymbols::object_array_signature());
|
||||||
compute_offset(_locals_offset, k, vmSymbols::locals_name(), vmSymbols::object_array_signature());
|
compute_offset(_locals_offset, k, vmSymbols::locals_name(), vmSymbols::object_array_signature());
|
||||||
compute_offset(_operands_offset, k, vmSymbols::operands_name(), vmSymbols::object_array_signature());
|
compute_offset(_operands_offset, k, vmSymbols::operands_name(), vmSymbols::object_array_signature());
|
||||||
|
compute_offset(_mode_offset, k, vmSymbols::mode_name(), vmSymbols::int_signature());
|
||||||
}
|
}
|
||||||
|
|
||||||
void java_lang_reflect_AccessibleObject::compute_offsets() {
|
void java_lang_reflect_AccessibleObject::compute_offsets() {
|
||||||
|
@ -3658,6 +3659,7 @@ int java_lang_StackFrameInfo::_version_offset;
|
||||||
int java_lang_LiveStackFrameInfo::_monitors_offset;
|
int java_lang_LiveStackFrameInfo::_monitors_offset;
|
||||||
int java_lang_LiveStackFrameInfo::_locals_offset;
|
int java_lang_LiveStackFrameInfo::_locals_offset;
|
||||||
int java_lang_LiveStackFrameInfo::_operands_offset;
|
int java_lang_LiveStackFrameInfo::_operands_offset;
|
||||||
|
int java_lang_LiveStackFrameInfo::_mode_offset;
|
||||||
int java_lang_AssertionStatusDirectives::classes_offset;
|
int java_lang_AssertionStatusDirectives::classes_offset;
|
||||||
int java_lang_AssertionStatusDirectives::classEnabled_offset;
|
int java_lang_AssertionStatusDirectives::classEnabled_offset;
|
||||||
int java_lang_AssertionStatusDirectives::packages_offset;
|
int java_lang_AssertionStatusDirectives::packages_offset;
|
||||||
|
@ -3728,6 +3730,10 @@ void java_lang_LiveStackFrameInfo::set_operands(oop element, oop value) {
|
||||||
element->obj_field_put(_operands_offset, value);
|
element->obj_field_put(_operands_offset, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void java_lang_LiveStackFrameInfo::set_mode(oop element, int value) {
|
||||||
|
element->int_field_put(_mode_offset, value);
|
||||||
|
}
|
||||||
|
|
||||||
// Support for java Assertions - java_lang_AssertionStatusDirectives.
|
// Support for java Assertions - java_lang_AssertionStatusDirectives.
|
||||||
|
|
||||||
void java_lang_AssertionStatusDirectives::set_classes(oop o, oop val) {
|
void java_lang_AssertionStatusDirectives::set_classes(oop o, oop val) {
|
||||||
|
|
|
@ -1380,11 +1380,13 @@ class java_lang_LiveStackFrameInfo: AllStatic {
|
||||||
static int _monitors_offset;
|
static int _monitors_offset;
|
||||||
static int _locals_offset;
|
static int _locals_offset;
|
||||||
static int _operands_offset;
|
static int _operands_offset;
|
||||||
|
static int _mode_offset;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void set_monitors(oop info, oop value);
|
static void set_monitors(oop info, oop value);
|
||||||
static void set_locals(oop info, oop value);
|
static void set_locals(oop info, oop value);
|
||||||
static void set_operands(oop info, oop value);
|
static void set_operands(oop info, oop value);
|
||||||
|
static void set_mode(oop info, int value);
|
||||||
|
|
||||||
static void compute_offsets();
|
static void compute_offsets();
|
||||||
|
|
||||||
|
|
|
@ -325,14 +325,8 @@
|
||||||
template(java_lang_StackStreamFactory_AbstractStackWalker, "java/lang/StackStreamFactory$AbstractStackWalker") \
|
template(java_lang_StackStreamFactory_AbstractStackWalker, "java/lang/StackStreamFactory$AbstractStackWalker") \
|
||||||
template(doStackWalk_signature, "(JIIII)Ljava/lang/Object;") \
|
template(doStackWalk_signature, "(JIIII)Ljava/lang/Object;") \
|
||||||
template(asPrimitive_name, "asPrimitive") \
|
template(asPrimitive_name, "asPrimitive") \
|
||||||
template(asPrimitive_int_signature, "(I)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
|
template(asPrimitive_int_signature, "(I)Ljava/lang/LiveStackFrame$PrimitiveSlot;") \
|
||||||
template(asPrimitive_long_signature, "(J)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
|
template(asPrimitive_long_signature, "(J)Ljava/lang/LiveStackFrame$PrimitiveSlot;") \
|
||||||
template(asPrimitive_short_signature, "(S)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
|
|
||||||
template(asPrimitive_byte_signature, "(B)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
|
|
||||||
template(asPrimitive_char_signature, "(C)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
|
|
||||||
template(asPrimitive_float_signature, "(F)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
|
|
||||||
template(asPrimitive_double_signature, "(D)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
|
|
||||||
template(asPrimitive_boolean_signature, "(Z)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
|
|
||||||
\
|
\
|
||||||
/* common method and field names */ \
|
/* common method and field names */ \
|
||||||
template(object_initializer_name, "<init>") \
|
template(object_initializer_name, "<init>") \
|
||||||
|
@ -444,6 +438,7 @@
|
||||||
template(monitors_name, "monitors") \
|
template(monitors_name, "monitors") \
|
||||||
template(locals_name, "locals") \
|
template(locals_name, "locals") \
|
||||||
template(operands_name, "operands") \
|
template(operands_name, "operands") \
|
||||||
|
template(mode_name, "mode") \
|
||||||
template(oop_size_name, "oop_size") \
|
template(oop_size_name, "oop_size") \
|
||||||
template(static_oop_field_count_name, "static_oop_field_count") \
|
template(static_oop_field_count_name, "static_oop_field_count") \
|
||||||
template(protection_domain_name, "protection_domain") \
|
template(protection_domain_name, "protection_domain") \
|
||||||
|
|
|
@ -173,7 +173,11 @@ void JavaFrameStream::fill_frame(int index, objArrayHandle frames_array,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
oop LiveFrameStream::create_primitive_value_instance(StackValueCollection* values, int i, TRAPS) {
|
// Create and return a LiveStackFrame.PrimitiveSlot (if needed) for the
|
||||||
|
// StackValue at the given index. 'type' is expected to be T_INT, T_LONG,
|
||||||
|
// T_OBJECT, or T_CONFLICT.
|
||||||
|
oop LiveFrameStream::create_primitive_slot_instance(StackValueCollection* values,
|
||||||
|
int i, BasicType type, TRAPS) {
|
||||||
Klass* k = SystemDictionary::resolve_or_null(vmSymbols::java_lang_LiveStackFrameInfo(), CHECK_NULL);
|
Klass* k = SystemDictionary::resolve_or_null(vmSymbols::java_lang_LiveStackFrameInfo(), CHECK_NULL);
|
||||||
instanceKlassHandle ik (THREAD, k);
|
instanceKlassHandle ik (THREAD, k);
|
||||||
|
|
||||||
|
@ -182,8 +186,8 @@ oop LiveFrameStream::create_primitive_value_instance(StackValueCollection* value
|
||||||
Symbol* signature = NULL;
|
Symbol* signature = NULL;
|
||||||
|
|
||||||
// ## TODO: type is only available in LocalVariable table, if present.
|
// ## TODO: type is only available in LocalVariable table, if present.
|
||||||
// ## StackValue type is T_INT or T_OBJECT.
|
// ## StackValue type is T_INT or T_OBJECT (or converted to T_LONG on 64-bit)
|
||||||
switch (values->at(i)->type()) {
|
switch (type) {
|
||||||
case T_INT:
|
case T_INT:
|
||||||
args.push_int(values->int_at(i));
|
args.push_int(values->int_at(i));
|
||||||
signature = vmSymbols::asPrimitive_int_signature();
|
signature = vmSymbols::asPrimitive_int_signature();
|
||||||
|
@ -195,42 +199,26 @@ oop LiveFrameStream::create_primitive_value_instance(StackValueCollection* value
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_FLOAT:
|
case T_FLOAT:
|
||||||
args.push_float(values->float_at(i));
|
|
||||||
signature = vmSymbols::asPrimitive_float_signature();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_DOUBLE:
|
case T_DOUBLE:
|
||||||
args.push_double(values->double_at(i));
|
|
||||||
signature = vmSymbols::asPrimitive_double_signature();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_BYTE:
|
case T_BYTE:
|
||||||
args.push_int(values->int_at(i));
|
|
||||||
signature = vmSymbols::asPrimitive_byte_signature();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_SHORT:
|
case T_SHORT:
|
||||||
args.push_int(values->int_at(i));
|
|
||||||
signature = vmSymbols::asPrimitive_short_signature();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_CHAR:
|
case T_CHAR:
|
||||||
args.push_int(values->int_at(i));
|
|
||||||
signature = vmSymbols::asPrimitive_char_signature();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_BOOLEAN:
|
case T_BOOLEAN:
|
||||||
args.push_int(values->int_at(i));
|
THROW_MSG_(vmSymbols::java_lang_InternalError(), "Unexpected StackValue type", NULL);
|
||||||
signature = vmSymbols::asPrimitive_boolean_signature();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_OBJECT:
|
case T_OBJECT:
|
||||||
return values->obj_at(i)();
|
return values->obj_at(i)();
|
||||||
|
|
||||||
case T_CONFLICT:
|
case T_CONFLICT:
|
||||||
// put a non-null slot
|
// put a non-null slot
|
||||||
args.push_int(0);
|
#ifdef _LP64
|
||||||
signature = vmSymbols::asPrimitive_int_signature();
|
args.push_long(0);
|
||||||
|
signature = vmSymbols::asPrimitive_long_signature();
|
||||||
|
#else
|
||||||
|
args.push_int(0);
|
||||||
|
signature = vmSymbols::asPrimitive_int_signature();
|
||||||
|
#endif
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: ShouldNotReachHere();
|
default: ShouldNotReachHere();
|
||||||
|
@ -252,9 +240,19 @@ objArrayHandle LiveFrameStream::values_to_object_array(StackValueCollection* val
|
||||||
objArrayHandle array_h(THREAD, array_oop);
|
objArrayHandle array_h(THREAD, array_oop);
|
||||||
for (int i = 0; i < values->size(); i++) {
|
for (int i = 0; i < values->size(); i++) {
|
||||||
StackValue* st = values->at(i);
|
StackValue* st = values->at(i);
|
||||||
oop obj = create_primitive_value_instance(values, i, CHECK_(empty));
|
BasicType type = st->type();
|
||||||
if (obj != NULL)
|
int index = i;
|
||||||
|
#ifdef _LP64
|
||||||
|
if (type != T_OBJECT && type != T_CONFLICT) {
|
||||||
|
intptr_t ret = st->get_int(); // read full 64-bit slot
|
||||||
|
type = T_LONG; // treat as long
|
||||||
|
index--; // undo +1 in StackValueCollection::long_at
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
oop obj = create_primitive_slot_instance(values, index, type, CHECK_(empty));
|
||||||
|
if (obj != NULL) {
|
||||||
array_h->obj_at_put(i, obj);
|
array_h->obj_at_put(i, obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return array_h;
|
return array_h;
|
||||||
}
|
}
|
||||||
|
@ -286,6 +284,13 @@ void LiveFrameStream::fill_live_stackframe(Handle stackFrame,
|
||||||
StackValueCollection* expressions = _jvf->expressions();
|
StackValueCollection* expressions = _jvf->expressions();
|
||||||
GrowableArray<MonitorInfo*>* monitors = _jvf->monitors();
|
GrowableArray<MonitorInfo*>* monitors = _jvf->monitors();
|
||||||
|
|
||||||
|
int mode = 0;
|
||||||
|
if (_jvf->is_interpreted_frame()) {
|
||||||
|
mode = MODE_INTERPRETED;
|
||||||
|
} else if (_jvf->is_compiled_frame()) {
|
||||||
|
mode = MODE_COMPILED;
|
||||||
|
}
|
||||||
|
|
||||||
if (!locals->is_empty()) {
|
if (!locals->is_empty()) {
|
||||||
objArrayHandle locals_h = values_to_object_array(locals, CHECK);
|
objArrayHandle locals_h = values_to_object_array(locals, CHECK);
|
||||||
java_lang_LiveStackFrameInfo::set_locals(stackFrame(), locals_h());
|
java_lang_LiveStackFrameInfo::set_locals(stackFrame(), locals_h());
|
||||||
|
@ -298,6 +303,7 @@ void LiveFrameStream::fill_live_stackframe(Handle stackFrame,
|
||||||
objArrayHandle monitors_h = monitors_to_object_array(monitors, CHECK);
|
objArrayHandle monitors_h = monitors_to_object_array(monitors, CHECK);
|
||||||
java_lang_LiveStackFrameInfo::set_monitors(stackFrame(), monitors_h());
|
java_lang_LiveStackFrameInfo::set_monitors(stackFrame(), monitors_h());
|
||||||
}
|
}
|
||||||
|
java_lang_LiveStackFrameInfo::set_mode(stackFrame(), mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,11 +92,16 @@ public:
|
||||||
|
|
||||||
class LiveFrameStream : public BaseFrameStream {
|
class LiveFrameStream : public BaseFrameStream {
|
||||||
private:
|
private:
|
||||||
|
enum {
|
||||||
|
MODE_INTERPRETED = 0x01,
|
||||||
|
MODE_COMPILED = 0x02
|
||||||
|
};
|
||||||
|
|
||||||
javaVFrame* _jvf;
|
javaVFrame* _jvf;
|
||||||
|
|
||||||
void fill_live_stackframe(Handle stackFrame, const methodHandle& method, TRAPS);
|
void fill_live_stackframe(Handle stackFrame, const methodHandle& method, TRAPS);
|
||||||
static oop create_primitive_value_instance(StackValueCollection* values,
|
static oop create_primitive_slot_instance(StackValueCollection* values,
|
||||||
int i, TRAPS);
|
int i, BasicType type, TRAPS);
|
||||||
static objArrayHandle monitors_to_object_array(GrowableArray<MonitorInfo*>* monitors,
|
static objArrayHandle monitors_to_object_array(GrowableArray<MonitorInfo*>* monitors,
|
||||||
TRAPS);
|
TRAPS);
|
||||||
static objArrayHandle values_to_object_array(StackValueCollection* values, TRAPS);
|
static objArrayHandle values_to_object_array(StackValueCollection* values, TRAPS);
|
||||||
|
|
|
@ -30,10 +30,10 @@ import java.lang.StackWalker.StackFrame;
|
||||||
|
|
||||||
public class LocalLongHelper {
|
public class LocalLongHelper {
|
||||||
static StackWalker sw;
|
static StackWalker sw;
|
||||||
static Method intValue;
|
static Method longValue;
|
||||||
static Method getLocals;
|
static Method getLocals;
|
||||||
static Class<?> primitiveValueClass;
|
static Class<?> primitiveValueClass;
|
||||||
static Method primitiveType;
|
static Method primitiveSize;
|
||||||
static Method getMethodType;
|
static Method getMethodType;
|
||||||
static Field memberName;
|
static Field memberName;
|
||||||
static Field offset;
|
static Field offset;
|
||||||
|
@ -43,27 +43,29 @@ public class LocalLongHelper {
|
||||||
new LocalLongHelper().longArg(0xC0FFEE, 0x1234567890ABCDEFL);
|
new LocalLongHelper().longArg(0xC0FFEE, 0x1234567890ABCDEFL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// locals[2] contains the high byte of the long argument.
|
// locals[2] contains the unused slot of the long argument.
|
||||||
public long longArg(int i, long l) throws Throwable {
|
public long longArg(int i, long l) throws Throwable {
|
||||||
List<StackFrame> frames = sw.walk(s -> s.collect(Collectors.toList()));
|
List<StackFrame> frames = sw.walk(s -> s.collect(Collectors.toList()));
|
||||||
Object[] locals = (Object[]) getLocals.invoke(frames.get(0));
|
Object[] locals = (Object[]) getLocals.invoke(frames.get(0));
|
||||||
|
|
||||||
int locals_2 = (int) intValue.invoke(locals[2]);
|
if (8 == (int) primitiveSize.invoke(locals[2])) { // Only test 64-bit
|
||||||
if (locals_2 != 0){
|
long locals_2 = (long) longValue.invoke(locals[2]);
|
||||||
throw new RuntimeException("Expected locals_2 == 0");
|
if (locals_2 != 0){
|
||||||
|
throw new RuntimeException("Expected locals_2 == 0");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return l; // Don't want l to become a dead var
|
return l; // Don't want l to become a dead var
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setupReflectionStatics() throws Throwable {
|
private static void setupReflectionStatics() throws Throwable {
|
||||||
Class<?> liveStackFrameClass = Class.forName("java.lang.LiveStackFrame");
|
Class<?> liveStackFrameClass = Class.forName("java.lang.LiveStackFrame");
|
||||||
primitiveValueClass = Class.forName("java.lang.LiveStackFrame$PrimitiveValue");
|
primitiveValueClass = Class.forName("java.lang.LiveStackFrame$PrimitiveSlot");
|
||||||
|
|
||||||
getLocals = liveStackFrameClass.getDeclaredMethod("getLocals");
|
getLocals = liveStackFrameClass.getDeclaredMethod("getLocals");
|
||||||
getLocals.setAccessible(true);
|
getLocals.setAccessible(true);
|
||||||
|
|
||||||
intValue = primitiveValueClass.getDeclaredMethod("intValue");
|
longValue = primitiveValueClass.getDeclaredMethod("longValue");
|
||||||
intValue.setAccessible(true);
|
longValue.setAccessible(true);
|
||||||
|
|
||||||
Class<?> stackFrameInfoClass = Class.forName("java.lang.StackFrameInfo");
|
Class<?> stackFrameInfoClass = Class.forName("java.lang.StackFrameInfo");
|
||||||
memberName = stackFrameInfoClass.getDeclaredField("memberName");
|
memberName = stackFrameInfoClass.getDeclaredField("memberName");
|
||||||
|
@ -80,20 +82,8 @@ public class LocalLongHelper {
|
||||||
f.setAccessible(true);
|
f.setAccessible(true);
|
||||||
Object localsAndOperandsOption = f.get(null);
|
Object localsAndOperandsOption = f.get(null);
|
||||||
|
|
||||||
primitiveType = primitiveValueClass.getDeclaredMethod("type");
|
primitiveSize = primitiveValueClass.getDeclaredMethod("size");
|
||||||
primitiveType.setAccessible(true);
|
primitiveSize.setAccessible(true);
|
||||||
|
|
||||||
sw = (StackWalker) ewsNI.invoke(null, java.util.Collections.emptySet(), localsAndOperandsOption);
|
sw = (StackWalker) ewsNI.invoke(null, java.util.Collections.emptySet(), localsAndOperandsOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String type(Object o) throws Throwable {
|
|
||||||
if (primitiveValueClass.isInstance(o)) {
|
|
||||||
final char c = (char) primitiveType.invoke(o);
|
|
||||||
return String.valueOf(c);
|
|
||||||
} else if (o != null) {
|
|
||||||
return o.getClass().getName();
|
|
||||||
} else {
|
|
||||||
return "null";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue