8156073: 2-slot LiveStackFrame locals (long and double) are incorrect

Reviewed-by: coleenp, mchung
This commit is contained in:
Brent Christian 2017-01-31 11:50:42 -08:00
parent 95ff3ccdb4
commit c38ccc4fb0
6 changed files with 67 additions and 63 deletions

View file

@ -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) {

View file

@ -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();

View file

@ -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") \

View file

@ -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
#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,10 +240,20 @@ 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);
}
}

View file

@ -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);

View file

@ -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 (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";
}
}
}