Skip to content

Commit b2b7484

Browse files
committed
fix HPy_Contains
1 parent 9734ed3 commit b2b7484

File tree

8 files changed

+188
-41
lines changed

8 files changed

+188
-41
lines changed

graalpython/com.oracle.graal.python.cext/hpy/hpy.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1578,6 +1578,7 @@ HPyContext *graal_hpy_context_to_native(HPyContext *managed_context, HPyContext
15781578
HPY_CTX_UPCALL(ctx_GetItem);
15791579
HPY_CTX_UPCALL(ctx_GetItem_i);
15801580
HPY_CTX_UPCALL(ctx_GetItem_s);
1581+
HPY_CTX_UPCALL(ctx_Contains);
15811582
HPY_CTX_UPCALL(ctx_SetItem);
15821583
HPY_CTX_UPCALL(ctx_SetItem_i);
15831584
HPY_CTX_UPCALL(ctx_SetItem_s);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/hpy/GraalHPyContextFunctions.java

Lines changed: 7 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@
143143
import com.oracle.graal.python.lib.PyObjectCallMethodObjArgs;
144144
import com.oracle.graal.python.lib.PyObjectIsTrueNode;
145145
import com.oracle.graal.python.lib.PyObjectRichCompareBool;
146+
import com.oracle.graal.python.lib.PySequenceContainsNode;
146147
import com.oracle.graal.python.lib.PyUnicodeReadCharNode;
147148
import com.oracle.graal.python.nodes.BuiltinNames;
148149
import com.oracle.graal.python.nodes.ErrorMessages;
@@ -3220,43 +3221,21 @@ public static final class GraalHPyContains extends GraalHPyContextFunction {
32203221
Object execute(Object[] arguments,
32213222
@Cached HPyAsContextNode asContextNode,
32223223
@Cached HPyAsPythonObjectNode asPythonObjectNode,
3223-
@Cached LookupInheritedAttributeNode.Dynamic lookupAttrNode,
3224-
@Cached CallBinaryMethodNode callAttrNode,
3225-
@Cached IsBuiltinClassProfile isBuiltinClassProfile,
3224+
@Cached PySequenceContainsNode containsNode,
32263225
@Cached HPyTransformExceptionToNativeNode transformExceptionToNativeNode,
3227-
@Cached ConditionProfile profile,
3228-
@Cached PyObjectRichCompareBool.EqNode eqNode,
32293226
@Cached GilNode gil) throws ArityException {
32303227
checkArity(arguments, 3);
32313228
boolean mustRelease = gil.acquire();
32323229
try {
32333230
GraalHPyContext context = asContextNode.execute(arguments[0]);
32343231
Object container = asPythonObjectNode.execute(context, arguments[1]);
32353232
Object key = asPythonObjectNode.execute(context, arguments[2]);
3236-
Object containsAttr = lookupAttrNode.execute(container, SpecialMethodNames.__CONTAINS__);
3237-
if (profile.profile(containsAttr != PNone.NO_VALUE)) {
3238-
try {
3239-
callAttrNode.executeObject(null, containsAttr, container, key);
3240-
} catch (PException e) {
3241-
transformExceptionToNativeNode.execute(context, e);
3242-
return -1;
3243-
}
3244-
} else {
3245-
Object iterAttr = lookupAttrNode.execute(container, SpecialMethodNames.__ITER__);
3246-
if (profile.profile(iterAttr != PNone.NO_VALUE)) {
3247-
while (true) {
3248-
try {
3249-
if (eqNode.execute(null, GetNextNode.getUncached().execute(iterAttr), key)) {
3250-
return true;
3251-
}
3252-
} catch (PException e) {
3253-
e.expectStopIteration(isBuiltinClassProfile);
3254-
return false;
3255-
}
3256-
}
3257-
}
3233+
try {
3234+
return containsNode.execute(container, key) ? 1 : 0;
3235+
} catch (PException e) {
3236+
transformExceptionToNativeNode.execute(context, e);
3237+
return -1;
32583238
}
3259-
return 0;
32603239
} finally {
32613240
gil.release(mustRelease);
32623241
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/hpy/GraalHPyDef.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,9 @@ public LLVMType getLLVMFunctionType() {
317317
enum HPySlot {
318318
HPY_BF_GETBUFFER(1, HPySlotWrapper.GETBUFFER, TypeBuiltins.TYPE_GETBUFFER),
319319
HPY_BF_RELEASEBUFFER(2, HPySlotWrapper.RELEASEBUFFER, TypeBuiltins.TYPE_RELEASEBUFFER),
320+
HPY_MP_ASS_SUBSCRRIPT(3, HPySlotWrapper.OBJOBJARGPROC, __SETITEM__, __DELITEM__),
321+
HPY_MP_LENGTH(4, HPySlotWrapper.LENFUNC, __LEN__),
322+
HPY_MP_SUBSCRIPT(5, HPySlotWrapper.BINARYFUNC, __GETITEM__),
320323
HPY_NB_ABSOLUTE(6, HPySlotWrapper.UNARYFUNC, __ABS__),
321324
HPY_NB_ADD(7, HPySlotWrapper.BINARYFUNC_L, __ADD__, HPySlotWrapper.BINARYFUNC_R, __RADD__),
322325
HPY_NB_AND(8, HPySlotWrapper.BINARYFUNC_L, __AND__, HPySlotWrapper.BINARYFUNC_R, __RAND__),

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/hpy/HPyExternalFunctionNodes.java

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -888,34 +888,52 @@ public Signature getSignature() {
888888
}
889889

890890
static final class HPyMethObjObjArgProcRoot extends HPyMethodDescriptorRootNode {
891-
private static final Signature SIGNATURE = new Signature(3, false, -1, false, new String[]{"$self", "x", "y"}, KEYWORDS_HIDDEN_CALLABLE, true);
891+
private static final Signature SIGNATURE = new Signature(-1, false, 1, false, new String[]{"$self", "x"}, KEYWORDS_HIDDEN_CALLABLE, true);
892892

893893
@Child private ReadIndexedArgumentNode readArg1Node;
894-
@Child private ReadIndexedArgumentNode readArg2Node;
894+
@Child private ReadVarArgsNode readVarargsNode;
895+
@Child private PRaiseNode raiseNode;
895896

896897
public HPyMethObjObjArgProcRoot(PythonLanguage language, String name) {
897898
super(language, name, HPyCheckPrimitiveResultNodeGen.create(), HPyAllAsHandleNodeGen.create());
898899
}
899900

900901
@Override
901902
protected Object[] prepareCArguments(VirtualFrame frame, @SuppressWarnings("unused") GraalHPyContext hpyContext) {
902-
return new Object[]{getSelf(frame), getArg1(frame), getArg2(frame)};
903+
Object[] varargs = getVarargs(frame);
904+
if (varargs.length == 0) {
905+
return new Object[]{getSelf(frame), getArg1(frame), PNone.NO_VALUE};
906+
} else if (varargs.length == 1) {
907+
return new Object[]{getSelf(frame), getArg1(frame), varargs[0]};
908+
} else {
909+
throw getRaiseNode().raise(PythonBuiltinClassType.TypeError,
910+
ErrorMessages.TAKES_FROM_D_TO_D_POS_ARG_S_BUT_D_S_GIVEN_S,
911+
getName(), 2, 3, "s", 1 + varargs.length, "were", "");
912+
}
903913
}
904914

905-
private Object getArg1(VirtualFrame frame) {
906-
if (readArg1Node == null) {
915+
private PRaiseNode getRaiseNode() {
916+
if (raiseNode == null) {
907917
CompilerDirectives.transferToInterpreterAndInvalidate();
908-
readArg1Node = insert(ReadIndexedArgumentNode.create(1));
918+
raiseNode = insert(PRaiseNode.create());
909919
}
910-
return readArg1Node.execute(frame);
920+
return raiseNode;
911921
}
912922

913-
private Object getArg2(VirtualFrame frame) {
914-
if (readArg2Node == null) {
923+
private Object[] getVarargs(VirtualFrame frame) {
924+
if (readVarargsNode == null) {
915925
CompilerDirectives.transferToInterpreterAndInvalidate();
916-
readArg2Node = insert(ReadIndexedArgumentNode.create(2));
926+
readVarargsNode = insert(ReadVarArgsNode.create(true));
917927
}
918-
return readArg2Node.execute(frame);
928+
return readVarargsNode.executeObjectArray(frame);
929+
}
930+
931+
private Object getArg1(VirtualFrame frame) {
932+
if (readArg1Node == null) {
933+
CompilerDirectives.transferToInterpreterAndInvalidate();
934+
readArg1Node = insert(ReadIndexedArgumentNode.create(1));
935+
}
936+
return readArg1Node.execute(frame);
919937
}
920938

921939
@Override

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/LazyString.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public static CharSequence createChecked(CharSequence left, CharSequence right,
7373

7474
private static boolean assertChecked(PythonContext context, CharSequence left, CharSequence right, int length) {
7575
assert context.getOption(PythonOptions.LazyStrings);
76-
assert (PGuards.isString(left) || left instanceof LazyString) && (PGuards.isString(right) || right instanceof LazyString);
76+
assert (PGuards.isString(left) || left instanceof LazyString || left instanceof NativeCharSequence) && (PGuards.isString(right) || right instanceof LazyString || right instanceof NativeCharSequence);
7777
assert length == left.length() + right.length();
7878
assert left.length() > 0 && right.length() > 0;
7979
assert length >= context.getOption(PythonOptions.MinLazyStringLength);
@@ -191,6 +191,9 @@ private static void flatten(CharSequence src, int srcBegin, int srcEnd, char[] d
191191
} else if (str instanceof String) {
192192
((String) str).getChars(from, to, dst, dstFrom);
193193
return;
194+
} else if (str instanceof NativeCharSequence) {
195+
((NativeCharSequence) str).materialize().getChars(from, to, dst, dstFrom);
196+
return;
194197
}
195198
}
196199
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/NativeCharSequence.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ String getMaterialized() {
116116
return materialized;
117117
}
118118

119-
private String materialize() {
119+
String materialize() {
120120
if (!isMaterialized()) {
121121
LOGGER.warning("uncached materialization of NativeCharSequence");
122122
materialized = StringMaterializeNode.materializeNativeCharSequence(this, PCallCapiFunction.getUncached(), UnicodeFromWcharNodeGen.getUncached());
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/*
2+
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.graal.python.lib;
42+
43+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
44+
import com.oracle.graal.python.builtins.objects.PNone;
45+
import com.oracle.graal.python.builtins.objects.PNotImplemented;
46+
import com.oracle.graal.python.builtins.objects.type.SpecialMethodSlot;
47+
import com.oracle.graal.python.nodes.ErrorMessages;
48+
import com.oracle.graal.python.nodes.PNodeWithContext;
49+
import com.oracle.graal.python.nodes.PRaiseNode;
50+
import com.oracle.graal.python.nodes.call.special.CallBinaryMethodNode;
51+
import com.oracle.graal.python.nodes.call.special.CallUnaryMethodNode;
52+
import com.oracle.graal.python.nodes.call.special.LookupSpecialMethodSlotNode;
53+
import com.oracle.graal.python.nodes.object.GetClassNode;
54+
import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
55+
import com.oracle.graal.python.runtime.exception.PException;
56+
import com.oracle.truffle.api.CompilerDirectives;
57+
import com.oracle.truffle.api.dsl.Cached;
58+
import com.oracle.truffle.api.dsl.GenerateUncached;
59+
import com.oracle.truffle.api.dsl.ImportStatic;
60+
import com.oracle.truffle.api.dsl.Specialization;
61+
import com.oracle.truffle.api.frame.Frame;
62+
import com.oracle.truffle.api.nodes.LoopNode;
63+
64+
/**
65+
* Equivalent of CPython's {@code PySequence_Contains}.
66+
*/
67+
@GenerateUncached
68+
@ImportStatic(SpecialMethodSlot.class)
69+
public abstract class PySequenceContainsNode extends PNodeWithContext {
70+
public abstract boolean execute(Frame frame, Object container, Object key);
71+
72+
public final boolean execute(Object container, Object key) {
73+
return execute(null, container, key);
74+
}
75+
76+
@Specialization
77+
boolean contains(Frame frame, Object container, Object key,
78+
@Cached GetClassNode getReceiverClass,
79+
@Cached(parameters = "Contains") LookupSpecialMethodSlotNode lookupContains,
80+
@Cached IsBuiltinClassProfile noContainsProfile,
81+
@Cached CallBinaryMethodNode callContains,
82+
@Cached PyObjectGetIter getIter,
83+
@Cached IsBuiltinClassProfile noIterProfile,
84+
@Cached PRaiseNode raiseNode,
85+
@Cached GetClassNode getIterClass,
86+
@Cached(parameters = "Next") LookupSpecialMethodSlotNode lookupIternext,
87+
@Cached IsBuiltinClassProfile noNextProfile,
88+
@Cached CallUnaryMethodNode callNext,
89+
@Cached PyObjectRichCompareBool.EqNode eqNode,
90+
@Cached IsBuiltinClassProfile stopIterationProfile,
91+
@Cached PyObjectIsTrueNode isTrue) {
92+
Object type = getReceiverClass.execute(container);
93+
Object contains = PNone.NO_VALUE;
94+
try {
95+
contains = lookupContains.execute(frame, type, container);
96+
} catch (PException e) {
97+
e.expectAttributeError(noContainsProfile);
98+
}
99+
Object result = PNotImplemented.NOT_IMPLEMENTED;
100+
if (!(contains instanceof PNone)) {
101+
result = callContains.executeObject(frame, contains, container, key);
102+
}
103+
if (result == PNotImplemented.NOT_IMPLEMENTED) {
104+
Object iterator;
105+
try {
106+
iterator = getIter.execute(frame, container);
107+
} catch (PException e) {
108+
e.expectTypeError(noIterProfile);
109+
throw raiseNode.raise(PythonBuiltinClassType.TypeError, ErrorMessages.IS_NOT_A_CONTAINER, container);
110+
}
111+
Object next = PNone.NO_VALUE;
112+
try {
113+
next = lookupIternext.execute(frame, getIterClass.execute(iterator), iterator);
114+
} catch (PException e) {
115+
e.expect(PythonBuiltinClassType.AttributeError, noNextProfile);
116+
}
117+
if (next instanceof PNone) {
118+
throw raiseNode.raise(PythonBuiltinClassType.TypeError, ErrorMessages.OBJ_NOT_ITERABLE, iterator);
119+
}
120+
int i = 0;
121+
while (true) {
122+
if (CompilerDirectives.hasNextTier()) {
123+
i++;
124+
}
125+
try {
126+
if (eqNode.execute(frame, callNext.executeObject(frame, next, iterator), key)) {
127+
return true;
128+
}
129+
} catch (PException e) {
130+
e.expectStopIteration(stopIterationProfile);
131+
return false;
132+
} finally {
133+
if (CompilerDirectives.hasNextTier()) {
134+
LoopNode.reportLoopCount(this, i);
135+
}
136+
}
137+
}
138+
} else {
139+
return isTrue.execute(frame, result);
140+
}
141+
}
142+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ public abstract class ErrorMessages {
375375
public static final String ISLICE_WRONG_ARGS = "islice(seq, stop) or islice(seq, start, stop[, step])";
376376
public static final String IS_EMPTY = "%s is empty";
377377
public static final String IS_NOT_A = "%s is not a %s";
378+
public static final String IS_NOT_A_CONTAINER = "%p is not a container";
378379
public static final String IS_NOT_A_DICTIONARY = "%s is not a dictionary";
379380
public static final String IS_NOT_IN_RANGE = "%s is not in range";
380381
public static final String IS_NOT_A_UNICODE_OBJECT = "%s is not a unicode object";

0 commit comments

Comments
 (0)