8156073: 2-slot LiveStackFrame locals (long and double) are incorrect
Reviewed-by: coleenp, mchung
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp Tue Jan 31 01:11:40 2017 +0300
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Tue Jan 31 11:50:42 2017 -0800
@@ -2269,6 +2269,7 @@
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_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 @@
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) {
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp Tue Jan 31 01:11:40 2017 +0300
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Tue Jan 31 11:50:42 2017 -0800
@@ -1380,11 +1380,13 @@
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();
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Tue Jan 31 01:11:40 2017 +0300
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Tue Jan 31 11:50:42 2017 -0800
@@ -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") \
--- a/hotspot/src/share/vm/prims/stackwalk.cpp Tue Jan 31 01:11:40 2017 +0300
+++ b/hotspot/src/share/vm/prims/stackwalk.cpp Tue Jan 31 11:50:42 2017 -0800
@@ -173,7 +173,11 @@
}
}
-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 @@
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 @@
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 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 @@
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 @@
objArrayHandle monitors_h = monitors_to_object_array(monitors, CHECK);
java_lang_LiveStackFrameInfo::set_monitors(stackFrame(), monitors_h());
}
+ java_lang_LiveStackFrameInfo::set_mode(stackFrame(), mode);
}
}
--- a/hotspot/src/share/vm/prims/stackwalk.hpp Tue Jan 31 01:11:40 2017 +0300
+++ b/hotspot/src/share/vm/prims/stackwalk.hpp Tue Jan 31 11:50:42 2017 -0800
@@ -92,11 +92,16 @@
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);
--- a/hotspot/test/runtime/LocalLong/LocalLongHelper.java Tue Jan 31 01:11:40 2017 +0300
+++ b/hotspot/test/runtime/LocalLong/LocalLongHelper.java Tue Jan 31 11:50:42 2017 -0800
@@ -30,10 +30,10 @@
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 @@
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 @@
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";
- }
- }
}