Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
package com.oracle.graal.python.builtins.modules.cext;

import static com.oracle.graal.python.builtins.PythonBuiltinClassType.IndexError;
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.MemoryError;
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.SystemError;
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
import static com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiCallPath.Direct;
Expand Down Expand Up @@ -68,9 +69,13 @@
import com.oracle.graal.python.builtins.objects.PNone;
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.EnsurePythonObjectNode;
import com.oracle.graal.python.builtins.objects.cext.capi.PySequenceArrayWrapper;
import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTiming;
import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.NativeToPythonInternalNode;
import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.PythonToNativeInternalNode;
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.GetItemScalarNode;
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.ListGeneralizationNode;
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.SetItemScalarNode;
import com.oracle.graal.python.builtins.objects.ints.PInt;
import com.oracle.graal.python.builtins.objects.list.ListBuiltins;
import com.oracle.graal.python.builtins.objects.list.ListBuiltins.ListExtendNode;
import com.oracle.graal.python.builtins.objects.list.ListBuiltins.ListInsertNode;
Expand All @@ -79,7 +84,7 @@
import com.oracle.graal.python.lib.PySliceNew;
import com.oracle.graal.python.nodes.ErrorMessages;
import com.oracle.graal.python.nodes.PRaiseNode;
import com.oracle.graal.python.nodes.builtins.ListNodes.AppendNode;
import com.oracle.graal.python.nodes.builtins.ListNodes.PListAppendNode;
import com.oracle.graal.python.nodes.builtins.TupleNodes.ConstructTupleNode;
import com.oracle.graal.python.runtime.PythonContext;
import com.oracle.graal.python.runtime.object.PFactory;
Expand All @@ -95,31 +100,31 @@

