Skip to content

Commit 35c030c

Browse files
committed
Properly implement 'HAS_SIZE' and 'GET_SIZE' messages.
1 parent 34f7a26 commit 35c030c

File tree

3 files changed

+82
-20
lines changed

3 files changed

+82
-20
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_interop.py

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,11 @@
4040
if sys.implementation.name == "graalpython":
4141
import polyglot
4242

43-
4443
def test_import():
4544
imported_cext = polyglot.import_value("python_cext")
4645
import python_cext
4746
assert imported_cext is python_cext
4847

49-
5048
class CustomObject():
5149
field = 42
5250

@@ -56,7 +54,6 @@ def __getitem__(self, item):
5654
def __len__(self):
5755
return 21
5856

59-
6057
class CustomMutable(CustomObject):
6158
_items = {}
6259

@@ -78,15 +75,13 @@ def __setitem__(self, key, item):
7875
def __delitem__(self, key):
7976
del self._items[key]
8077

81-
8278
def test_read():
8379
o = CustomObject()
8480
assert polyglot.__read__(o, "field") == o.field
8581
assert polyglot.__read__(o, 10) == o[10]
8682
assert polyglot.__read__(o, "@field") == o.field
8783
assert polyglot.__read__(o, "[field") == o["field"]
8884

89-
9085
def test_write():
9186
o = CustomMutable()
9287
o2 = CustomObject()
@@ -120,7 +115,6 @@ def test_write():
120115
polyglot.__write__(o2, non_string, 12)
121116
assert getattr(o2, non_string) == 12
122117

123-
124118
def test_remove():
125119
o = CustomMutable()
126120
o.direct_field = 111
@@ -141,26 +135,21 @@ def test_remove():
141135
polyglot.__remove__(o, "grrrr")
142136
assert "grrrr" not in list(o.keys())
143137

144-
145138
def test_execute():
146139
assert polyglot.__execute__(abs, -10) == 10
147140
o = CustomMutable()
148141
assert polyglot.__execute__(o.__getattribute__, "field") == o.field
149142

150-
151143
def test_invoke():
152144
o = CustomMutable()
153145
assert polyglot.__invoke__(o, "__getattribute__", "field") == o.field
154146

155-
156147
def test_new():
157148
assert isinstance(polyglot.__new__(CustomMutable), CustomMutable)
158149

159-
160150
def test_is_null():
161151
assert polyglot.__is_null__(None)
162152

163-
164153
def test_has_size():
165154
import array
166155

@@ -171,15 +160,16 @@ def test_has_size():
171160
assert polyglot.__has_size__(b"")
172161
assert polyglot.__has_size__("")
173162
assert polyglot.__has_size__(range(10))
163+
assert polyglot.__has_size__(CustomObject())
174164

175165
assert not polyglot.__has_size__({})
176166
assert not polyglot.__has_size__(object())
177-
assert not polyglot.__has_size__(CustomObject())
178-
179167

180168
def test_get_size():
181169
called = False
170+
182171
class LenObject():
172+
183173
def __getitem__(self, k):
184174
if k == 0:
185175
return 1
@@ -194,23 +184,20 @@ def __len__(self):
194184
assert polyglot.__get_size__(LenObject()) == 1
195185
assert called
196186

197-
198187
def test_has_keys():
199188
assert not polyglot.__has_keys__(True)
200189
assert polyglot.__has_keys__(None)
201190
assert polyglot.__has_keys__(NotImplemented)
202191
assert not polyglot.__has_keys__(False)
203192
assert polyglot.__has_keys__(object())
204193

205-
206194
def test_keys():
207195
o = CustomObject()
208196
assert len(polyglot.__keys__(o)) == 0
209197
o.my_field = 1
210198
assert len(polyglot.__keys__(o)) == 1
211199
assert "my_field" in polyglot.__keys__(o)
212200

213-
214201
def test_host_lookup():
215202
import java
216203
try:

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/datamodel/IsSequenceNode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@
4646
import com.oracle.truffle.api.profiles.ConditionProfile;
4747

