Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JDK-8269408: [lworld] [lqagain] Withfield and field resolution update #465

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -3181,7 +3181,14 @@ void TemplateTable::withfield() {

resolve_cache_and_index(f2_byte, cache, index, sizeof(u2));

call_VM(rbx, CAST_FROM_FN_PTR(address, InterpreterRuntime::withfield), cache);
Register cpentry = rbx;

ByteSize cp_base_offset = ConstantPoolCache::base_offset();

__ lea(cpentry, Address(cache, index, Address::times_ptr,
in_bytes(cp_base_offset)));
__ lea(rax, at_tos());
__ call_VM(rbx, CAST_FROM_FN_PTR(address, InterpreterRuntime::withfield2), cpentry, rax);
// new value type is returned in rbx
// stack adjustement is returned in rax
__ verify_oop(rbx);
@@ -306,6 +306,7 @@ JRT_ENTRY(void, InterpreterRuntime::defaultvalue(JavaThread* current, ConstantPo
current->set_vm_result(res);
JRT_END

// withfield support used by aarch64 but not x86 (see withfield2 below)
JRT_ENTRY(int, InterpreterRuntime::withfield(JavaThread* current, ConstantPoolCache* cp_cache))
LastFrameAccessor last_frame(current);
// Getting the InlineKlass
@@ -329,7 +330,11 @@ JRT_ENTRY(int, InterpreterRuntime::withfield(JavaThread* current, ConstantPoolCa
jint tos_idx = f.interpreter_frame_expression_stack_size() - 1;
int vt_offset = type2size[field_type];
oop old_value = *(oop*)f.interpreter_frame_expression_stack_at(tos_idx - vt_offset);
assert(old_value != NULL && oopDesc::is_oop(old_value) && old_value->is_inline_type(),"Verifying receiver");
if (old_value == NULL) {
THROW_(vmSymbols::java_lang_NullPointerException(), return_offset);
}
assert(oopDesc::is_oop(old_value), "Verifying receiver");
assert(old_value->klass()->is_inline_klass(), "Must have been checked during resolution");
Handle old_value_h(THREAD, old_value);

// Creating new value by copying the one passed in argument
@@ -368,6 +373,79 @@ JRT_ENTRY(int, InterpreterRuntime::withfield(JavaThread* current, ConstantPoolCa
return return_offset;
JRT_END

// withfield support for x86, avoiding costly calls to retrieve last Java frame
JRT_ENTRY(int, InterpreterRuntime::withfield2(JavaThread* current, ConstantPoolCacheEntry* cpe, uintptr_t ptr))
oop obj = NULL;
int recv_offset = type2size[as_BasicType(cpe->flag_state())];
assert(frame::interpreter_frame_expression_stack_direction() == -1, "currently is -1 on all platforms");
int ret_adj = (recv_offset + type2size[T_OBJECT] )* AbstractInterpreter::stackElementSize;
obj = (oopDesc*)(((uintptr_t*)ptr)[recv_offset * Interpreter::stackElementWords]);
if (obj == NULL) {
THROW_(vmSymbols::java_lang_NullPointerException(), ret_adj);
}
assert(oopDesc::is_oop(obj), "Verifying receiver");
assert(obj->klass()->is_inline_klass(), "Must have been checked during resolution");
instanceHandle old_value_h(THREAD, (instanceOop)obj);
oop ref = NULL;
if (cpe->flag_state() == atos) {
ref = *(oopDesc**)ptr;
}
Handle ref_h(THREAD, ref);
InlineKlass* ik = InlineKlass::cast(old_value_h()->klass());
instanceOop new_value = ik->allocate_instance_buffer(CHECK_(ret_adj));
Handle new_value_h = Handle(THREAD, new_value);
ik->inline_copy_oop_to_new_oop(old_value_h(), new_value_h());
int offset = cpe->f2_as_offset();
switch(cpe->flag_state()) {
case ztos:
new_value_h()->bool_field_put(offset, (jboolean)(*(jint*)ptr));
break;
case btos:
new_value_h()->byte_field_put(offset, (jbyte)(*(jint*)ptr));
break;
case ctos:
new_value_h()->char_field_put(offset, (jchar)(*(jint*)ptr));
break;
case stos:
new_value_h()->short_field_put(offset, (jshort)(*(jint*)ptr));
break;
case itos:
new_value_h()->int_field_put(offset, (*(jint*)ptr));
break;
case ltos:
new_value_h()->long_field_put(offset, *(jlong*)ptr);
break;
case ftos:
new_value_h()->float_field_put(offset, *(jfloat*)ptr);
break;
case dtos:
new_value_h()->double_field_put(offset, *(jdouble*)ptr);
break;
case atos:
{
if (cpe->is_null_free_inline_type()) {
if (!cpe->is_inlined()) {
if (ref_h() == NULL) {
THROW_(vmSymbols::java_lang_NullPointerException(), ret_adj);
}
new_value_h()->obj_field_put(offset, ref_h());
} else {
int field_index = cpe->field_index();
InlineKlass* field_ik = InlineKlass::cast(ik->get_inline_type_field_klass(field_index));
field_ik->write_inlined_field(new_value_h(), offset, ref_h(), CHECK_(ret_adj));
}
} else {
new_value_h()->obj_field_put(offset, ref_h());
}
}
break;
default:
ShouldNotReachHere();
}
current->set_vm_result(new_value_h());
return ret_adj;
JRT_END

JRT_ENTRY(void, InterpreterRuntime::uninitialized_static_inline_type_field(JavaThread* current, oopDesc* mirror, int index))
// The interpreter tries to access an inline static field that has not been initialized.
// This situation can happen in different scenarios:
@@ -66,6 +66,7 @@ class InterpreterRuntime: AllStatic {
static void register_finalizer(JavaThread* current, oopDesc* obj);
static void defaultvalue (JavaThread* current, ConstantPool* pool, int index);
static int withfield (JavaThread* current, ConstantPoolCache* cp_cache);
static int withfield2 (JavaThread* current, ConstantPoolCacheEntry* cpe, uintptr_t ptr);
static void uninitialized_static_inline_type_field(JavaThread* current, oopDesc* mirror, int offset);
static void write_heap_copy (JavaThread* current, oopDesc* value, int offset, oopDesc* rcv);
static void read_inlined_field(JavaThread* current, oopDesc* value, int index, Klass* field_holder);
@@ -970,6 +970,20 @@ void LinkResolver::resolve_field(fieldDescriptor& fd,
THROW_MSG(vmSymbols::java_lang_NoSuchFieldError(), field->as_C_string());
}

if (byte == Bytecodes::_withfield && !resolved_klass->is_inline_klass()) {
ResourceMark rm(THREAD);
char msg[200];
jio_snprintf(msg, sizeof(msg), "Bytecode withfield cannot be used on identity class %s", resolved_klass->external_name());
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), msg);
}

if (is_put && !is_static && byte != Bytecodes::_withfield && resolved_klass->is_inline_klass()) {
ResourceMark rm(THREAD);
char msg[200];
jio_snprintf(msg, sizeof(msg), "Bytecode putfield cannot be used on primitive class %s", resolved_klass->external_name());
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), msg);
}

// Resolve instance field
Klass* sel_klass = resolved_klass->find_field(field, sig, &fd);
// check if field exists; i.e., if a klass containing the field def has been selected
@@ -59,6 +59,11 @@ static Point make(int x, int y) {
y = 0;
}

Point (int x, int y) {
this.x = x;
this.y = y;
}

public int getX() {
return x;
}
@@ -78,11 +83,132 @@ static Point setY(Point p, int y) {
}
}

static primitive class TestValue {
boolean z = false;
static boolean[] z_values = new boolean[] { false, true, false};
byte b = 0;
static byte[] b_values = new byte[] { 0, 125, -111};
short s = 0;
static short[] s_values = new short[] { 0, 32654, -31836};
char c = 0;
static char[] c_values = new char[] { 0, 1, 65528};
int i = 0;
static int[] i_values = new int[] { 0, 2137523847, -2037453241};
long l = 0;
static long[] l_values = new long[] { 0, 9123456036854775807L, -9112272036854775507L};
float f = 0.0f;
static float[] f_values = new float[] { 0.0f, 1.52758043e7f, -7.93757e-5f};
double d = 0.0d;
static double[] d_values = new double[] { 0.0d, 3.304786e9d, -0.7548345e-15d};
Object o = null;
static Object[] o_values = new Object[] { null, "Hello", "Duke"};
Point p = new Point(0, 0);
static Point[] p_values = new Point[] { new Point(0, 0), new Point(-1, 1), new Point(1, -1)};
int[] map = new int[10];

TestValue set_z(int i) {
TestValue t = __WithField(this.z, z_values[i]);
t.map[0] = i;
return t;
}

TestValue set_b(int i) {
TestValue t = __WithField(this.b, b_values[i]);
t.map[1] = i;
return t;
}

TestValue set_s(int i) {
TestValue t = __WithField(this.s, s_values[i]);
t.map[2] = i;
return t;
}

TestValue set_c(int i) {
TestValue t = __WithField(this.c, c_values[i]);
t.map[3] = i;
return t;
}

TestValue set_i(int i) {
TestValue t = __WithField(this.i, i_values[i]);
t.map[4] = i;
return t;
}

TestValue set_l(int i) {
TestValue t = __WithField(this.l, l_values[i]);
t.map[5] = i;
return t;
}

TestValue set_f(int i) {
TestValue t = __WithField(this.f, f_values[i]);
t.map[6] = i;
return t;
}

TestValue set_d(int i) {
TestValue t = __WithField(this.d, d_values[i]);
t.map[7] = i;
return t;
}

TestValue set_o(int i) {
TestValue t = __WithField(this.o, o_values[i]);
t.map[8] = i;
return t;
}

TestValue set_p(int i) {
TestValue t = __WithField(this.p, p_values[i]);
t.map[9] = i;
return t;
}

void verify() {
Asserts.assertEquals(z, z_values[map[0]]);
Asserts.assertEquals(b, b_values[map[1]]);
Asserts.assertEquals(s, s_values[map[2]]);
Asserts.assertEquals(c, c_values[map[3]]);
Asserts.assertEquals(i, i_values[map[4]]);
Asserts.assertEquals(l, l_values[map[5]]);
Asserts.assertEquals(f, f_values[map[6]]);
Asserts.assertEquals(d, d_values[map[7]]);
Asserts.assertEquals(o, o_values[map[8]]);
Asserts.assertEquals(p, p_values[map[9]]);
}

static void test() {
TestValue value = new TestValue();
value.verify();
for (int i = 2; i >= 0; i--) {
value = value.set_z(i);
value.verify();
value = value.set_b(i);
value.verify();
value = value.set_s(i);
value.verify();
value = value.set_c(i);
value.verify();
value = value.set_i(i);
value.verify();
value = value.set_l(i);
value.verify();
value = value.set_f(i);
value.verify();
value = value.set_d(i);
value.verify();
}
}
}

public static void main(String[] args) {
creationTest();
creationTest();
witherTest();
witherTest();
TestValue.test();
}

static void creationTest() {