Skip to content
This repository was archived by the owner on Aug 27, 2022. It is now read-only.

Commit b4d0186

Browse files
committed
8253525: Implement getInstanceSize/sizeOf intrinsics
Reviewed-by: kvn, sspitsyn
1 parent ea576dd commit b4d0186

File tree

12 files changed

+655
-0
lines changed

12 files changed

+655
-0
lines changed

src/hotspot/share/c1/c1_Compiler.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,8 @@ bool Compiler::is_intrinsic_supported(const methodHandle& method) {
228228
#endif
229229
#endif
230230
break;
231+
case vmIntrinsics::_getObjectSize:
232+
break;
231233
default:
232234
return false; // Intrinsics not on the previous list are not available.
233235
}

src/hotspot/share/c1/c1_LIRGenerator.cpp

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1323,6 +1323,108 @@ void LIRGenerator::do_currentThread(Intrinsic* x) {
13231323
LIR_OprFact::address(new LIR_Address(temp, T_OBJECT)), reg);
13241324
}
13251325

1326+
void LIRGenerator::do_getObjectSize(Intrinsic* x) {
1327+
assert(x->number_of_arguments() == 3, "wrong type");
1328+
LIR_Opr result_reg = rlock_result(x);
1329+
1330+
LIRItem value(x->argument_at(2), this);
1331+
value.load_item();
1332+
1333+
LIR_Opr klass = new_register(T_METADATA);
1334+
__ move(new LIR_Address(value.result(), oopDesc::klass_offset_in_bytes(), T_ADDRESS), klass, NULL);
1335+
LIR_Opr layout = new_register(T_INT);
1336+
__ move(new LIR_Address(klass, in_bytes(Klass::layout_helper_offset()), T_INT), layout);
1337+
1338+
LabelObj* L_done = new LabelObj();
1339+
LabelObj* L_array = new LabelObj();
1340+
1341+
__ cmp(lir_cond_lessEqual, layout, 0);
1342+
__ branch(lir_cond_lessEqual, L_array->label());
1343+
1344+
// Instance case: the layout helper gives us instance size almost directly,
1345+
// but we need to mask out the _lh_instance_slow_path_bit.
1346+
__ convert(Bytecodes::_i2l, layout, result_reg);
1347+
1348+
assert((int) Klass::_lh_instance_slow_path_bit < BytesPerLong, "clear bit");
1349+
jlong mask = ~(jlong) right_n_bits(LogBytesPerLong);
1350+
__ logical_and(result_reg, LIR_OprFact::longConst(mask), result_reg);
1351+
1352+
__ branch(lir_cond_always, L_done->label());
1353+
1354+
// Array case: size is round(header + element_size*arraylength).
1355+
// Since arraylength is different for every array instance, we have to
1356+
// compute the whole thing at runtime.
1357+
1358+
__ branch_destination(L_array->label());
1359+
1360+
int round_mask = MinObjAlignmentInBytes - 1;
1361+
1362+
// Figure out header sizes first.
1363+
LIR_Opr hss = LIR_OprFact::intConst(Klass::_lh_header_size_shift);
1364+
LIR_Opr hsm = LIR_OprFact::intConst(Klass::_lh_header_size_mask);
1365+
1366+
LIR_Opr header_size = new_register(T_INT);
1367+
__ move(layout, header_size);
1368+
LIR_Opr tmp = new_register(T_INT);
1369+
__ unsigned_shift_right(header_size, hss, header_size, tmp);
1370+
__ logical_and(header_size, hsm, header_size);
1371+
__ add(header_size, LIR_OprFact::intConst(round_mask), header_size);
1372+
1373+
// Figure out the array length in bytes
1374+
assert(Klass::_lh_log2_element_size_shift == 0, "use shift in place");
1375+
LIR_Opr l2esm = LIR_OprFact::intConst(Klass::_lh_log2_element_size_mask);
1376+
__ logical_and(layout, l2esm, layout);
1377+
1378+
LIR_Opr length_int = new_register(T_INT);
1379+
__ move(new LIR_Address(value.result(), arrayOopDesc::length_offset_in_bytes(), T_INT), length_int);
1380+
1381+
#ifdef _LP64
1382+
LIR_Opr length = new_register(T_LONG);
1383+
__ convert(Bytecodes::_i2l, length_int, length);
1384+
#endif
1385+
1386+
// Shift-left awkwardness. Normally it is just:
1387+
// __ shift_left(length, layout, length);
1388+
// But C1 cannot perform shift_left with non-constant count, so we end up
1389+
// doing the per-bit loop dance here. x86_32 also does not know how to shift
1390+
// longs, so we have to act on ints.
1391+
LabelObj* L_shift_loop = new LabelObj();
1392+
LabelObj* L_shift_exit = new LabelObj();
1393+
1394+
__ branch_destination(L_shift_loop->label());
1395+
__ cmp(lir_cond_equal, layout, 0);
1396+
__ branch(lir_cond_equal, L_shift_exit->label());
1397+
1398+
#ifdef _LP64
1399+
__ shift_left(length, 1, length);
1400+
#else
1401+
__ shift_left(length_int, 1, length_int);
1402+
#endif
1403+
1404+
__ sub(layout, LIR_OprFact::intConst(1), layout);
1405+
1406+
__ branch(lir_cond_always, L_shift_loop->label());
1407+
__ branch_destination(L_shift_exit->label());
1408+
1409+
// Mix all up, round, and push to the result.
1410+
#ifdef _LP64
1411+
LIR_Opr header_size_long = new_register(T_LONG);
1412+
__ convert(Bytecodes::_i2l, header_size, header_size_long);
1413+
__ add(length, header_size_long, length);
1414+
if (round_mask != 0) {
1415+
__ logical_and(length, LIR_OprFact::longConst(~round_mask), length);
1416+
}
1417+
__ move(length, result_reg);
1418+
#else
1419+
__ add(length_int, header_size, length_int);
1420+
if (round_mask != 0) {
1421+
__ logical_and(length_int, LIR_OprFact::intConst(~round_mask), length_int);
1422+
}
1423+
__ convert(Bytecodes::_i2l, length_int, result_reg);
1424+
#endif
1425+
1426+
__ branch_destination(L_done->label());
1427+
}
13261428

