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(_locals_offset, k, vmSymbols::locals_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() {
|
||||
|
@ -3658,6 +3659,7 @@ int java_lang_StackFrameInfo::_version_offset;
|
|||
int java_lang_LiveStackFrameInfo::_monitors_offset;
|
||||
int java_lang_LiveStackFrameInfo::_locals_offset;
|
||||
int java_lang_LiveStackFrameInfo::_operands_offset;
|
||||
int java_lang_LiveStackFrameInfo::_mode_offset;
|
||||
int java_lang_AssertionStatusDirectives::classes_offset;
|
||||
int java_lang_AssertionStatusDirectives::classEnabled_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);
|
||||
}
|
||||
|
||||
void java_lang_LiveStackFrameInfo::set_mode(oop element, int value) {
|
||||
element->int_field_put(_mode_offset, value);
|
||||
}
|
||||
|
||||
// Support for java Assertions - java_lang_AssertionStatusDirectives.
|
||||
|
||||
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 _locals_offset;
|
||||
static int _operands_offset;
|
||||
static int _mode_offset;
|
||||
|
||||
public:
|
||||
static void set_monitors(oop info, oop value);
|
||||
static void set_locals(oop info, oop value);
|
||||
static void set_operands(oop info, oop value);
|
||||
static void set_mode(oop info, int value);
|
||||
|
||||
static void compute_offsets();
|
||||
|
||||
|
|
|
@ -325,14 +325,8 @@
|
|||
template(java_lang_StackStreamFactory_AbstractStackWalker, "java/lang/StackStreamFactory$AbstractStackWalker") \
|
||||
template(doStackWalk_signature, "(JIIII)Ljava/lang/Object;") \
|
||||
template(asPrimitive_name, "asPrimitive") \
|
||||
template(asPrimitive_int_signature, "(I)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
|
||||
template(asPrimitive_long_signature, "(J)Ljava/lang/LiveStackFrame$PrimitiveValue;") \
|
||||
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;") \
|
||||
template(asPrimitive_int_signature, "(I)Ljava/lang/LiveStackFrame$PrimitiveSlot;") \
|
||||
template(asPrimitive_long_signature, "(J)Ljava/lang/LiveStackFrame$PrimitiveSlot;") \
|
||||
\
|
||||
/* common method and field names */ \
|
||||
template(object_initializer_name, "<init>") \
|
||||
|
@ -444,6 +438,7 @@
|
|||
template(monitors_name, "monitors") \
|
||||
template(locals_name, "locals") \
|
||||
template(operands_name, "operands") \
|
||||
template(mode_name, "mode") \
|
||||
template(oop_size_name, "oop_size") \
|
||||
template(static_oop_field_count_name, "static_oop_field_count") \
|
||||
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);
|
||||
instanceKlassHandle ik (THREAD, k);
|
||||
|
||||
|
@ -182,8 +186,8 @@ oop LiveFrameStream::create_primitive_value_instance(StackValueCollection* value
|
|||
Symbol* signature = NULL;
|
||||
|
||||
// ## TODO: type is only available in LocalVariable table, if present.
|
||||
// ## StackValue type is T_INT or T_OBJECT.
|
||||
switch (values->at(i)->type()) {
|
||||
// ## StackValue type is T_INT or T_OBJECT (or converted to T_LONG on 64-bit)
|
||||
switch (type) {
|
||||
case T_INT:
|
||||
args.push_int(values->int_at(i));
|
||||
signature = vmSymbols::asPrimitive_int_signature();
|
||||
|
@ -195,42 +199,26 @@ oop LiveFrameStream::create_primitive_value_instance(StackValueCollection* value
|
|||
break;
|
||||
|
||||
case T_FLOAT:
|
||||
args.push_float(values->float_at(i));
|
||||
signature = vmSymbols::asPrimitive_float_signature();
|
||||
break;
|
||||
|
||||
case T_DOUBLE:
|
||||
args.push_double(values->double_at(i));
|
||||
signature = vmSymbols::asPrimitive_double_signature();
|
||||
break;
|
||||
|
||||
case T_BYTE:
|
||||
args.push_int(values->int_at(i));
|
||||
signature = vmSymbols::asPrimitive_byte_signature();
|
||||
break;
|
||||
|
||||
case T_SHORT:
|
||||
args.push_int(values->int_at(i));
|
||||
signature = vmSymbols::asPrimitive_short_signature();
|
||||
break;
|
||||
|
||||
case T_CHAR:
|
||||
args.push_int(values->int_at(i));
|
||||
signature = vmSymbols::asPrimitive_char_signature();
|
||||
break;
|
||||
|
||||
case T_BOOLEAN:
|
||||
args.push_int(values->int_at(i));
|
||||
signature = vmSymbols::asPrimitive_boolean_signature();
|
||||
break;
|
||||
THROW_MSG_(vmSymbols::java_lang_InternalError(), "Unexpected StackValue type", NULL);
|
||||
|
||||
case T_OBJECT:
|
||||
return values->obj_at(i)();
|
||||
|
||||
case T_CONFLICT:
|
||||
// put a non-null slot
|
||||
args.push_int(0);
|
||||
signature = vmSymbols::asPrimitive_int_signature();
|
||||
#ifdef _LP64
|
||||
args.push_long(0);
|
||||
signature = vmSymbols::asPrimitive_long_signature();
|
||||
#else
|
||||
args.push_int(0);
|
||||
signature = vmSymbols::asPrimitive_int_signature();
|
||||
#endif
|
||||
|
||||
break;
|
||||
|
||||
default: ShouldNotReachHere();
|
||||
|
@ -252,9 +240,19 @@ objArrayHandle LiveFrameStream::values_to_object_array(StackValueCollection* val
|
|||
objArrayHandle array_h(THREAD, array_oop);
|
||||
for (int i = 0; i < values->size(); i++) {
|
||||
StackValue* st = values->at(i);
|
||||
oop obj = create_primitive_value_instance(values, i, CHECK_(empty));
|
||||
if (obj != NULL)
|
||||
BasicType type = st->type();
|
||||
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);
|
||||
}
|
||||
}
|
||||
return array_h;
|
||||
}
|
||||
|
@ -286,6 +284,13 @@ void LiveFrameStream::fill_live_stackframe(Handle stackFrame,
|
|||
StackValueCollection* expressions = _jvf->expressions();
|
||||
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()) {
|
||||
objArrayHandle locals_h = values_to_object_array(locals, CHECK);
|
||||
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);
|
||||
java_lang_LiveStackFrameInfo::set_monitors(stackFrame(), monitors_h());
|
||||
}
|
||||
java_lang_LiveStackFrameInfo::set_mode(stackFrame(), mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -92,11 +92,16 @@ public:
|
|||
|
||||
class LiveFrameStream : public BaseFrameStream {
|
||||
private:
|
||||
enum {
|
||||
MODE_INTERPRETED = 0x01,
|
||||
MODE_COMPILED = 0x02
|
||||
};
|
||||
|
||||
javaVFrame* _jvf;
|
||||
|
||||
void fill_live_stackframe(Handle stackFrame, const methodHandle& method, TRAPS);
|
||||
static oop create_primitive_value_instance(StackValueCollection* values,
|
||||
int i, TRAPS);
|
||||
static oop create_primitive_slot_instance(StackValueCollection* values,
|
||||
int i, BasicType type, TRAPS);
|
||||
static objArrayHandle monitors_to_object_array(GrowableArray<MonitorInfo*>* monitors,
|
||||
TRAPS);
|
||||
static objArrayHandle values_to_object_array(StackValueCollection* values, TRAPS);
|
||||
|
|
|
@ -30,10 +30,10 @@ import java.lang.StackWalker.StackFrame;
|
|||
|
||||
public class LocalLongHelper {
|
||||
static StackWalker sw;
|
||||
static Method intValue;
|
||||
static Method longValue;
|
||||
static Method getLocals;
|
||||
static Class<?> primitiveValueClass;
|
||||
static Method primitiveType;
|
||||
static Method primitiveSize;
|
||||
static Method getMethodType;
|
||||
static Field memberName;
|
||||
static Field offset;
|
||||
|
@ -43,27 +43,29 @@ public class LocalLongHelper {
|
|||
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 {
|
||||
List<StackFrame> frames = sw.walk(s -> s.collect(Collectors.toList()));
|
||||
Object[] locals = (Object[]) getLocals.invoke(frames.get(0));
|
||||
|
||||
int locals_2 = (int) intValue.invoke(locals[2]);
|
||||
if (locals_2 != 0){
|
||||
throw new RuntimeException("Expected locals_2 == 0");
|
||||
if (8 == (int) primitiveSize.invoke(locals[2])) { // Only test 64-bit
|
||||
long locals_2 = (long) longValue.invoke(locals[2]);
|
||||
if (locals_2 != 0){
|
||||
throw new RuntimeException("Expected locals_2 == 0");
|
||||
}
|
||||
}
|
||||
return l; // Don't want l to become a dead var
|
||||
}
|
||||
|
||||
private static void setupReflectionStatics() throws Throwable {
|
||||
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.setAccessible(true);
|
||||
|
||||
intValue = primitiveValueClass.getDeclaredMethod("intValue");
|
||||
intValue.setAccessible(true);
|
||||
longValue = primitiveValueClass.getDeclaredMethod("longValue");
|
||||
longValue.setAccessible(true);
|
||||
|
||||
Class<?> stackFrameInfoClass = Class.forName("java.lang.StackFrameInfo");
|
||||
memberName = stackFrameInfoClass.getDeclaredField("memberName");
|
||||
|
@ -80,20 +82,8 @@ public class LocalLongHelper {
|
|||
f.setAccessible(true);
|
||||
Object localsAndOperandsOption = f.get(null);
|
||||
|
||||
primitiveType = primitiveValueClass.getDeclaredMethod("type");
|
||||
primitiveType.setAccessible(true);
|
||||
|
||||
primitiveSize = primitiveValueClass.getDeclaredMethod("size");
|
||||
primitiveSize.setAccessible(true);
|
||||
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