Skip to content

Commit 0085e7d

Browse files
committed
Implement the builtin hash with the library
1 parent 53d2f48 commit 0085e7d

File tree

4 files changed

+22
-44
lines changed

4 files changed

+22
-44
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ static boolean isMappingType(PythonBuiltinClassType type,
461461
@ExportMessage
462462
static long hash(PythonBuiltinClassType type,
463463
@CachedContext(PythonLanguage.class) PythonContext context,
464-
@CachedLibrary(limit = "1") PythonObjectLibrary lib) throws UnsupportedMessageException {
464+
@CachedLibrary(limit = "1") PythonObjectLibrary lib) {
465465
return lib.hash(context.getCore().lookupType(type));
466466
}
467467

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

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,6 @@
139139
import com.oracle.graal.python.nodes.call.CallNode;
140140
import com.oracle.graal.python.nodes.call.GenericInvokeNode;
141141
import com.oracle.graal.python.nodes.call.PythonCallNode;
142-
import com.oracle.graal.python.nodes.call.special.CallUnaryMethodNode;
143142
import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode;
144143
import com.oracle.graal.python.nodes.call.special.LookupAndCallTernaryNode;
145144
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
@@ -490,39 +489,19 @@ public char charFromObject(Object arg) {
490489
}
491490
}
492491

493-
// hash([object])
492+
// hash(object)
494493
@Builtin(name = HASH, minNumOfPositionalArgs = 1)
495494
@GenerateNodeFactory
496495
public abstract static class HashNode extends PythonUnaryBuiltinNode {
497-
@Specialization // tfel: TODO: this shouldn't be needed!
498-
Object hash(PException exception) {
499-
return exception.hashCode();
500-
}
501-
502-
protected boolean isPException(Object object) {
503-
return object instanceof PException;
504-
}
505-
506-
@Specialization(guards = "!isPException(object)")
507-
Object hash(VirtualFrame frame, Object object,
508-
@Cached("create(__DIR__)") LookupInheritedAttributeNode lookupDirNode,
509-
@Cached("create(__HASH__)") LookupInheritedAttributeNode lookupHash,
510-
@CachedLibrary(limit = "1") PythonObjectLibrary dataModelLibrary,
511-
@Cached CallUnaryMethodNode callUnary,
512-
@Cached("createIfTrueNode()") CastToBooleanNode trueNode,
513-
@Cached IsInstanceNode isInstanceNode) {
514-
if (trueNode.executeBoolean(frame, lookupDirNode.execute(object))) {
515-
Object hashAttr = lookupHash.execute(object);
516-
if (!dataModelLibrary.isCallable(hashAttr)) {
517-
throw raise(PythonErrorType.TypeError, "unhashable type: '%p'", object);
518-
}
519-
Object hashValue = callUnary.executeObject(frame, hashAttr, object);
520-
if (isInstanceNode.executeWith(frame, hashValue, getBuiltinPythonClass(PythonBuiltinClassType.PInt))) {
521-
return hashValue;
522-
}
523-
throw raise(PythonErrorType.TypeError, "__hash__ method should return an integer");
496+
@Specialization(limit = "getCallSiteInlineCacheMaxDepth()")
497+
long hash(VirtualFrame frame, Object object,
498+
@Cached("createBinaryProfile()") ConditionProfile profile,
499+
@CachedLibrary("object") PythonObjectLibrary lib) {
500+
if (profile.profile(frame != null)) {
501+
return lib.hashWithState(object, PArguments.getThreadState(frame));
502+
} else {
503+
return lib.hash(object);
524504
}
525-
return object.hashCode();
526505
}
527506
}
528507

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/PythonAbstractObject.java

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@
108108
import com.oracle.graal.python.nodes.object.GetLazyClassNode;
109109
import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
110110
import com.oracle.graal.python.nodes.util.CastToJavaIntNode;
111+
import com.oracle.graal.python.nodes.util.CastToJavaLongNode;
111112
import com.oracle.graal.python.runtime.exception.PException;
112113
import com.oracle.truffle.api.CompilerDirectives;
113114
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
@@ -675,24 +676,22 @@ public long hashWithState(ThreadState state,
675676
@Exclusive @Cached LookupInheritedAttributeNode.Dynamic lookupHashAttributeNode,
676677
@Exclusive @Cached CallNode callNode,
677678
@Exclusive @Cached PRaiseNode raise,
678-
@CachedLibrary(limit = "1") PythonObjectLibrary lib,
679-
@CachedLibrary(limit = "1") InteropLibrary interopLib) {
679+
@Cached CastToJavaLongNode castToLong,
680+
@CachedLibrary(limit = "1") PythonObjectLibrary lib) {
680681
Object hashAttr = getHashAttr(lookupHashAttributeNode, raise, lib);
681682
Object result;
682683
if (gotState.profile(state == null)) {
683684
result = callNode.execute(hashAttr, this);
684685
} else {
685686
result = callNode.execute(PArguments.frameForCall(state), hashAttr, this);
686687
}
687-
if (interopLib.fitsInLong(hashAttr)) {
688-
try {
689-
return interopLib.asLong(result);
690-
} catch (UnsupportedMessageException e) {
691-
CompilerDirectives.transferToInterpreter();
692-
throw new IllegalStateException(e);
693-
}
688+
// see PyObject_GetHash and slot_tp_hash in CPython. The result of the
689+
// hash call is always a plain long, forcibly and lossy read from memory.
690+
try {
691+
return castToLong.execute(result);
692+
} catch (CastToJavaLongNode.CannotCastException e) {
693+
throw raise.raise(PythonBuiltinClassType.TypeError, "__hash__ method should return an integer");
694694
}
695-
throw raise.raise(PythonBuiltinClassType.TypeError, "__hash__ method should return an integer");
696695
}
697696

698697
private Object getHashAttr(LookupInheritedAttributeNode.Dynamic lookupHashAttributeNode, PRaiseNode raise, PythonObjectLibrary lib) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/PythonObjectLibrary.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,9 +198,9 @@ public boolean isHashable(Object receiver) {
198198
* call. It ensures that we can use fastcalls and pass the thread state in
199199
* the frame arguments.
200200
*/
201-
public long hashWithState(Object receiver, ThreadState threadState) throws UnsupportedMessageException {
201+
public long hashWithState(Object receiver, ThreadState threadState) {
202202
if (threadState == null) {
203-
throw UnsupportedMessageException.create();
203+
throw new AbstractMethodError();
204204
}
205205
return hash(receiver);
206206
}
@@ -210,7 +210,7 @@ public long hashWithState(Object receiver, ThreadState threadState) throws Unsup
210210
* Python {@link Frame} is available to the caller, {@link #hashWithState}
211211
* should be preferred.
212212
*/
213-
public long hash(Object receiver) throws UnsupportedMessageException {
213+
public long hash(Object receiver) {
214214
return hashWithState(receiver, null);
215215
}
216216

0 commit comments

Comments
 (0)