13271429
void LIRGenerator::do_RegisterFinalizer(Intrinsic* x) {
13281430
assert(x->number_of_arguments() == 1, "wrong type");
@@ -3044,6 +3146,7 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) {
30443146
case vmIntrinsics::_isPrimitive: do_isPrimitive(x); break;
30453147
case vmIntrinsics::_getClass: do_getClass(x); break;
30463148
case vmIntrinsics::_currentThread: do_currentThread(x); break;
3149+
case vmIntrinsics::_getObjectSize: do_getObjectSize(x); break;
30473150

30483151
case vmIntrinsics::_dlog: // fall through
30493152
case vmIntrinsics::_dlog10: // fall through

src/hotspot/share/c1/c1_LIRGenerator.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
253253
void do_isPrimitive(Intrinsic* x);
254254
void do_getClass(Intrinsic* x);
255255
void do_currentThread(Intrinsic* x);
256+
void do_getObjectSize(Intrinsic* x);
256257
void do_FmaIntrinsic(Intrinsic* x);
257258
void do_MathIntrinsic(Intrinsic* x);
258259
void do_LibmIntrinsic(Intrinsic* x);

src/hotspot/share/classfile/vmIntrinsics.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,10 @@ class methodHandle;
524524
do_name( isCompileConstant_name, "isCompileConstant") \
525525
do_alias( isCompileConstant_signature, object_boolean_signature) \
526526
\
527+
do_intrinsic(_getObjectSize, sun_instrument_InstrumentationImpl, getObjectSize_name, getObjectSize_signature, F_RN) \
528+
do_name( getObjectSize_name, "getObjectSize0") \
529+
do_alias( getObjectSize_signature, long_object_long_signature) \
530+
\
527531
/* unsafe memory references (there are a lot of them...) */ \
528532
do_signature(getReference_signature, "(Ljava/lang/Object;J)Ljava/lang/Object;") \
529533
do_signature(putReference_signature, "(Ljava/lang/Object;JLjava/lang/Object;)V") \

src/hotspot/share/classfile/vmSymbols.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@
139139
template(sun_net_www_ParseUtil, "sun/net/www/ParseUtil") \
140140
template(java_util_Iterator, "java/util/Iterator") \
141141
template(java_lang_Record, "java/lang/Record") \
142+
template(sun_instrument_InstrumentationImpl, "sun/instrument/InstrumentationImpl") \
142143
\
143144
template(jdk_internal_loader_NativeLibraries, "jdk/internal/loader/NativeLibraries") \
144145
template(jdk_internal_loader_BuiltinClassLoader, "jdk/internal/loader/BuiltinClassLoader") \
@@ -521,6 +522,7 @@
521522
template(int_array_signature, "[I") \
522523
template(object_void_signature, "(Ljava/lang/Object;)V") \
523524
template(object_int_signature, "(Ljava/lang/Object;)I") \
525+
template(long_object_long_signature, "(JLjava/lang/Object;)J") \
524526
template(object_boolean_signature, "(Ljava/lang/Object;)Z") \
525527
template(object_object_signature, "(Ljava/lang/Object;)Ljava/lang/Object;") \
526528
template(string_void_signature, "(Ljava/lang/String;)V") \

src/hotspot/share/opto/c2compiler.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,7 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt
649649
case vmIntrinsics::_profileBoolean:
650650
case vmIntrinsics::_isCompileConstant:
651651
case vmIntrinsics::_Preconditions_checkIndex:
652+
case vmIntrinsics::_getObjectSize:
652653
break;
653654

654655
case vmIntrinsics::_VectorUnaryOp:

src/hotspot/share/opto/library_call.cpp

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,9 @@ bool LibraryCallKit::try_to_inline(int predicate) {
661661
case vmIntrinsics::_VectorExtract:
662662
return inline_vector_extract();
663663

664+
case vmIntrinsics::_getObjectSize:
665+
return inline_getObjectSize();
666+
664667
default:
665668
// If you get here, it may be that someone has added a new intrinsic
666669
// to the list in vmSymbols.hpp without implementing it here.
@@ -6692,3 +6695,119 @@ bool LibraryCallKit::inline_isCompileConstant() {
66926695
set_result(n->is_Con() ? intcon(1) : intcon(0));
66936696
return true;
66946697
}
6698+
6699+
//------------------------------- inline_getObjectSize --------------------------------------
6700+
//
6701+
// Calculate the runtime size of the object/array.
6702+
// native long sun.instrument.InstrumentationImpl.getObjectSize0(long nativeAgent, Object objectToSize);
6703+
//
6704+
bool LibraryCallKit::inline_getObjectSize() {
6705+
Node* obj = argument(3);
6706+
Node* klass_node = load_object_klass(obj);
6707+
6708+
jint layout_con = Klass::_lh_neutral_value;
6709+
Node* layout_val = get_layout_helper(klass_node, layout_con);
6710+
int layout_is_con = (layout_val == NULL);
6711+
6712+
if (layout_is_con) {
6713+
// Layout helper is constant, can figure out things at compile time.
6714+
6715+
if (Klass::layout_helper_is_instance(layout_con)) {
6716+
// Instance case: layout_con contains the size itself.
6717+
Node *size = longcon(Klass::layout_helper_size_in_bytes(layout_con));
6718+
set_result(size);
6719+
} else {
6720+
// Array case: size is round(header + element_size*arraylength).
6721+
// Since arraylength is different for every array instance, we have to
6722+
// compute the whole thing at runtime.
6723+
6724+
Node* arr_length = load_array_length(obj);
6725+
6726+
int round_mask = MinObjAlignmentInBytes - 1;
6727+
int hsize = Klass::layout_helper_header_size(layout_con);
6728+
int eshift = Klass::layout_helper_log2_element_size(layout_con);
6729+
6730+
if ((round_mask & ~right_n_bits(eshift)) == 0) {
6731+
round_mask = 0; // strength-reduce it if it goes away completely
6732+
}
6733+
assert((hsize & right_n_bits(eshift)) == 0, "hsize is pre-rounded");
6734+
Node* header_size = intcon(hsize + round_mask);
6735+
6736+
Node* lengthx = ConvI2X(arr_length);
6737+
Node* headerx = ConvI2X(header_size);
6738+
6739+
Node* abody = lengthx;
6740+
if (eshift != 0) {
6741+
abody = _gvn.transform(new LShiftXNode(lengthx, intcon(eshift)));
6742+
}
6743+
Node* size = _gvn.transform( new AddXNode(headerx, abody) );
6744+
if (round_mask != 0) {
6745+
size = _gvn.transform( new AndXNode(size, MakeConX(~round_mask)) );
6746+
}
6747+
size = ConvX2L(size);
6748+
set_result(size);
6749+
}
6750+
} else {
6751+
// Layout helper is not constant, need to test for array-ness at runtime.
6752+
6753+
enum { _instance_path = 1, _array_path, PATH_LIMIT };
6754+
RegionNode* result_reg = new RegionNode(PATH_LIMIT);
6755+
PhiNode* result_val = new PhiNode(result_reg, TypeLong::LONG);
6756+
record_for_igvn(result_reg);
6757+
6758+
Node* array_ctl = generate_array_guard(klass_node, NULL);
6759+
if (array_ctl != NULL) {
6760+
// Array case: size is round(header + element_size*arraylength).
6761+
// Since arraylength is different for every array instance, we have to
6762+
// compute the whole thing at runtime.
6763+
6764+
PreserveJVMState pjvms(this);
6765+
set_control(array_ctl);
6766+
Node* arr_length = load_array_length(obj);
6767+
6768+
int round_mask = MinObjAlignmentInBytes - 1;
6769+
Node* mask = intcon(round_mask);
6770+
6771+
Node* hss = intcon(Klass::_lh_header_size_shift);
6772+
Node* hsm = intcon(Klass::_lh_header_size_mask);
6773+
Node* header_size = _gvn.transform(new URShiftINode(layout_val, hss));
6774+
header_size = _gvn.transform(new AndINode(header_size, hsm));
6775+
header_size = _gvn.transform(new AddINode(header_size, mask));
6776+
6777+
// There is no need to mask or shift this value.
6778+
// The semantics of LShiftINode include an implicit mask to 0x1F.
6779+
assert(Klass::_lh_log2_element_size_shift == 0, "use shift in place");
6780+
Node* elem_shift = layout_val;
6781+
6782+
Node* lengthx = ConvI2X(arr_length);
6783+
Node* headerx = ConvI2X(header_size);
6784+
6785+
Node* abody = _gvn.transform(new LShiftXNode(lengthx, elem_shift));
6786+
Node* size = _gvn.transform(new AddXNode(headerx, abody));
6787+
if (round_mask != 0) {
6788+
size = _gvn.transform(new AndXNode(size, MakeConX(~round_mask)));
6789+
}
6790+
size = ConvX2L(size);
6791+
6792+
result_reg->init_req(_array_path, control());
6793+
result_val->init_req(_array_path, size);
6794+
}
6795+
6796+
if (!stopped()) {
6797+
// Instance case: the layout helper gives us instance size almost directly,
6798+
// but we need to mask out the _lh_instance_slow_path_bit.
6799+
Node* size = ConvI2X(layout_val);
6800+
assert((int) Klass::_lh_instance_slow_path_bit < BytesPerLong, "clear bit");
6801+
Node* mask = MakeConX(~(intptr_t) right_n_bits(LogBytesPerLong));
6802+
size = _gvn.transform(new AndXNode(size, mask));
6803+
size = ConvX2L(size);
6804+
6805+
result_reg->init_req(_instance_path, control());
6806+
result_val->init_req(_instance_path, size);
6807+
}
6808+
6809+
set_result(result_reg, result_val);
6810+
}
6811+
6812+
return true;
6813+
}

src/hotspot/share/opto/library_call.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,5 +344,7 @@ class LibraryCallKit : public GraphKit {
344344
}
345345
#endif
346346
}
347+
348+
bool inline_getObjectSize();
347349
};
348350

src/java.base/share/classes/module-info.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@
230230
jdk.internal.jvmstat,
231231
jdk.management.agent;
232232
exports jdk.internal.vm.annotation to
233+
java.instrument,
233234
jdk.internal.vm.ci,
234235
jdk.incubator.vector,
235236
jdk.incubator.foreign,

src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import java.util.jar.JarFile;
4545

4646
import jdk.internal.module.Modules;
47+
import jdk.internal.vm.annotation.IntrinsicCandidate;
4748

4849
/*
4950
* Copyright 2003 Wily Technology, Inc.
@@ -392,6 +393,7 @@ public void redefineModule(Module module,
392393
private native Class[]
393394
getInitiatedClasses0(long nativeAgent, ClassLoader loader);
394395

396+
@IntrinsicCandidate
395397
private native long
396398
getObjectSize0(long nativeAgent, Object objectToSize);
397399

0 commit comments

Comments
 (0)