992 uniqueVirtualObject = false; 993 } 994 ensureVirtual &= objectState.getEnsureVirtualized(); 995 virtualInputs++; 996 } 997 } 998 } 999 if (virtualInputs == states.length) { 1000 if (uniqueVirtualObject) { 1001 // all inputs refer to the same object: just make the phi node an alias 1002 addVirtualAlias(virtualObjs[0], phi); 1003 mergeEffects.deleteNode(phi); 1004 return false; 1005 } else { 1006 // all inputs are virtual: check if they're compatible and without identity 1007 boolean compatible = true; 1008 VirtualObjectNode firstVirtual = virtualObjs[0]; 1009 for (int i = 0; i < states.length; i++) { 1010 VirtualObjectNode virtual = virtualObjs[i]; 1011 1012 boolean identitySurvives = virtual.hasIdentity() && 1013 // check whether we trivially see that this is the only 1014 // reference to this allocation 1015 !isSingleUsageAllocation(getPhiValueAt(phi, i)); 1016 1017 if (identitySurvives || !firstVirtual.type().equals(virtual.type()) || firstVirtual.entryCount() != virtual.entryCount()) { 1018 compatible = false; 1019 break; 1020 } 1021 if (!states[0].getObjectState(firstVirtual).locksEqual(states[i].getObjectState(virtual))) { 1022 compatible = false; 1023 break; 1024 } 1025 } 1026 if (compatible) { 1027 VirtualObjectNode virtual = getValueObjectVirtual(phi, virtualObjs[0]); 1028 mergeEffects.addFloatingNode(virtual, "valueObjectNode"); 1029 mergeEffects.deleteNode(phi); 1030 if (virtual.getObjectId() == -1) { 1031 int id = virtualObjects.size(); 1032 virtualObjects.add(virtual); 1033 virtual.setObjectId(id); 1034 } 1035 1036 int[] virtualObjectIds = new int[states.length]; 1037 for (int i = 0; i < states.length; i++) { 1038 virtualObjectIds[i] = virtualObjs[i].getObjectId(); 1039 } 1040 boolean materialized = mergeObjectStates(virtual.getObjectId(), virtualObjectIds, states); 1041 addVirtualAlias(virtual, virtual); 1042 addVirtualAlias(virtual, phi); 1043 return materialized; 1044 } 1045 } 1046 } 1052 VirtualObjectNode virtual = virtualObjs[i]; 1053 if (virtual != null) { 1054 Block predecessor = getPredecessor(i); 1055 if (!ensureVirtual && states[i].getObjectState(virtual).isVirtual()) { 1056 // we can materialize if not all inputs are "ensureVirtualized" 1057 states[i].getObjectState(virtual).setEnsureVirtualized(false); 1058 } 1059 materialized |= ensureMaterialized(states[i], virtual.getObjectId(), predecessor.getEndNode(), blockEffects.get(predecessor), COUNTER_MATERIALIZATIONS_PHI); 1060 } 1061 } 1062 } 1063 for (int i = 0; i < states.length; i++) { 1064 VirtualObjectNode virtual = virtualObjs[i]; 1065 if (virtual != null) { 1066 setPhiInput(phi, i, getAliasAndResolve(states[i], virtual)); 1067 } 1068 } 1069 return materialized; 1070 } 1071 1072 private boolean isSingleUsageAllocation(ValueNode value) { 1073 /* 1074 * If the phi input is an allocation, we know that it is a "fresh" value, i.e., that 1075 * this is a value that will only appear through this source, and cannot appear anywhere 1076 * else. If the phi is also the only usage of this input, we know that no other place 1077 * can check object identity against it, so it is safe to lose the object identity here. 1078 */ 1079 return value instanceof AllocatedObjectNode && value.hasExactlyOneUsage(); 1080 } 1081 } 1082 1083 public ObjectState getObjectState(PartialEscapeBlockState<?> state, ValueNode value) { 1084 if (value == null) { 1085 return null; 1086 } 1087 if (value.isAlive() && !aliases.isNew(value)) { 1088 ValueNode object = aliases.get(value); 1089 return object instanceof VirtualObjectNode ? state.getObjectStateOptional((VirtualObjectNode) object) : null; 1090 } else { 1091 if (value instanceof VirtualObjectNode) { 1092 return state.getObjectStateOptional((VirtualObjectNode) value); 1093 } 1094 return null; 1095 } 1096 } 1097 1098 public ValueNode getAlias(ValueNode value) { 1099 if (value != null && !(value instanceof VirtualObjectNode)) { | 992 uniqueVirtualObject = false; 993 } 994 ensureVirtual &= objectState.getEnsureVirtualized(); 995 virtualInputs++; 996 } 997 } 998 } 999 if (virtualInputs == states.length) { 1000 if (uniqueVirtualObject) { 1001 // all inputs refer to the same object: just make the phi node an alias 1002 addVirtualAlias(virtualObjs[0], phi); 1003 mergeEffects.deleteNode(phi); 1004 return false; 1005 } else { 1006 // all inputs are virtual: check if they're compatible and without identity 1007 boolean compatible = true; 1008 VirtualObjectNode firstVirtual = virtualObjs[0]; 1009 for (int i = 0; i < states.length; i++) { 1010 VirtualObjectNode virtual = virtualObjs[i]; 1011 1012 if (!firstVirtual.type().equals(virtual.type()) || firstVirtual.entryCount() != virtual.entryCount()) { 1013 compatible = false; 1014 break; 1015 } 1016 if (!states[0].getObjectState(firstVirtual).locksEqual(states[i].getObjectState(virtual))) { 1017 compatible = false; 1018 break; 1019 } 1020 } 1021 if (compatible) { 1022 for (int i = 0; i < states.length; i++) { 1023 VirtualObjectNode virtual = virtualObjs[i]; 1024 /* 1025 * check whether we trivially see that this is the only reference to 1026 * this allocation 1027 */ 1028 if (virtual.hasIdentity() && !isSingleUsageAllocation(getPhiValueAt(phi, i), virtualObjs, states[i])) { 1029 compatible = false; 1030 } 1031 } 1032 } 1033 if (compatible) { 1034 VirtualObjectNode virtual = getValueObjectVirtual(phi, virtualObjs[0]); 1035 mergeEffects.addFloatingNode(virtual, "valueObjectNode"); 1036 mergeEffects.deleteNode(phi); 1037 if (virtual.getObjectId() == -1) { 1038 int id = virtualObjects.size(); 1039 virtualObjects.add(virtual); 1040 virtual.setObjectId(id); 1041 } 1042 1043 int[] virtualObjectIds = new int[states.length]; 1044 for (int i = 0; i < states.length; i++) { 1045 virtualObjectIds[i] = virtualObjs[i].getObjectId(); 1046 } 1047 boolean materialized = mergeObjectStates(virtual.getObjectId(), virtualObjectIds, states); 1048 addVirtualAlias(virtual, virtual); 1049 addVirtualAlias(virtual, phi); 1050 return materialized; 1051 } 1052 } 1053 } 1059 VirtualObjectNode virtual = virtualObjs[i]; 1060 if (virtual != null) { 1061 Block predecessor = getPredecessor(i); 1062 if (!ensureVirtual && states[i].getObjectState(virtual).isVirtual()) { 1063 // we can materialize if not all inputs are "ensureVirtualized" 1064 states[i].getObjectState(virtual).setEnsureVirtualized(false); 1065 } 1066 materialized |= ensureMaterialized(states[i], virtual.getObjectId(), predecessor.getEndNode(), blockEffects.get(predecessor), COUNTER_MATERIALIZATIONS_PHI); 1067 } 1068 } 1069 } 1070 for (int i = 0; i < states.length; i++) { 1071 VirtualObjectNode virtual = virtualObjs[i]; 1072 if (virtual != null) { 1073 setPhiInput(phi, i, getAliasAndResolve(states[i], virtual)); 1074 } 1075 } 1076 return materialized; 1077 } 1078 1079 private boolean isSingleUsageAllocation(ValueNode value, VirtualObjectNode[] virtualObjs, PartialEscapeBlockState<?> state) { 1080 /* 1081 * If the phi input is an allocation, we know that it is a "fresh" value, i.e., that 1082 * this is a value that will only appear through this source, and cannot appear anywhere 1083 * else. If the phi is also the only usage of this input, we know that no other place 1084 * can check object identity against it, so it is safe to lose the object identity here. 1085 */ 1086 if (!(value instanceof AllocatedObjectNode && value.hasExactlyOneUsage())) { 1087 return false; 1088 } 1089 1090 /* 1091 * Check that the state only references the one virtual object from the Phi. 1092 */ 1093 VirtualObjectNode singleVirtual = null; 1094 for (int v = 0; v < virtualObjs.length; v++) { 1095 if (state.contains(virtualObjs[v])) { 1096 if (singleVirtual == null) { 1097 singleVirtual = virtualObjs[v]; 1098 } else if (singleVirtual != virtualObjs[v]) { 1099 /* 1100 * More than one virtual object is visible in the object state. 1101 */ 1102 return false; 1103 } 1104 } 1105 } 1106 return true; 1107 } 1108 } 1109 1110 public ObjectState getObjectState(PartialEscapeBlockState<?> state, ValueNode value) { 1111 if (value == null) { 1112 return null; 1113 } 1114 if (value.isAlive() && !aliases.isNew(value)) { 1115 ValueNode object = aliases.get(value); 1116 return object instanceof VirtualObjectNode ? state.getObjectStateOptional((VirtualObjectNode) object) : null; 1117 } else { 1118 if (value instanceof VirtualObjectNode) { 1119 return state.getObjectStateOptional((VirtualObjectNode) value); 1120 } 1121 return null; 1122 } 1123 } 1124 1125 public ValueNode getAlias(ValueNode value) { 1126 if (value != null && !(value instanceof VirtualObjectNode)) { |