Skip to content

Commit 46adeb8

Browse files
committed
make our IdNode more sane
1 parent 39145bc commit 46adeb8

File tree

1 file changed

+106
-112
lines changed

1 file changed

+106
-112
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java

Lines changed: 106 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,10 @@
9595
import com.oracle.graal.python.builtins.objects.common.SequenceNodes;
9696
import com.oracle.graal.python.builtins.objects.common.SequenceNodes.GetObjectArrayNode;
9797
import com.oracle.graal.python.builtins.objects.common.SequenceNodesFactory.GetObjectArrayNodeGen;
98+
import com.oracle.graal.python.builtins.objects.complex.PComplex;
9899
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes;
99100
import com.oracle.graal.python.builtins.objects.dict.PDict;
101+
import com.oracle.graal.python.builtins.objects.floats.PFloat;
100102
import com.oracle.graal.python.builtins.objects.frame.PFrame;
101103
import com.oracle.graal.python.builtins.objects.function.PArguments;
102104
import com.oracle.graal.python.builtins.objects.function.PKeyword;
@@ -108,6 +110,7 @@
108110
import com.oracle.graal.python.builtins.objects.str.PString;
109111
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
110112
import com.oracle.graal.python.builtins.objects.type.PythonAbstractClass;
113+
import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass;
111114
import com.oracle.graal.python.builtins.objects.type.TypeBuiltins;
112115
import com.oracle.graal.python.builtins.objects.type.TypeNodes;
113116
import com.oracle.graal.python.nodes.BuiltinNames;
@@ -172,9 +175,11 @@
172175
import com.oracle.truffle.api.TruffleLanguage;
173176
import com.oracle.truffle.api.debug.Debugger;
174177
import com.oracle.truffle.api.dsl.Cached;
178+
import com.oracle.truffle.api.dsl.CachedContext;
175179
import com.oracle.truffle.api.dsl.Cached.Shared;
176180
import com.oracle.truffle.api.dsl.Fallback;
177181
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
182+
import com.oracle.truffle.api.dsl.GenerateUncached;
178183
import com.oracle.truffle.api.dsl.ImportStatic;
179184
import com.oracle.truffle.api.dsl.ReportPolymorphism;
180185
import com.oracle.truffle.api.dsl.Specialization;
@@ -909,15 +914,16 @@ Object getAttrGeneric(VirtualFrame frame, Object primary, Object name, Object de
909914
// id(object)
910915
@Builtin(name = ID, minNumOfPositionalArgs = 1)
911916
@GenerateNodeFactory
912-
public abstract static class IdNode extends PythonBuiltinNode {
913-
/**
914-
* The reserved ids at the beginning.
915-
*
916-
* <pre>
917-
* None, NotImplemented, True, False
918-
* </pre>
919-
*/
920-
private static final long KNOWN_OBJECTS_COUNT = 4L;
917+
public abstract static class IdNode extends PythonUnaryBuiltinNode {
918+
@Specialization
919+
long doObject(Object value,
920+
@Cached IdExpressionNode idNode) {
921+
return idNode.executeLong(value);
922+
}
923+
}
924+
925+
@GenerateUncached
926+
public abstract static class IdExpressionNode extends Node {
921927
// borrowed logic from pypy
922928
// -1 - (-maxunicode-1): unichar
923929
// 0 - 255: char
@@ -929,97 +935,124 @@ public abstract static class IdNode extends PythonBuiltinNode {
929935
private static final long BASE_EMPTY_UNICODE = 257;
930936
private static final long BASE_EMPTY_TUPLE = 258;
931937
private static final long BASE_EMPTY_FROZENSET = 259;
932-
private static final long IDTAG_SPECIAL = 11;
933-
private static final int IDTAG_SHIFT = 4;
938+
private static final int IDTAG_INT = 1;
939+
private static final int IDTAG_FLOAT = 5;
940+
private static final int IDTAG_COMPLEX = 7;
941+
private static final int IDTAG_SPECIAL = 11;
942+
private static final int IDTAG_SHIFT = 4;
934943

935-
/**
936-
* The next available global id. We reserve space for all integers to be their own id +
937-
* offset.
938-
*/
944+
public abstract long executeLong(Object value);
939945

940-
@Child private ReadAttributeFromObjectNode readId = null;
941-
@Child private WriteAttributeToObjectNode writeId = null;
942-
@Child private SequenceNodes.LenNode lenNode = null;
943-
@Child private HashingCollectionNodes.LenNode setLenNode = null;
944-
945-
@SuppressWarnings("unused")
946946
@Specialization
947-
int doId(PNone none) {
948-
return 0;
947+
long doId(boolean value,
948+
@CachedContext(PythonLanguage.class) PythonContext ctx) {
949+
return value ? doGeneric(ctx.getCore().getTrue()) : doGeneric(ctx.getCore().getFalse());
949950
}
950951

951-
@SuppressWarnings("unused")
952952
@Specialization
953-
int doId(PNotImplemented none) {
954-
return 1;
953+
long doId(int integer) {
954+
return ((long) integer) << IDTAG_SHIFT | IDTAG_INT;
955955
}
956956

957957
@Specialization
958-
int doId(boolean value) {
959-
return value ? 2 : 3;
958+
long doId(PInt value,
959+
@Shared("isBuiltin") @Cached IsBuiltinClassProfile isBuiltin) {
960+
if (isBuiltin.profileIsAnyBuiltinObject(value)) {
961+
try {
962+
return doId(value.intValueExact());
963+
} catch (ArithmeticException e) {
964+
// fall through
965+
}
966+
}
967+
return doGeneric(value);
960968
}
961969

962970
@Specialization
963-
long doId(int integer) {
964-
return integer + KNOWN_OBJECTS_COUNT;
971+
long doString(String s) {
972+
if (s.length() == 0) {
973+
return (BASE_EMPTY_UNICODE << IDTAG_SHIFT) | IDTAG_SPECIAL;
974+
} else if (s.length() == 1) {
975+
return (~s.codePointAt(0) << IDTAG_SHIFT) | IDTAG_SPECIAL;
976+
} else {
977+
return doGeneric(s);
978+
}
965979
}
966980

967981
@Specialization
968-
Object doId(PInt value) {
969-
try {
970-
return value.intValueExact() + KNOWN_OBJECTS_COUNT;
971-
} catch (ArithmeticException e) {
972-
return getId(value);
982+
long doPString(PString s,
983+
@Shared("isBuiltin") @Cached IsBuiltinClassProfile isBuiltin,
984+
@Cached CastToJavaStringNode castStr) {
985+
if (isBuiltin.profileIsAnyBuiltinObject(s)) {
986+
String jS = castStr.execute(s);
987+
return doString(jS);
988+
} else {
989+
return doGeneric(s);
973990
}
974991
}
975992

976993
@Specialization
977-
int doId(double value) {
978-
return Double.hashCode(value);
979-
}
980-
981-
@Specialization(guards = "isEmpty(value)")
982-
Object doEmptyString(@SuppressWarnings("unused") String value) {
983-
return (BASE_EMPTY_UNICODE << IDTAG_SHIFT) | IDTAG_SPECIAL;
994+
long doTuple(@SuppressWarnings("unused") PTuple value,
995+
@Shared("isBuiltin") @Cached IsBuiltinClassProfile isBuiltin,
996+
@Shared("lenNode") @Cached SequenceNodes.LenNode lenNode) {
997+
if (isBuiltin.profileIsAnyBuiltinObject(value) && lenNode.execute(value) == 0) {
998+
return (BASE_EMPTY_TUPLE << IDTAG_SHIFT) | IDTAG_SPECIAL;
999+
} else {
1000+
return doGeneric(value);
1001+
}
9841002
}
9851003

986-
@Specialization(guards = "isEmpty(value)")
987-
Object doEmptyString(@SuppressWarnings("unused") PString value) {
988-
return (BASE_EMPTY_UNICODE << IDTAG_SHIFT) | IDTAG_SPECIAL;
1004+
@Specialization
1005+
long doBytes(PBytes value,
1006+
@Shared("isBuiltin") @Cached IsBuiltinClassProfile isBuiltin,
1007+
@Shared("lenNode") @Cached SequenceNodes.LenNode lenNode) {
1008+
if (isBuiltin.profileIsAnyBuiltinObject(value) && lenNode.execute(value) == 0) {
1009+
return (BASE_EMPTY_BYTES << IDTAG_SHIFT) | IDTAG_SPECIAL;
1010+
} else {
1011+
return doGeneric(value);
1012+
}
9891013
}
9901014

991-
@Specialization(guards = "isEmpty(value)")
992-
Object doEmptyTuple(@SuppressWarnings("unused") PTuple value) {
993-
return (BASE_EMPTY_TUPLE << IDTAG_SHIFT) | IDTAG_SPECIAL;
1015+
@Specialization
1016+
long doFrozenSet(PFrozenSet value,
1017+
@Shared("isBuiltin") @Cached IsBuiltinClassProfile isBuiltin,
1018+
@Cached HashingCollectionNodes.LenNode lenNode) {
1019+
if (isBuiltin.profileIsAnyBuiltinObject(value) && lenNode.execute(value) == 0) {
1020+
return (BASE_EMPTY_FROZENSET << IDTAG_SHIFT) | IDTAG_SPECIAL;
1021+
} else {
1022+
return doGeneric(value);
1023+
}
9941024
}
9951025

996-
@Specialization(guards = "isEmpty(value)")
997-
Object doEmptyBytes(@SuppressWarnings("unused") PBytes value) {
998-
return (BASE_EMPTY_BYTES << IDTAG_SHIFT) | IDTAG_SPECIAL;
1026+
@Specialization
1027+
long doDouble(double value) {
1028+
return Double.doubleToLongBits(value) << IDTAG_SHIFT | IDTAG_FLOAT;
9991029
}
10001030

1001-
@Specialization(guards = "isEmpty(value)")
1002-
Object doEmptyFrozenSet(@SuppressWarnings("unused") PFrozenSet value) {
1003-
return (BASE_EMPTY_FROZENSET << IDTAG_SHIFT) | IDTAG_SPECIAL;
1031+
@Specialization
1032+
long doPFloat(PFloat value,
1033+
@Shared("isBuiltin") @Cached IsBuiltinClassProfile isBuiltin) {
1034+
if (isBuiltin.profileIsAnyBuiltinObject(value)) {
1035+
return doDouble(value.getValue());
1036+
} else {
1037+
return doGeneric(value);
1038+
}
10041039
}
10051040

1006-
protected boolean isEmptyImmutableBuiltin(Object object) {
1007-
return (object instanceof PTuple && isEmpty((PTuple) object)) ||
1008-
(object instanceof String && PGuards.isEmpty((String) object)) ||
1009-
(object instanceof PString && isEmpty((PString) object)) ||
1010-
(object instanceof PBytes && isEmpty((PBytes) object)) ||
1011-
(object instanceof PFrozenSet && isEmpty((PFrozenSet) object));
1041+
@Specialization
1042+
long doComplex(PComplex value,
1043+
@Shared("isBuiltin") @Cached IsBuiltinClassProfile isBuiltin) {
1044+
if (isBuiltin.profileIsAnyBuiltinObject(value)) {
1045+
int imag = Double.hashCode(value.getImag());
1046+
int real = Double.hashCode(value.getReal());
1047+
return (((real << 32) | imag) << IDTAG_SHIFT) | IDTAG_COMPLEX;
1048+
} else {
1049+
return doGeneric(value);
1050+
}
10121051
}
10131052

1014-
/**
1015-
* TODO: {@link #doId(String)} and {@link #doId(double)} are not quite right, because the
1016-
* hashCode will certainly collide with integer hashes. It should be good for comparisons
1017-
* between String and String id, though, it'll just look as if we interned all strings from
1018-
* the Python code's perspective.
1019-
*/
1020-
@Specialization(guards = "!isEmpty(value)")
1021-
int doId(String value) {
1022-
return value.hashCode();
1053+
@Specialization
1054+
long doPythonBuiltinClass(PythonBuiltinClass value) {
1055+
return doGeneric(value.getType());
10231056
}
10241057

10251058
/**
@@ -1031,55 +1064,16 @@ int doId(String value) {
10311064
long doId(PCode obj) {
10321065
RootCallTarget ct = obj.getRootCallTarget();
10331066
if (ct != null) {
1034-
return ct.hashCode();
1067+
return doGeneric(ct);
10351068
} else {
1036-
return obj.hashCode();
1069+
return doGeneric(obj);
10371070
}
10381071
}
10391072

1040-
@Specialization(guards = {"!isPCode(obj)", "!isPInt(obj)", "!isPString(obj)", "!isPFloat(obj)", "!isEmptyImmutableBuiltin(obj)"})
1041-
long doId(PythonObject obj) {
1042-
return getId(obj);
1043-
}
1044-
10451073
@Fallback
10461074
@TruffleBoundary(allowInlining = true)
1047-
Object doId(Object obj) {
1048-
return obj.hashCode();
1049-
}
1050-
1051-
protected boolean isEmpty(PSequence s) {
1052-
if (lenNode == null) {
1053-
CompilerDirectives.transferToInterpreterAndInvalidate();
1054-
lenNode = insert(SequenceNodes.LenNode.create());
1055-
}
1056-
return lenNode.execute(s) == 0;
1057-
}
1058-
1059-
protected boolean isEmpty(PHashingCollection s) {
1060-
if (setLenNode == null) {
1061-
CompilerDirectives.transferToInterpreterAndInvalidate();
1062-
setLenNode = insert(HashingCollectionNodes.LenNode.create());
1063-
}
1064-
return setLenNode.execute(s) == 0;
1065-
}
1066-
1067-
private long getId(PythonObject obj) {
1068-
if (readId == null) {
1069-
CompilerDirectives.transferToInterpreterAndInvalidate();
1070-
readId = insert(ReadAttributeFromObjectNode.create());
1071-
}
1072-
Object id = readId.execute(obj, ID_KEY);
1073-
if (id == NO_VALUE) {
1074-
if (writeId == null) {
1075-
CompilerDirectives.transferToInterpreterAndInvalidate();
1076-
writeId = insert(WriteAttributeToObjectNode.create());
1077-
}
1078-
id = getContext().getNextGlobalId();
1079-
writeId.execute(obj, ID_KEY, id);
1080-
}
1081-
assert id instanceof Long : "invalid object ID stored";
1082-
return (long) id;
1075+
long doGeneric(Object obj) {
1076+
return System.identityHashCode(obj);
10831077
}
10841078
}
10851079

0 commit comments

Comments
 (0)