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(_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) {

View file

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

View file

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

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

View file

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

View file

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