|
40 | 40 | #include "opto/locknode.hpp" |
41 | 41 | #include "opto/machnode.hpp" |
42 | 42 | #include "opto/matcher.hpp" |
43 | | -#include "opto/memnode.hpp" |
44 | 43 | #include "opto/movenode.hpp" |
45 | 44 | #include "opto/parse.hpp" |
46 | 45 | #include "opto/regalloc.hpp" |
@@ -1185,14 +1184,58 @@ Node* CallStaticJavaNode::Ideal(PhaseGVN* phase, bool can_reshape) { |
1185 | 1184 | } |
1186 | 1185 | } |
1187 | 1186 |
|
1188 | | - // Try to replace the runtime call to the substitutability test emitted by acmp if we can reason |
1189 | | - // about the operands |
1190 | | - if (can_reshape && !control()->is_top() && method() != nullptr && |
1191 | | - method()->holder() == phase->C->env()->ValueObjectMethods_klass() && |
1192 | | - method()->name() == ciSymbols::isSubstitutable_name()) { |
1193 | | - Node* res = replace_is_substitutable(phase->is_IterGVN()); |
1194 | | - if (res != nullptr) { |
1195 | | - return res; |
| 1187 | + // Try to replace the runtime call to the substitutability test emitted by acmp if (at least) one operand is a known type |
| 1188 | + if (can_reshape && !control()->is_top() && method() != nullptr && method()->holder() == phase->C->env()->ValueObjectMethods_klass() && |
| 1189 | + (method()->name() == ciSymbols::isSubstitutable_name())) { |
| 1190 | + Node* left = in(TypeFunc::Parms); |
| 1191 | + Node* right = in(TypeFunc::Parms + 1); |
| 1192 | + if (!left->is_top() && !right->is_top() && (left->is_InlineType() || right->is_InlineType())) { |
| 1193 | + if (!left->is_InlineType()) { |
| 1194 | + swap(left, right); |
| 1195 | + } |
| 1196 | + InlineTypeNode* vt = left->as_InlineType(); |
| 1197 | + |
| 1198 | + // Check if the field layout can be optimized |
| 1199 | + if (vt->can_emit_substitutability_check(right)) { |
| 1200 | + PhaseIterGVN* igvn = phase->is_IterGVN(); |
| 1201 | + |
| 1202 | + Node* ctrl = control(); |
| 1203 | + RegionNode* region = new RegionNode(1); |
| 1204 | + Node* phi = new PhiNode(region, TypeInt::POS); |
| 1205 | + |
| 1206 | + Node* base = right; |
| 1207 | + Node* ptr = right; |
| 1208 | + if (!base->is_InlineType()) { |
| 1209 | + // Parse time checks guarantee that both operands are non-null and have the same type |
| 1210 | + base = igvn->register_new_node_with_optimizer(new CheckCastPPNode(ctrl, base, vt->bottom_type())); |
| 1211 | + ptr = base; |
| 1212 | + } |
| 1213 | + // Emit IR for field-wise comparison |
| 1214 | + vt->check_substitutability(igvn, region, phi, &ctrl, in(MemNode::Memory), base, ptr); |
| 1215 | + |
| 1216 | + // Equals |
| 1217 | + region->add_req(ctrl); |
| 1218 | + phi->add_req(igvn->intcon(1)); |
| 1219 | + |
| 1220 | + ctrl = igvn->register_new_node_with_optimizer(region); |
| 1221 | + Node* res = igvn->register_new_node_with_optimizer(phi); |
| 1222 | + |
| 1223 | + // Kill exception projections and return a tuple that will replace the call |
| 1224 | + CallProjections* projs = extract_projections(false /*separate_io_proj*/); |
| 1225 | + if (projs->fallthrough_catchproj != nullptr) { |
| 1226 | + igvn->replace_node(projs->fallthrough_catchproj, ctrl); |
| 1227 | + } |
| 1228 | + if (projs->catchall_memproj != nullptr) { |
| 1229 | + igvn->replace_node(projs->catchall_memproj, igvn->C->top()); |
| 1230 | + } |
| 1231 | + if (projs->catchall_ioproj != nullptr) { |
| 1232 | + igvn->replace_node(projs->catchall_ioproj, igvn->C->top()); |
| 1233 | + } |
| 1234 | + if (projs->catchall_catchproj != nullptr) { |
| 1235 | + igvn->replace_node(projs->catchall_catchproj, igvn->C->top()); |
| 1236 | + } |
| 1237 | + return TupleNode::make(tf()->range_cc(), ctrl, i_o(), memory(), frameptr(), returnadr(), res); |
| 1238 | + } |
1196 | 1239 | } |
1197 | 1240 | } |
1198 | 1241 |
|
@@ -1382,52 +1425,6 @@ bool CallStaticJavaNode::remove_unknown_flat_array_load(PhaseIterGVN* igvn, Node |
1382 | 1425 | return true; |
1383 | 1426 | } |
1384 | 1427 |
|
1385 | | -// Try to replace a runtime call to the substitutability test by either a simple pointer comparison |
1386 | | -// if either operand is not a value object, or comparing their fields if either operand is an |
1387 | | -// object of a known value type |
1388 | | -Node* CallStaticJavaNode::replace_is_substitutable(PhaseIterGVN* igvn) { |
1389 | | - // Delay IGVN during macro expansion |
1390 | | - assert(!igvn->delay_transform(), "must not delay during Ideal"); |
1391 | | - igvn->set_delay_transform(true); |
1392 | | - |
1393 | | - // Prepare to inline, clone the jvms |
1394 | | - JVMState* jvms = this->jvms()->clone_shallow(igvn->C); |
1395 | | - assert(jvms->map()->next_exception() == nullptr, "this call does not throw"); |
1396 | | - SafePointNode* map = new SafePointNode(req(), jvms); |
1397 | | - igvn->register_new_node_with_optimizer(map); |
1398 | | - for (uint i = 0; i < req(); i++) { |
1399 | | - map->init_req(i, in(i)); |
1400 | | - } |
1401 | | - MergeMemNode* mem = MergeMemNode::make(map->memory()); |
1402 | | - igvn->register_new_node_with_optimizer(mem); |
1403 | | - map->set_memory(mem); |
1404 | | - jvms->set_map(map); |
1405 | | - GraphKit kit(jvms, igvn); |
1406 | | - |
1407 | | - Node* left = in(TypeFunc::Parms); |
1408 | | - Node* right = in(TypeFunc::Parms + 1); |
1409 | | - Node* replace = InlineTypeNode::emit_substitutability_check(&kit, left, right); |
1410 | | - igvn->set_delay_transform(false); |
1411 | | - if (replace == nullptr) { |
1412 | | - return nullptr; |
1413 | | - } |
1414 | | - |
1415 | | - // Kill exception projections and return a tuple that will replace the call |
1416 | | - CallProjections* projs = extract_projections(false /*separate_io_proj*/); |
1417 | | - if (projs->fallthrough_catchproj != nullptr) { |
1418 | | - igvn->replace_node(projs->fallthrough_catchproj, kit.control()); |
1419 | | - } |
1420 | | - if (projs->catchall_memproj != nullptr) { |
1421 | | - igvn->replace_node(projs->catchall_memproj, igvn->C->top()); |
1422 | | - } |
1423 | | - if (projs->catchall_ioproj != nullptr) { |
1424 | | - igvn->replace_node(projs->catchall_ioproj, igvn->C->top()); |
1425 | | - } |
1426 | | - if (projs->catchall_catchproj != nullptr) { |
1427 | | - igvn->replace_node(projs->catchall_catchproj, igvn->C->top()); |
1428 | | - } |
1429 | | - return TupleNode::make(tf()->range_cc(), igvn->C->top(), kit.i_o(), kit.reset_memory(), kit.frameptr(), kit.returnadr(), replace); |
1430 | | -} |
1431 | 1428 |
|
1432 | 1429 | #ifndef PRODUCT |
1433 | 1430 | void CallStaticJavaNode::dump_spec(outputStream *st) const { |
|
0 commit comments