public final class PythonCextListBuiltins {

@CApiBuiltin(ret = PyObjectTransfer, args = {Py_ssize_t}, call = Direct)
abstract static class PyList_New extends CApiUnaryBuiltinNode {
@Specialization(guards = "size < 0")
static Object newListError(long size,
@Bind Node inliningTarget) {
throw PRaiseNode.raiseStatic(inliningTarget, SystemError, BAD_ARG_TO_INTERNAL_FUNC_S, size);
}

@SuppressWarnings("unused")
@Specialization(guards = "size == 0")
static Object newEmptyList(long size,
@Bind PythonLanguage language) {
return PFactory.createList(language);
}
private static final CApiTiming TIMING_PYLIST_NEW = CApiTiming.create(false, "PyList_New");

@Specialization(guards = "size > 0")
static Object newList(long size,
@Bind PythonLanguage language) {
return PFactory.createList(language, array(size));
}
@CApiBuiltin(ret = PyObjectTransfer, args = {Py_ssize_t}, call = Direct, acquireGil = false)
static long PyList_New(long size) {
CApiTiming.enter();
try {
if (size < 0) {
throw PRaiseNode.raiseStatic(null, SystemError, BAD_ARG_TO_INTERNAL_FUNC_S, size);
}

private static Object[] array(long size) {
Object[] a = new Object[(int) size];
Arrays.fill(a, PNone.NO_VALUE);
return a;
PythonLanguage language = PythonLanguage.get(null);
PList result;
if (size == 0) {
result = PFactory.createList(language);
} else {
if (!PInt.fitsInInt(size)) {
throw PRaiseNode.raiseStatic(null, MemoryError);
}
Object[] a = new Object[(int) size];
Arrays.fill(a, PNone.NO_VALUE);
result = PFactory.createList(language, a);
}
return PythonToNativeInternalNode.executeNewRefUncached(result);
} finally {
CApiTiming.exit(TIMING_PYLIST_NEW);
}
}

Expand Down Expand Up @@ -157,58 +162,50 @@ Object fallback(Object list, @SuppressWarnings("unused") Object pos) {
}
}

@CApiBuiltin(ret = PyObjectTransfer, args = {PyObject, Py_ssize_t}, call = Direct)
abstract static class PyList_GetItemRef extends CApiBinaryBuiltinNode {
private static final CApiTiming TIMING_PYLIST_GETITEMREF = CApiTiming.create(false, "PyList_GetItemRef");

@Specialization
static Object doPList(PList list, long key,
@Bind Node inliningTarget,
@Bind PythonContext context,
@Cached EnsurePythonObjectNode ensureNode,
@Cached ListGeneralizationNode generalizationNode,
@Cached SetItemScalarNode setItemNode,
@Cached GetItemScalarNode getItemNode,
@Cached PRaiseNode raiseNode) {
@CApiBuiltin(ret = PyObjectTransfer, args = {PyObject, Py_ssize_t}, call = Direct)
static long PyList_GetItemRef(long opPtr, long key) {
CApiTiming.enter();
try {
Object op = NativeToPythonInternalNode.executeUncached(opPtr, false);
if (!(op instanceof PList list)) {
throw PRaiseNode.raiseStatic(null, TypeError, ErrorMessages.EXPECTED_A_LIST);
}
SequenceStorage sequenceStorage = list.getSequenceStorage();
// we must do a bounds-check but we must not normalize the index
if (key < 0 || key >= sequenceStorage.length()) {
throw raiseNode.raise(inliningTarget, IndexError, ErrorMessages.LIST_INDEX_OUT_OF_RANGE);
throw PRaiseNode.raiseStatic(null, IndexError, ErrorMessages.LIST_INDEX_OUT_OF_RANGE);
}
Object result = getItemNode.execute(inliningTarget, sequenceStorage, (int) key);
Object result = GetItemScalarNode.executeUncached(sequenceStorage, (int) key);
// See the note in PyDict_GetItemRef
Object promotedValue = ensureNode.execute(context, result, false);
Object promotedValue = EnsurePythonObjectNode.executeUncached(PythonContext.get(null), result, false);
if (promotedValue != result) {
sequenceStorage = generalizationNode.execute(inliningTarget, sequenceStorage, promotedValue);
sequenceStorage = ListGeneralizationNode.executeUncached(sequenceStorage, promotedValue);
list.setSequenceStorage(sequenceStorage);
setItemNode.execute(inliningTarget, sequenceStorage, (int) key, promotedValue);
return promotedValue;
SetItemScalarNode.executeUncached(sequenceStorage, (int) key, promotedValue);
}
return result;
}

@Fallback
static Object fallback(@SuppressWarnings("unused") Object list, @SuppressWarnings("unused") Object pos,
@Bind Node inliningTarget) {
throw PRaiseNode.raiseStatic(inliningTarget, TypeError, ErrorMessages.EXPECTED_A_LIST);
return PythonToNativeInternalNode.executeNewRefUncached(promotedValue);
} finally {
CApiTiming.exit(TIMING_PYLIST_GETITEMREF);
}
}

@CApiBuiltin(ret = Int, args = {PyObject, PyObject}, call = Direct)
abstract static class PyList_Append extends CApiBinaryBuiltinNode {
private static final CApiTiming TIMING_PYLIST_APPEND = CApiTiming.create(false, "PyList_Append");

@Specialization
int append(PList list, Object newItem,
@Cached AppendNode appendNode) {
if (newItem == PNone.NO_VALUE) {
throw badInternalCall("newitem");
@CApiBuiltin(ret = Int, args = {PyObject, PyObject}, call = Direct)
static int PyList_Append(long opPtr, long itemPtr) {
CApiTiming.enter();
try {
Object op = NativeToPythonInternalNode.executeUncached(opPtr, false);
Object item = NativeToPythonInternalNode.executeUncached(itemPtr, false);
if (op instanceof PList list && item != PNone.NO_VALUE) {
PListAppendNode.executeUncached(list, item);
return 0;
}
appendNode.execute(list, newItem);
return 0;
}

@Fallback
int fallback(Object list, @SuppressWarnings("unused") Object newItem) {
throw raiseFallback(list, PythonBuiltinClassType.PList);
throw PythonCextBuiltins.badInternalCall("PyList_Append", "op");
} finally {
CApiTiming.exit(TIMING_PYLIST_APPEND);
}
}

Expand Down Expand Up @@ -293,21 +290,23 @@ Object fallback(Object list, @SuppressWarnings("unused") Object iterable) {
}
}

private static final CApiTiming TIMING_PYLIST_SIZE = CApiTiming.create(false, "PyList_Size");

/*
* A pure-C Py_SIZE implementation regressed mixed managed/native/list-subclass workload by
* about 1.26x.
*/
@CApiBuiltin(ret = Py_ssize_t, args = {PyObject}, call = Direct)
abstract static class PyList_Size extends CApiUnaryBuiltinNode {

@Specialization
static long size(PList list) {
return list.getSequenceStorage().length();
}

@Fallback
long fallback(Object list) {
throw raiseFallback(list, PythonBuiltinClassType.PList);
@CApiBuiltin(ret = Py_ssize_t, args = {PyObject}, call = Direct, acquireGil = false)
static long PyList_Size(long opPtr) {
CApiTiming.enter();
try {
Object op = NativeToPythonInternalNode.executeUncached(opPtr, false);
if (op instanceof PList list) {
return list.getSequenceStorage().length();
}
throw PythonCextBuiltins.badInternalCall("PyList_Size", "op");
} finally {
CApiTiming.exit(TIMING_PYLIST_SIZE);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodesFactory.RepeatNodeGen;
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodesFactory.SetItemDynamicNodeGen;
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodesFactory.SetItemNodeGen;
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodesFactory.SetItemScalarNodeGen;
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodesFactory.StorageToNativeNodeGen;
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodesFactory.ToArrayNodeGen;
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodesFactory.ToByteArrayNodeGen;
Expand Down Expand Up @@ -1324,6 +1325,11 @@ static void doError(@SuppressWarnings("unused") Node inliningTarget, SequenceSto
@GenerateCached(false)
public abstract static class SetItemScalarNode extends AbstractSetItemScalarNode {

@TruffleBoundary
public static void executeUncached(SequenceStorage storage, int idx, Object value) {
SetItemScalarNodeGen.getUncached().execute(null, storage, idx, value);
}

@InliningCutoff
@Specialization
protected static void doNative(NativeSequenceStorage storage, int idx, Object value,
Expand Down Expand Up @@ -2830,6 +2836,11 @@ public GeneralizationNode create() {
}
};

@TruffleBoundary
public static SequenceStorage executeUncached(SequenceStorage toGeneralize, Object indicationValue) {
return ListGeneralizationNodeGen.getUncached().execute(null, toGeneralize, indicationValue);
}

@Override
public final SequenceStorage executeCached(SequenceStorage toGeneralize, Object indicationValue) {
return execute(this, toGeneralize, indicationValue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
import com.oracle.graal.python.nodes.PRaiseNode;
import com.oracle.graal.python.nodes.builtins.ListNodesFactory.AppendNodeGen;
import com.oracle.graal.python.nodes.builtins.ListNodesFactory.ConstructListNodeGen;
import com.oracle.graal.python.nodes.builtins.ListNodesFactory.PListAppendNodeGen;
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
import com.oracle.graal.python.nodes.object.GetClassNode;
import com.oracle.graal.python.nodes.object.IsForeignObjectNode;
Expand All @@ -74,7 +75,6 @@
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff;
import com.oracle.truffle.api.bytecode.OperationProxy;
import com.oracle.truffle.api.bytecode.StoreBytecodeIndex;
import com.oracle.truffle.api.dsl.Bind;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Cached.Exclusive;
Expand Down Expand Up @@ -260,6 +260,39 @@ protected PList doGeneric(VirtualFrame frame, Object value,

}

@GenerateUncached
@GenerateInline(false) // footprint reduction 36 -> 17
public abstract static class AppendNode extends PNodeWithContext {

public abstract void execute(Object list, Object value);

@Specialization
static void appendObjectGeneric(PList list, Object value,
@Bind Node inliningTarget,
@Cached PListAppendNode appendNode) {
appendNode.execute(list, value);
}

@Fallback
static void appendObjectForeign(Object list, Object value,
@Bind Node inliningTarget,
@Cached GetListStorageNode getStorageNode,
@Cached SequenceStorageNodes.AppendNode appendNode) {
var storage = getStorageNode.execute(inliningTarget, list);
SequenceStorage newStore = appendNode.execute(inliningTarget, storage, value, ListGeneralizationNode.SUPPLIER);
assert newStore == storage;
}

@NeverDefault
public static AppendNode create() {
return AppendNodeGen.create();
}

public static AppendNode getUncached() {
return AppendNodeGen.getUncached();
}
}

/**
* This node takes a bit of care to avoid compiling code for switching storages. In the
* interpreter, it will use a different {@link AppendNode} than in the compiled code, so the
Expand All @@ -269,12 +302,16 @@ protected PList doGeneric(VirtualFrame frame, Object value,
* code will only see lists of the correct size and storage type.
*/
@GenerateUncached
@GenerateInline(false) // footprint reduction 36 -> 17
@GenerateInline(false)
@OperationProxy.Proxyable(allowUncached = true, storeBytecodeIndex = false)
public abstract static class AppendNode extends PNodeWithContext {
public abstract static class PListAppendNode extends PNodeWithContext {
private static final BranchProfile[] DISABLED = new BranchProfile[]{BranchProfile.getUncached()};

public abstract void execute(Object list, Object value);
public static void executeUncached(PList list, Object value) {
PListAppendNodeGen.getUncached().execute(list, value);
}

public abstract void execute(PList list, Object value);

@NeverDefault
public static BranchProfile[] getUpdateStoreProfile() {
Expand All @@ -286,10 +323,9 @@ public static BranchProfile[] getUpdateStoreProfileUncached() {
}

@Specialization
public static void appendObjectGeneric(PList list, Object value,
public static void doPList(PList list, Object value,
@Bind Node inliningTarget,
// @Exclusive for truffle-interpreted-performance
@Exclusive @Cached SequenceStorageNodes.AppendNode appendNode,
@Cached SequenceStorageNodes.AppendNode appendNode,
@Cached(value = "getUpdateStoreProfile()", uncached = "getUpdateStoreProfileUncached()", dimensions = 1) BranchProfile[] updateStoreProfile) {
if (updateStoreProfile[0] == null) {
// Executed for the first time. We don't pollute the AppendNode specializations,
Expand All @@ -313,26 +349,6 @@ public static void appendObjectGeneric(PList list, Object value,
}
}
}

@Fallback
@StoreBytecodeIndex
public static void appendObjectForeign(Object list, Object value,
@Bind Node inliningTarget,
@Cached GetListStorageNode getStorageNode,
@Exclusive @Cached SequenceStorageNodes.AppendNode appendNode) {
var storage = getStorageNode.execute(inliningTarget, list);
SequenceStorage newStore = appendNode.execute(inliningTarget, storage, value, ListGeneralizationNode.SUPPLIER);
assert newStore == storage;
}

@NeverDefault
public static AppendNode create() {
return AppendNodeGen.create();
}

public static AppendNode getUncached() {
return AppendNodeGen.getUncached();
}
}

@GenerateInline(false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@
@OperationProxy(value = CopyDictWithoutKeysNode.class, name = "CopyDictWithoutKeys")
@OperationProxy(value = PyObjectIsTrueNode.class, name = "Yes")
@OperationProxy(value = PyObjectIsNotTrueNode.class, name = "Not")
@OperationProxy(value = ListNodes.AppendNode.class, name = "ListAppend")
@OperationProxy(value = ListNodes.PListAppendNode.class, name = "ListAppend")
@OperationProxy(value = SetNodes.AddNode.class, name = "SetAdd")
@ShortCircuitOperation(name = "BoolAnd", booleanConverter = PyObjectIsTrueNode.class, operator = Operator.AND_RETURN_VALUE)
@ShortCircuitOperation(name = "BoolOr", booleanConverter = PyObjectIsTrueNode.class, operator = Operator.OR_RETURN_VALUE)
Expand Down
Loading