Skip to content

Commit 34e60f0

Browse files
committed
[GR-20146] Add "length" message to PythonObjectLibrary
PullRequest: graalpython/769
2 parents bd4ef72 + 0aa0575 commit 34e60f0

13 files changed

+256
-103
lines changed

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

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@
6565
import static com.oracle.graal.python.nodes.HiddenAttributes.ID_KEY;
6666
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__NAME__;
6767
import static com.oracle.graal.python.nodes.SpecialMethodNames.__INSTANCECHECK__;
68-
import static com.oracle.graal.python.nodes.SpecialMethodNames.__LEN__;
6968
import static com.oracle.graal.python.nodes.SpecialMethodNames.__NEXT__;
7069
import static com.oracle.graal.python.nodes.SpecialMethodNames.__SUBCLASSCHECK__;
7170
import static com.oracle.graal.python.runtime.exception.PythonErrorType.OverflowError;
@@ -143,7 +142,6 @@
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;
146-
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode.NoAttributeHandler;
147145
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
148146
import com.oracle.graal.python.nodes.control.GetIteratorExpressionNode.GetIteratorNode;
149147
import com.oracle.graal.python.nodes.control.GetNextNode;
@@ -188,6 +186,7 @@
188186
import com.oracle.truffle.api.dsl.Fallback;
189187
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
190188
import com.oracle.truffle.api.dsl.ImportStatic;
189+
import com.oracle.truffle.api.dsl.ReportPolymorphism;
191190
import com.oracle.truffle.api.dsl.Specialization;
192191
import com.oracle.truffle.api.dsl.TypeSystemReference;
193192
import com.oracle.truffle.api.frame.Frame;
@@ -1206,31 +1205,12 @@ public Object iter(Object callable, Object sentinel) {
12061205
// len(s)
12071206
@Builtin(name = LEN, minNumOfPositionalArgs = 1)
12081207
@GenerateNodeFactory
1208+
@ReportPolymorphism
12091209
public abstract static class LenNode extends PythonUnaryBuiltinNode {
1210-
1211-
private static final Supplier<NoAttributeHandler> NO_LEN = () -> new NoAttributeHandler() {
1212-
@Child private PRaiseNode raiseNode;
1213-
1214-
@Override
1215-
public Object execute(Object receiver) {
1216-
if (raiseNode == null) {
1217-
CompilerDirectives.transferToInterpreterAndInvalidate();
1218-
raiseNode = insert(PRaiseNode.create());
1219-
}
1220-
throw raiseNode.raise(TypeError, "object of type '%p' has no len()", receiver);
1221-
}
1222-
};
1223-
1224-
public abstract Object executeWith(VirtualFrame frame, Object object);
1225-
1226-
protected static LookupAndCallUnaryNode createLen() {
1227-
return LookupAndCallUnaryNode.create(__LEN__, NO_LEN);
1228-
}
1229-
1230-
@Specialization
1231-
public Object len(VirtualFrame frame, Object obj,
1232-
@Cached("createLen()") LookupAndCallUnaryNode dispatch) {
1233-
return dispatch.executeObject(frame, obj);
1210+
@Specialization(limit = "getCallSiteInlineCacheMaxDepth()")
1211+
public int len(VirtualFrame frame, Object obj,
1212+
@CachedLibrary("obj") PythonObjectLibrary lib) {
1213+
return lib.lengthWithState(obj, PArguments.getThreadState(frame));
12341214
}
12351215
}
12361216

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

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -173,7 +173,6 @@ abstract static class LZMANode extends PythonBuiltinNode {
173173

174174
@Child private GetItemNode getItemNode;
175175
@Child private PythonObjectLibrary castToLongNode;
176-
@Child private BuiltinFunctions.LenNode lenNode;
177176
@CompilationFinal private IsBuiltinClassProfile keyErrorProfile;
178177

179178
@TruffleBoundary
@@ -195,7 +194,7 @@ protected static LZMA2Options parseLZMAOptions(int preset) {
195194

196195
// corresponds to 'parse_filter_chain_spec' in '_lzmamodule.c'
197196
protected FilterOptions[] parseFilterChainSpec(VirtualFrame frame, Object filters, PythonObjectLibrary library) {
198-
int n = len(frame, filters);
197+
int n = library.lengthWithState(filters, PArguments.getThreadState(frame));
199198
FilterOptions[] optionsChain = new FilterOptions[n];
200199
for (int i = 0; i < n; i++) {
201200
optionsChain[i] = convertLZMAFilter(frame, getItem(frame, filters, i), library);
@@ -285,14 +284,6 @@ private int asInt(VirtualFrame frame, Object obj) {
285284
return castToLongNode.asSizeWithState(obj, PArguments.getThreadState(frame));
286285
}
287286

288-
private int len(VirtualFrame frame, Object obj) {
289-
if (lenNode == null) {
290-
CompilerDirectives.transferToInterpreterAndInvalidate();
291-
lenNode = insert(BuiltinFunctionsFactory.LenNodeFactory.create());
292-
}
293-
return asInt(frame, lenNode.execute(frame, obj));
294-
}
295-
296287
protected static boolean isNoneOrNoValue(Object obj) {
297288
return PGuards.isNone(obj) || PGuards.isNoValue(obj);
298289
}
@@ -419,7 +410,6 @@ private static LZMAOutputStream createLZMAOutputStream(ByteArrayOutputStream bos
419410
abstract static class LZMADecompressorNode extends LZMANode {
420411

421412
@Child private GetItemNode getItemNode;
422-
@Child private BuiltinFunctions.LenNode lenNode;
423413

424414
@CompilationFinal private IsBuiltinClassProfile keyErrorProfile;
425415

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,36 @@ public boolean isSequence(@Shared("thisObject") @Cached GetLazyClassNode getClas
590590
return pythonTypeLibrary.isSequenceType(getClassNode.execute(this));
591591
}
592592

593+
@ExportMessage
594+
public int lengthWithState(ThreadState state,
595+
@Exclusive @Cached("createBinaryProfile()") ConditionProfile gotState,
596+
@Exclusive @Cached("createBinaryProfile()") ConditionProfile hasLen,
597+
@Exclusive @Cached("createBinaryProfile()") ConditionProfile ltZero,
598+
@Exclusive @Cached LookupInheritedAttributeNode.Dynamic getLenNode,
599+
@Exclusive @Cached CallNode callNode,
600+
@Exclusive @Cached PRaiseNode raiseNode,
601+
@Exclusive @CachedLibrary(limit = "1") PythonObjectLibrary lib) {
602+
Object lenFunc = getLenNode.execute(this, SpecialMethodNames.__LEN__);
603+
if (hasLen.profile(lenFunc != PNone.NO_VALUE)) {
604+
Object lenResult;
605+
int len;
606+
if (gotState.profile(state == null)) {
607+
lenResult = callNode.execute(lenFunc, this);
608+
len = lib.asSize(lenResult);
609+
} else {
610+
lenResult = callNode.execute(PArguments.frameForCall(state), lenFunc, this);
611+
len = lib.asSizeWithState(lenResult, state);
612+
}
613+
if (ltZero.profile(len < 0)) {
614+
throw raiseNode.raise(PythonBuiltinClassType.ValueError, "__len__() should return >= 0");
615+
} else {
616+
return len;
617+
}
618+
} else {
619+
throw raiseNode.raiseHasNoLength(this);
620+
}
621+
}
622+
593623
@ExportMessage
594624
public boolean isMapping(@Shared("thisObject") @Cached GetLazyClassNode getClassNode,
595625
@CachedLibrary(limit = "1") PythonObjectLibrary pythonTypeLibrary) {

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

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@
124124
import com.oracle.graal.python.nodes.attributes.LookupAttributeInMRONode;
125125
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
126126
import com.oracle.graal.python.nodes.attributes.WriteAttributeToObjectNode;
127-
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode.LookupAndCallUnaryDynamicNode;
128127
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
129128
import com.oracle.graal.python.nodes.object.GetClassNode;
130129
import com.oracle.graal.python.nodes.object.GetLazyClassNode;
@@ -601,24 +600,24 @@ Object doObBase(PString o, @SuppressWarnings("unused") String key,
601600
return toSulongNode.execute(o);
602601
}
603602

604-
@Specialization(guards = "eq(OB_SIZE, key)")
603+
@Specialization(guards = "eq(OB_SIZE, key)", limit = "getCallSiteInlineCacheMaxDepth()")
605604
long doObSize(Object object, @SuppressWarnings("unused") String key,
606-
@Exclusive @Cached LookupAndCallUnaryDynamicNode callLenNode) {
607-
Object res = callLenNode.executeObject(object, SpecialMethodNames.__LEN__);
608-
if (res instanceof Number) {
609-
return ((Number) res).intValue();
605+
@CachedLibrary("object") PythonObjectLibrary lib) {
606+
try {
607+
return lib.length(object);
608+
} catch (PException e) {
609+
return -1;
610610
}
611-
return -1;
612611
}
613612

614-
@Specialization(guards = "eq(MA_USED, key)")
613+
@Specialization(guards = "eq(MA_USED, key)", limit = "getCallSiteInlineCacheMaxDepth()")
615614
int doMaUsed(PDict object, @SuppressWarnings("unused") String key,
616-
@Exclusive @Cached LookupAndCallUnaryDynamicNode callLenNode) {
617-
Object res = callLenNode.executeObject(object, SpecialMethodNames.__LEN__);
618-
if (res instanceof Number) {
619-
return ((Number) res).intValue();
615+
@CachedLibrary("object") PythonObjectLibrary lib) {
616+
try {
617+
return lib.length(object);
618+
} catch (PException e) {
619+
return -1;
620620
}
621-
return -1;
622621
}
623622

624623
@Specialization(guards = "eq(OB_SVAL, key)")

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

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -57,13 +57,14 @@
5757
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.NoGeneralizationNode;
5858
import com.oracle.graal.python.builtins.objects.list.PList;
5959
import com.oracle.graal.python.builtins.objects.mmap.PMMap;
60+
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
6061
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
6162
import com.oracle.graal.python.nodes.SpecialMethodNames;
6263
import com.oracle.graal.python.nodes.attributes.LookupInheritedAttributeNode;
6364
import com.oracle.graal.python.nodes.call.CallNode;
64-
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode.LookupAndCallUnaryDynamicNode;
6565
import com.oracle.graal.python.nodes.truffle.PythonTypes;
6666
import com.oracle.graal.python.nodes.util.CoerceToJavaLongNode;
67+
import com.oracle.graal.python.runtime.PythonOptions;
6768
import com.oracle.graal.python.runtime.sequence.PSequence;
6869
import com.oracle.graal.python.runtime.sequence.storage.EmptySequenceStorage;
6970
import com.oracle.graal.python.runtime.sequence.storage.NativeSequenceStorage;
@@ -138,9 +139,8 @@ public boolean equals(Object obj) {
138139
@ExportMessage
139140
final long getArraySize(
140141
@CachedLibrary("this") PythonNativeWrapperLibrary lib,
141-
@Shared("callLenNode") @Cached LookupAndCallUnaryDynamicNode callLenNode,
142-
@Shared("castToLongNode") @Cached CoerceToJavaLongNode castToLongNode) {
143-
return castToLongNode.execute(callLenNode.executeObject(lib.getDelegate(this), SpecialMethodNames.__LEN__));
142+
@CachedLibrary(limit = "getCallSiteInlineCacheMaxDepth()") PythonObjectLibrary objectLib) {
143+
return objectLib.length(lib.getDelegate(this));
144144
}
145145

146146
@ExportMessage
@@ -156,13 +156,16 @@ final Object readArrayElement(long index,
156156
return readArrayItemNode.execute(lib.getDelegate(this), index);
157157
}
158158

159+
static int getCallSiteInlineCacheMaxDepth() {
160+
return PythonOptions.getCallSiteInlineCacheMaxDepth();
161+
}
162+
159163
@ExportMessage
160164
final boolean isArrayElementReadable(long identifier,
161165
@CachedLibrary("this") PythonNativeWrapperLibrary lib,
162-
@Shared("callLenNode") @Cached LookupAndCallUnaryDynamicNode callLenNode,
163-
@Shared("castToLongNode") @Cached CoerceToJavaLongNode castToLongNode) {
166+
@CachedLibrary(limit = "getCallSiteInlineCacheMaxDepth()") PythonObjectLibrary objectLib) {
164167
// also include the implicit null-terminator
165-
return 0 <= identifier && identifier <= getArraySize(lib, callLenNode, castToLongNode);
168+
return 0 <= identifier && identifier <= getArraySize(lib, objectLib);
166169
}
167170

168171
@ImportStatic({SpecialMethodNames.class, PySequenceArrayWrapper.class})
@@ -302,25 +305,22 @@ public void removeArrayElement(@SuppressWarnings("unused") long index) throws Un
302305
@ExportMessage
303306
public boolean isArrayElementModifiable(long index,
304307
@CachedLibrary("this") PythonNativeWrapperLibrary lib,
305-
@Shared("callLenNode") @Cached LookupAndCallUnaryDynamicNode callLenNode,
306-
@Shared("castToLongNode") @Cached CoerceToJavaLongNode castToLongNode) {
307-
return 0 <= index && index <= getArraySize(lib, callLenNode, castToLongNode);
308+
@CachedLibrary(limit = "getCallSiteInlineCacheMaxDepth()") PythonObjectLibrary objectLib) {
309+
return 0 <= index && index <= getArraySize(lib, objectLib);
308310
}
309311

310312
@ExportMessage
311313
public boolean isArrayElementInsertable(long index,
312314
@CachedLibrary("this") PythonNativeWrapperLibrary lib,
313-
@Shared("callLenNode") @Cached LookupAndCallUnaryDynamicNode callLenNode,
314-
@Shared("castToLongNode") @Cached CoerceToJavaLongNode castToLongNode) {
315-
return 0 <= index && index <= getArraySize(lib, callLenNode, castToLongNode);
315+
@CachedLibrary(limit = "getCallSiteInlineCacheMaxDepth()") PythonObjectLibrary objectLib) {
316+
return 0 <= index && index <= getArraySize(lib, objectLib);
316317
}
317318

318319
@ExportMessage
319320
public boolean isArrayElementRemovable(long index,
320321
@CachedLibrary("this") PythonNativeWrapperLibrary lib,
321-
@Shared("callLenNode") @Cached LookupAndCallUnaryDynamicNode callLenNode,
322-
@Shared("castToLongNode") @Cached CoerceToJavaLongNode castToLongNode) {
323-
return 0 <= index && index <= getArraySize(lib, callLenNode, castToLongNode);
322+
@CachedLibrary(limit = "getCallSiteInlineCacheMaxDepth()") PythonObjectLibrary objectLib) {
323+
return 0 <= index && index <= getArraySize(lib, objectLib);
324324
}
325325

326326
@GenerateUncached

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/memoryview/PMemoryView.java

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -43,13 +43,11 @@
4343
import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject;
4444
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
4545
import com.oracle.graal.python.builtins.objects.type.LazyPythonClass;
46-
import com.oracle.graal.python.nodes.SpecialMethodNames;
4746
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromDynamicObjectNode;
48-
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode.LookupAndCallUnaryDynamicNode;
4947
import com.oracle.graal.python.nodes.util.CastToByteNode;
50-
import com.oracle.graal.python.nodes.util.CastToJavaIntNode;
5148
import com.oracle.truffle.api.dsl.Cached;
5249
import com.oracle.truffle.api.dsl.Cached.Shared;
50+
import com.oracle.truffle.api.library.CachedLibrary;
5351
import com.oracle.truffle.api.library.ExportLibrary;
5452
import com.oracle.truffle.api.library.ExportMessage;
5553

@@ -70,21 +68,19 @@ boolean isBuffer() {
7068
@ExportMessage
7169
int getBufferLength(
7270
@Shared("readNativeMemoryViewNode") @Cached ReadAttributeFromDynamicObjectNode readNativeMemoryViewNode,
73-
@Shared("lenNode") @Cached LookupAndCallUnaryDynamicNode lenNode,
74-
@Shared("castToIntNode") @Cached CastToJavaIntNode castToIntNode) {
71+
@CachedLibrary(limit = "1") PythonObjectLibrary lib) {
7572
Object nativeMemoryViewObject = readNativeMemoryViewNode.execute(getStorage(), C_MEMORYVIEW);
76-
return castToIntNode.execute(lenNode.executeObject(nativeMemoryViewObject, SpecialMethodNames.__LEN__));
73+
return lib.length(nativeMemoryViewObject);
7774
}
7875

7976
@ExportMessage
8077
byte[] getBufferBytes(
8178
@Shared("readNativeMemoryViewNode") @Cached ReadAttributeFromDynamicObjectNode readNativeMemoryViewNode,
82-
@Shared("lenNode") @Cached LookupAndCallUnaryDynamicNode lenNode,
83-
@Shared("castToIntNode") @Cached CastToJavaIntNode castToIntNode,
79+
@CachedLibrary(limit = "1") PythonObjectLibrary lib,
8480
@Cached PInteropSubscriptNode subscriptNode,
8581
@Cached CastToByteNode castToByteNode) {
8682
Object nativeMemoryViewObject = readNativeMemoryViewNode.execute(getStorage(), C_MEMORYVIEW);
87-
int len = castToIntNode.execute(lenNode.executeObject(nativeMemoryViewObject, SpecialMethodNames.__LEN__));
83+
int len = lib.length(nativeMemoryViewObject);
8884
byte[] data = new byte[len];
8985
for (int i = 0; i < data.length; i++) {
9086
data[i] = castToByteNode.execute(null, subscriptNode.execute(nativeMemoryViewObject, i));

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

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ static Object asIndex(Object receiver,
9292
@ExportMessage
9393
static int asSize(Object receiver, LazyPythonClass type,
9494
@Shared("raiseNode") @Cached PRaiseNode raise,
95-
@CachedLibrary("receiver") InteropLibrary interopLib) {
95+
@CachedLibrary(limit = "2") InteropLibrary interopLib) {
9696
Object index = asIndex(receiver, raise, interopLib);
9797
if (interopLib.fitsInInt(index)) {
9898
try {
@@ -116,4 +116,26 @@ static LazyPythonClass getLazyPythonClass(@SuppressWarnings("unused") Object val
116116
static long hash(Object receiver) {
117117
return receiver.hashCode();
118118
}
119+
120+
@ExportMessage
121+
static int length(Object receiver,
122+
@Shared("raiseNode") @Cached PRaiseNode raise,
123+
@CachedLibrary("receiver") InteropLibrary interopLib) {
124+
if (interopLib.hasArrayElements(receiver)) {
125+
long sz;
126+
try {
127+
sz = interopLib.getArraySize(receiver);
128+
} catch (UnsupportedMessageException e) {
129+
CompilerDirectives.transferToInterpreter();
130+
throw new IllegalStateException(e);
131+
}
132+
if (sz == (int) sz) {
133+
return (int) sz;
134+
} else {
135+
throw raise.raiseNumberTooLarge(PythonBuiltinClassType.OverflowError, sz);
136+
}
137+
} else {
138+
throw raise.raiseHasNoLength(receiver);
139+
}
140+
}
119141
}

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -84,4 +84,9 @@ static byte[] getBufferBytes(String str) {
8484
static long hash(String self) {
8585
return self.hashCode();
8686
}
87+
88+
@ExportMessage
89+
static int length(String self) {
90+
return self.length();
91+
}
8792
}

0 commit comments

Comments
 (0)