4848
public abstract class IsSequenceNode extends PDataModelEmulationNode {
49-
@Child private HasInheritedAttributeNode hasGetItemNode = HasInheritedAttributeNode.create(__LEN__);
50-
@Child private HasInheritedAttributeNode hasLenNode = HasInheritedAttributeNode.create(__GETITEM__);
49+
@Child private HasInheritedAttributeNode hasGetItemNode = HasInheritedAttributeNode.create(__GETITEM__);
50+
@Child private HasInheritedAttributeNode hasLenNode = HasInheritedAttributeNode.create(__LEN__);
5151

5252
private final ConditionProfile lenProfile = ConditionProfile.createBinaryProfile();
5353
private final ConditionProfile getItemProfile = ConditionProfile.createBinaryProfile();

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/interop/PythonMessageResolution.java

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,16 @@
3838
*/
3939
package com.oracle.graal.python.runtime.interop;
4040

41+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__GETITEM__;
42+
4143
import java.util.Arrays;
4244

4345
import com.oracle.graal.python.builtins.modules.BuiltinFunctions;
4446
import com.oracle.graal.python.builtins.modules.BuiltinFunctionsFactory;
4547
import com.oracle.graal.python.builtins.objects.PNone;
4648
import com.oracle.graal.python.builtins.objects.PythonAbstractObject;
4749
import com.oracle.graal.python.builtins.objects.cext.PythonNativeObject;
50+
import com.oracle.graal.python.builtins.objects.common.PHashingCollection;
4851
import com.oracle.graal.python.builtins.objects.function.PKeyword;
4952
import com.oracle.graal.python.builtins.objects.list.PList;
5053
import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject;
@@ -60,6 +63,7 @@
6063
import com.oracle.graal.python.nodes.attributes.LookupInheritedAttributeNode;
6164
import com.oracle.graal.python.nodes.attributes.SetAttributeNode;
6265
import com.oracle.graal.python.nodes.call.CallDispatchNode;
66+
import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode;
6367
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
6468
import com.oracle.graal.python.nodes.datamodel.IsCallableNode;
6569
import com.oracle.graal.python.nodes.datamodel.IsMappingNode;
@@ -444,19 +448,90 @@ public Object access(Object object) {
444448

445449
@Resolve(message = "HAS_SIZE")
446450
abstract static class PForeignHasSizeNode extends Node {
451+
@Child private IsSequenceNode isSequenceNode;
452+
@Child private IsMappingNode isMappingNode;
453+
@Child private BuiltinFunctions.LenNode lenNode;
454+
@Child private PTypeUnboxNode unboxNode;
455+
@Child private LookupAndCallBinaryNode callGetItemNode;
456+
457+
private final ValueProfile profile = ValueProfile.createClassProfile();
458+
447459
public Object access(Object object) {
448-
return object instanceof PSequence;
460+
Object profiled = profile.profile(object);
461+
// A sequence object always has a size even if there is no '__len__' attribute. This is,
462+
// e.g., the case for 'array'.
463+
if (profiled instanceof PSequence) {
464+
return true;
465+
}
466+
if (profiled instanceof PHashingCollection) {
467+
return false;
468+
}
469+
if (getIsSequenceNode().execute(profiled) && !getIsMappingNode().execute(profiled)) {
470+
// also try to access using an integer index
471+
int len = (int) getUnboxNode().execute(getLenNode().executeWith(profiled));
472+
if (len > 0) {
473+
try {
474+
getCallGetItemNode().executeObject(profiled, 0);
475+
return true;
476+
} catch (PException e) {
477+
return false;
478+
}
479+
}
480+
return true;
481+
}
482+
return false;
483+
}
484+
485+
private BuiltinFunctions.LenNode getLenNode() {
486+
if (lenNode == null) {
487+
CompilerDirectives.transferToInterpreterAndInvalidate();
488+
lenNode = insert(BuiltinFunctionsFactory.LenNodeFactory.create());
489+
}
490+
return lenNode;
491+
}
492+
493+
private PTypeUnboxNode getUnboxNode() {
494+
if (unboxNode == null) {
495+
CompilerDirectives.transferToInterpreterAndInvalidate();
496+
unboxNode = insert(PTypeUnboxNode.create());
497+
}
498+
return unboxNode;
499+
}
500+
501+
private LookupAndCallBinaryNode getCallGetItemNode() {
502+
if (callGetItemNode == null) {
503+
CompilerDirectives.transferToInterpreterAndInvalidate();
504+
callGetItemNode = insert(LookupAndCallBinaryNode.create(__GETITEM__));
505+
}
506+
return callGetItemNode;
507+
}
508+
509+
private IsSequenceNode getIsSequenceNode() {
510+
if (isSequenceNode == null) {
511+
CompilerDirectives.transferToInterpreterAndInvalidate();
512+
isSequenceNode = insert(IsSequenceNode.create());
513+
}
514+
return isSequenceNode;
515+
}
516+
517+
private IsMappingNode getIsMappingNode() {
518+
if (isMappingNode == null) {
519+
CompilerDirectives.transferToInterpreterAndInvalidate();
520+
isMappingNode = insert(IsMappingNode.create());
521+
}
522+
return isMappingNode;
449523
}
450524
}
451525

452526
@Resolve(message = "GET_SIZE")
453527
abstract static class PForeignGetSizeNode extends Node {
454528
@Child IsSequenceNode isSeq = IsSequenceNode.create();
455529
@Child private BuiltinFunctions.LenNode lenNode = BuiltinFunctionsFactory.LenNodeFactory.create();
530+
@Child private PTypeUnboxNode unboxNode = PTypeUnboxNode.create();
456531

457532
public Object access(Object object) {
458533
if (isSeq.execute(object)) {
459-
return lenNode.executeWith(object);
534+
return unboxNode.execute(lenNode.executeWith(object));
460535
}
461536
throw UnsupportedMessageException.raise(Message.GET_SIZE);
462537
}

0 commit comments

Comments
 (0)