From a528f8f842f19f845f053d283aa3aafcaae39f2c Mon Sep 17 00:00:00 2001 From: stepan Date: Thu, 15 Oct 2026 09:07:18 +0200 Subject: [PATCH 1/6] Convert external function wrappers (`WrapperBaseRoot`) to builtin nodes wrapped by `BuiltinFunctionRootNode` --- .../processor/CApiBuiltinsProcessor.java | 27 +- .../test/ExternalFunctionWrapperTest.java | 652 ++++++++++++++++++ .../src/tests/cpyext/test_descr.py | 86 ++- .../src/tests/cpyext/test_tp_slots.py | 23 + .../oracle/graal/python/PythonLanguage.java | 2 +- .../modules/cext/PythonCextTypeBuiltins.java | 15 +- .../cext/capi/ExternalFunctionNodes.java | 305 ++++---- .../capi/ExternalFunctionWrapperFactory.java | 211 ++++++ .../cext/capi/MethodDescriptorWrapper.java | 55 +- .../oracle/graal/python/nodes/PRootNode.java | 4 +- .../function/BuiltinFunctionRootNode.java | 92 +-- ...e.java => PythonBuiltinFrameArgsNode.java} | 13 +- .../nodes/function/PythonBuiltinNode.java | 4 +- .../function/builtins/BuiltinCallNode.java | 39 +- 14 files changed, 1222 insertions(+), 306 deletions(-) create mode 100644 graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/ExternalFunctionWrapperTest.java create mode 100644 graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionWrapperFactory.java rename graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/{builtins/PythonSenaryBuiltinNode.java => PythonBuiltinFrameArgsNode.java} (82%) diff --git a/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/CApiBuiltinsProcessor.java b/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/CApiBuiltinsProcessor.java index 78c442f270..5ff044c88c 100644 --- a/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/CApiBuiltinsProcessor.java +++ b/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/CApiBuiltinsProcessor.java @@ -2004,7 +2004,7 @@ private void generateExternalFunctionRootNodes(List lines.add("package " + EXFUNC_INVOKER_PACKAGE + ";"); lines.add(""); - lines.add("import com.oracle.graal.python.PythonLanguage;"); + lines.add("import com.oracle.graal.python.builtins.objects.function.Signature;"); lines.add("import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.EnsurePythonObjectNode;"); for (InvokeExternalFunctionDesc wrapper : wrapperInvokeDescs) { Element clazz = wrapper.origin.getEnclosingElement(); @@ -2014,7 +2014,6 @@ private void generateExternalFunctionRootNodes(List lines.add("import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.WrapperDescriptorRoot;"); lines.add("import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTiming;"); lines.add("import " + NATIVE_FUNCTION_POINTER + ";"); - lines.add("import com.oracle.graal.python.runtime.ExecutionContext.CalleeContext;"); lines.add("import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData;"); lines.add("import com.oracle.graal.python.runtime.PythonContext;"); lines.add("import com.oracle.graal.python.runtime.PythonContext.GetThreadStateNode;"); @@ -2097,7 +2096,6 @@ private void generateExternalFunctionRootNodes(List lines.add(""); lines.add(" public static final class " + genClassName + " extends " + clazz.getSimpleName() + " {"); lines.add(""); - lines.add(" @Child private CalleeContext calleeContext = CalleeContext.create();"); lines.add(" @Child private BoundaryCallData boundaryCallData;"); lines.add(" @Child private GetThreadStateNode getThreadStateNode = GetThreadStateNode.create();"); for (int j = 0; j < wrapper.argumentTypes.size(); j++) { @@ -2150,8 +2148,8 @@ private void generateExternalFunctionRootNodes(List lines.add(""); lines.add(" private final CApiTiming timing;"); lines.add(""); - lines.add(" public " + genClassName + "(PythonLanguage language, TruffleString name, PExternalFunctionWrapper wrapper) {"); - lines.add(" super(language, name, wrapper);"); + lines.add(" public " + genClassName + "(TruffleString name, PExternalFunctionWrapper wrapper) {"); + lines.add(" super(name, wrapper);"); lines.add(" this.timing = CApiTiming.create(true, name);"); lines.add(" this.boundaryCallData = BoundaryCallData.createFor(this);"); lines.add(" }"); @@ -2184,16 +2182,31 @@ private void generateExternalFunctionRootNodes(List // generate factory method lines.add(" @TruffleBoundary"); - lines.add(" public static WrapperDescriptorRoot create(PythonLanguage language, TruffleString name, PExternalFunctionWrapper wrapper) {"); + lines.add(" public static WrapperDescriptorRoot create(TruffleString name, PExternalFunctionWrapper wrapper) {"); lines.add(" return switch (wrapper) {"); for (CApiExternalFunctionWrapperDesc wrapper : wrappers) { String wrapperList = wrapper.wrapperNames.stream().map(CApiBuiltinsProcessor::name).collect(Collectors.joining(", ")); - lines.add(" case " + wrapperList + " -> new " + name(wrapper.origin) + "Gen(language, name, wrapper);"); + lines.add(" case " + wrapperList + " -> new " + name(wrapper.origin) + "Gen(name, wrapper);"); } lines.add(" default -> throw CompilerDirectives.shouldNotReachHere(\"no root node for wrapper \" + wrapper);"); lines.add(" };"); lines.add(" }"); + // Use the same annotation mapping for the actual body class and its Python signature. + for (boolean signature : new boolean[]{false, true}) { + lines.add(" @TruffleBoundary"); + lines.add(signature ? " public static Signature getSignature(PExternalFunctionWrapper wrapper) {" + : " public static Class getNodeClass(PExternalFunctionWrapper wrapper) {"); + lines.add(" return switch (wrapper) {"); + for (CApiExternalFunctionWrapperDesc wrapper : wrappers) { + String wrapperList = wrapper.wrapperNames.stream().map(CApiBuiltinsProcessor::name).collect(Collectors.joining(", ")); + lines.add(" case " + wrapperList + " -> " + name(wrapper.origin) + (signature ? ".SIGNATURE;" : ".class;")); + } + lines.add(" default -> throw CompilerDirectives.shouldNotReachHere(\"no body for wrapper \" + wrapper);"); + lines.add(" };"); + lines.add(" }"); + } + // closing brace for WRAPPER_DESCRIPTOR_GEN_CLASS_NAME lines.add("}"); diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/ExternalFunctionWrapperTest.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/ExternalFunctionWrapperTest.java new file mode 100644 index 0000000000..8c16324cf1 --- /dev/null +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/ExternalFunctionWrapperTest.java @@ -0,0 +1,652 @@ +/* + * Copyright (c) 2026, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.graal.python.test; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static com.oracle.graal.python.util.PythonUtils.tsLiteral; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +import org.graalvm.polyglot.Context; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.oracle.graal.python.PythonLanguage; +import com.oracle.graal.python.annotations.Builtin; +import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes; +import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.PExternalFunctionWrapper; +import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.WrapperBaseRoot; +import com.oracle.graal.python.builtins.objects.cext.capi.MethodDescriptorWrapper; +import com.oracle.graal.python.builtins.modules.cext.PythonCextTypeBuiltins; +import com.oracle.graal.python.builtins.objects.frame.FrameBuiltinsFactory.GetLocalsNodeFactory; +import com.oracle.graal.python.builtins.objects.function.PArguments; +import com.oracle.graal.python.builtins.objects.function.PKeyword; +import com.oracle.graal.python.builtins.objects.function.Signature; +import com.oracle.graal.python.runtime.CallerFlags; +import com.oracle.graal.python.nodes.argument.CreateArgumentsNode; +import com.oracle.graal.python.nodes.argument.ReadArgumentNode; +import com.oracle.graal.python.nodes.argument.ReadIndexedArgumentNode; +import com.oracle.graal.python.nodes.argument.ReadVarArgsNode; +import com.oracle.graal.python.nodes.argument.ReadVarKeywordsNode; +import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode; +import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; +import com.oracle.graal.python.nodes.function.PythonBuiltinFrameArgsNode; +import com.oracle.graal.python.nodes.function.PythonBuiltinNode; +import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; +import com.oracle.graal.python.util.PythonUtils.PrototypeNodeFactory; +import com.oracle.truffle.api.RootCallTarget; +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.dsl.NodeFactory; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.DirectCallNode; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.RootNode; +import com.oracle.truffle.api.strings.TruffleString; + +/** Independent inventory and runtime checks for native wrappers using ordinary builtin roots. */ +public class ExternalFunctionWrapperTest { + private Context context; + private static final TruffleString NAME = tsLiteral("wrapper_test"); + + // Positional names and literal vararg indices are the pre-conversion Python signatures. + private record Spec(String body, String enums, String parameters, int vararg, boolean kwargs, boolean hidden, boolean owner, boolean closure, boolean method) { + } + + private static Spec method(String body, String convention, String parameters, int vararg, boolean kwargs) { + return new Spec(body, convention, parameters, vararg, kwargs, true, true, false, true); + } + + private static Spec descriptor(String body, String wrappers, String parameters, int vararg, boolean kwargs, boolean hidden, boolean owner, boolean closure) { + return new Spec(body, wrappers, parameters, vararg, kwargs, hidden, owner, closure, false); + } + + private static final List SPECS = List.of( + method("MethNoargsRoot", "NOARGS", "self", -1, false), + method("MethORoot", "O", "self,arg", -1, false), + method("MethVarargsRoot", "VARARGS", "self", 1, false), + method("MethKeywordsRoot", "KEYWORDS", "self", 1, true), + method("MethFastcallRoot", "FASTCALL", "self", 1, false), + method("MethFastcallWithKeywordsRoot", "FASTCALL_WITH_KEYWORDS", "self", 1, true), + method("MethMethodRoot", "METHOD", "self,cls", 1, true), + descriptor("MethUnaryFunc", "UNARYFUNC", "self", -1, false, false, true, false), + descriptor("MethNewRoot", "NEW", "self", 1, true, true, true, false), + descriptor("MethCallRoot", "CALL", "self", 1, true, true, true, false), + descriptor("MethInitRoot", "INIT", "self", 1, true, true, true, false), + descriptor("MethInquiryRoot", "INQUIRYPRED", "self", -1, false, false, true, false), + descriptor("IndexArgFuncRootNode", "INDEXARGFUNC", "self,i", -1, false, false, true, false), + descriptor("GetAttrFuncRootNode", "GETATTR", "self,key", -1, false, false, true, false), + descriptor("SetAttrFuncRootNode", "SETATTR", "self,key,value", -1, false, false, true, false), + descriptor("SetAttrOFuncRootNode", "SETATTRO", "self,name,value", -1, false, false, true, false), + descriptor("RichCmpFuncRootNode", "RICHCMP", "self,other,op", -1, false, false, true, false), + descriptor("GetItemRootNode", "SQ_ITEM", "self,i", -1, false, false, true, false), + descriptor("SetItemRootNode", "SQ_SETITEM", "self,i,value", -1, false, false, true, false), + descriptor("SqDelItemRootNode", "SQ_DELITEM", "self,key", -1, false, false, true, false), + descriptor("DescrGetRootNode", "DESCR_GET", "self,obj,type", -1, false, false, true, false), + descriptor("DescrDeleteRootNode", "DESCR_DELETE", "self,obj", -1, false, false, true, false), + descriptor("DelAttrRootNode", "DELATTRO", "self,obj", -1, false, false, true, false), + descriptor("MpDelItemRootNode", "MP_DELITEM", "self,key", -1, false, false, true, false), + descriptor("MethTernaryFuncRoot", "TERNARYFUNC,TERNARYFUNC_R", "self,other,third", -1, false, false, false, false), + descriptor("MethRichcmpOpRootNode", "GT,GE,LE,LT,EQ,NE", "self,other", -1, false, false, true, false), + descriptor("IterNextFuncRootNode", "ITERNEXT", "self", -1, false, true, true, false), + descriptor("GetterRoot", "GETTER", "self", -1, false, false, true, true), + descriptor("SetterRoot", "SETTER", "self,value", -1, false, false, true, true), + descriptor("MethLenfuncRoot", "LENFUNC,HASHFUNC", "self", -1, false, false, true, false), + descriptor("MethObjObjProcRoot", "OBJOBJPROC", "self,value", -1, false, false, true, false), + descriptor("MethObjObjArgProcRoot", "OBJOBJARGPROC", "self,key,value", -1, false, false, true, false), + descriptor("MethBinaryRoot", "BINARYFUNC,BINARYFUNC_L,BINARYFUNC_R", "self,other", -1, false, false, true, false), + descriptor("MethDescrSetRoot", "DESCR_SET", "self,instance,value", -1, false, false, true, false)); + + @Before + public void enter() { + context = Context.newBuilder("python").allowAllAccess(true).allowExperimentalOptions(true).option("engine.WarnInterpreterOnly", "false").option("engine.SplittingAllowForcedSplits", + "true").build(); + context.initialize("python"); + context.enter(); + } + + @After + public void leave() { + context.leave(); + context.close(); + } + + private static Object invoke(Class owner, Object receiver, String name, Class[] types, Object... args) throws Exception { + Method method = owner.getDeclaredMethod(name, types); + method.setAccessible(true); + return method.invoke(receiver, args); + } + + private static NodeFactory factory(Spec spec, String convention, boolean isStatic) throws Exception { + if (spec.method) { + return (NodeFactory) invoke(MethodDescriptorWrapper.class, null, "createFactory", + new Class[]{MethodDescriptorWrapper.class, TruffleString.class, boolean.class}, MethodDescriptorWrapper.valueOf(convention), NAME, isStatic); + } + return (NodeFactory) invoke(PExternalFunctionWrapper.class, null, "createFactory", new Class[]{PExternalFunctionWrapper.class, TruffleString.class}, + PExternalFunctionWrapper.valueOf(convention), NAME); + } + + private static BuiltinFunctionRootNode root(NodeFactory factory) throws Exception { + return (BuiltinFunctionRootNode) invoke(factory.getClass(), factory, "createRoot", new Class[]{PythonLanguage.class}, PythonLanguage.get(null)); + } + + private static List names(TruffleString[] names) { + return Arrays.stream(names).map(TruffleString::toJavaStringUncached).toList(); + } + + private static List readerFields(WrapperBaseRoot body) { + List fields = new ArrayList<>(); + for (Class owner = body.getClass(); owner != null; owner = owner.getSuperclass()) { + for (Field field : owner.getDeclaredFields()) { + if (ReadArgumentNode.class.isAssignableFrom(field.getType())) { + field.setAccessible(true); + fields.add(field); + } + } + } + return fields; + } + + private static void initializeReaders(WrapperBaseRoot body, Signature signature) throws Exception { + // Initialize the production helper groups without making a native call. The C API suite + // separately exercises the guards on first and repeated real wrapper invocations. + for (Class owner = body.getClass(); owner != null; owner = owner.getSuperclass()) { + for (Method method : owner.getDeclaredMethods()) { + if ((method.getName().equals("createNodes") || method.getName().equals("ensureReadArgNode")) && method.getParameterCount() == 0) { + method.setAccessible(true); + method.invoke(body); + } + } + } + for (Field field : readerFields(body)) { + if (field.getName().equals("readClosureNode")) { + field.set(body, invoke(ExternalFunctionNodes.GetterRoot.class, null, "createReadClosureNode", new Class[]{Signature.class}, signature)); + } + } + } + + private static List checkReaders(WrapperBaseRoot body, Spec spec, boolean isStatic, VirtualFrame frame, Object[] positional, + Object callable, Object closure, Object[] extras, PKeyword[] keywords) throws Exception { + List readers = new ArrayList<>(); + Map counts = new IdentityHashMap<>(); + countChildren(body, counts); + int indexed = 0; + int varargs = 0; + int kwargs = 0; + for (Field field : readerFields(body)) { + ReadArgumentNode reader = (ReadArgumentNode) field.get(body); + if (field.getName().equals("readSelfNode") && isStatic) { + assertSame(null, reader); + continue; + } + assertNotNull(field.getName(), reader); + assertSame(body, reader.getParent()); + assertEquals(Integer.valueOf(1), counts.get(reader)); + readers.add(reader); + Object value = reader.execute(frame); + if (reader instanceof ReadIndexedArgumentNode argument) { + int expectedIndex = switch (field.getName()) { + case "readSelfNode" -> 0; + case "readCallableNode" -> positional.length; + case "readClosureNode" -> positional.length + 1; + case "readArg2Node", "readOpNode", "readType" -> 2; + case "readValueNode" -> positional.length - 1; + case "readArg1Node", "readArgNode", "readClsNode", "readINode", "readInstanceNode", "readKeyNode", "readNameNode", "readObj", "readOtherNode" -> 1; + default -> throw new AssertionError(field.getName()); + }; + assertEquals(field.getName(), expectedIndex, argument.getIndex()); + Object expected = expectedIndex < positional.length ? positional[expectedIndex] : expectedIndex == positional.length ? callable : closure; + assertSame(field.getName(), expected, value); + indexed++; + } else if (reader instanceof ReadVarArgsNode) { + assertArrayEquals(extras, (Object[]) value); + varargs++; + } else if (reader instanceof ReadVarKeywordsNode) { + assertArrayEquals(keywords, (PKeyword[]) value); + kwargs++; + } else { + fail("unexpected production reader: " + reader.getClass()); + } + } + assertEquals(positional.length + (spec.closure ? 2 : 1) - (isStatic ? 1 : 0), indexed); + assertEquals(spec.vararg == -1 ? 0 : 1, varargs); + assertEquals(spec.kwargs ? 1 : 0, kwargs); + assertSame(isStatic ? com.oracle.graal.python.builtins.objects.PNone.NO_VALUE : positional[0], + invoke(WrapperBaseRoot.class, body, "readSelf", new Class[]{VirtualFrame.class}, frame)); + return readers; + } + + @Test + public void builtinBodyDispatch() { + Object token = new Object(); + Object[] arguments = PArguments.create(1); + PArguments.setArgument(arguments, 0, token); + Signature signature = new Signature(false, -1, new TruffleString[]{tsLiteral("self")}, null); + Builtin metadata = OrdinaryNode.class.getAnnotation(Builtin.class); + Builtin frameMetadata = (Builtin) Proxy.newProxyInstance(Builtin.class.getClassLoader(), new Class[]{Builtin.class}, (proxy, method, args) -> { + switch (method.getName()) { + case "parameterNames", "keywordOnlyNames", "minNumOfPositionalArgs", "maxNumOfPositionalArgs", "takesVarArgs", "takesVarKeywordArgs" -> throw new AssertionError( + "frame-only builtin queried reader metadata: " + method.getName()); + } + return method.invoke(metadata, args); + }); + BuiltinFunctionRootNode frameRoot = new BuiltinFunctionRootNode(PythonLanguage.get(null), signature, frameMetadata, + new ZeroArgumentFactory<>(FrameRecordingNode.class, FrameRecordingNode::new), true, null); + BuiltinFunctionRootNode ordinaryRoot = new BuiltinFunctionRootNode(PythonLanguage.get(null), signature, metadata, new RecordingFactory(), true, null); + BuiltinFunctionRootNode unaryRoot = new BuiltinFunctionRootNode(PythonLanguage.get(null), signature, metadata, + new ZeroArgumentFactory<>(UnaryRecordingNode.class, UnaryRecordingNode::new), true, null); + for (int i = 0; i < 2; i++) { + assertSame(token, frameRoot.getCallTarget().call(arguments)); + assertArrayEquals(new Object[]{token}, (Object[]) ordinaryRoot.getCallTarget().call(arguments)); + assertSame(token, unaryRoot.getCallTarget().call(arguments)); + } + } + + @Test + public void readerLayouts() throws Exception { + assertEquals(34, SPECS.size()); + for (Spec spec : SPECS) { + for (boolean isStatic : spec.method && !spec.enums.equals("METHOD") ? new boolean[]{false, true} : new boolean[]{false}) { + BuiltinFunctionRootNode production = root(factory(spec, spec.enums.split(",")[0], isStatic)); + Signature signature = production.getSignature(); + Builtin builtin = production.getBuiltin(); + List parameters = List.of(spec.parameters.split(",")); + List hidden = spec.closure ? List.of("$callable", "$closure") : List.of("$callable"); + assertEquals(spec.body, parameters, names(signature.getParameterIds())); + assertEquals(hidden, names(signature.getKeywordNames())); + assertEquals(0, builtin.parameterNames().length); + assertEquals(0, builtin.keywordOnlyNames().length); + Field vararg = Signature.class.getDeclaredField("varArgIndex"); + vararg.setAccessible(true); + assertEquals(spec.vararg, vararg.getInt(signature)); + assertEquals(-1, signature.getPositionalOnlyArgIndex()); + assertEquals(spec.kwargs, signature.takesVarKeywordArgs()); + assertEquals(spec.owner, signature.checkEnclosingType()); + assertEquals(spec.hidden, signature.isHidden()); + assertEquals("", signature.getRaiseErrorName().toJavaStringUncached()); + assertEquals(0, signature.getVisibleKeywordNames().length); + assertEquals(-1, builtin.maxNumOfPositionalArgs()); + assertEquals(0, builtin.minNumOfPositionalArgs()); + assertTrue(production.declaresExplicitSelf()); + assertTrue(builtin.declaresExplicitSelf()); + assertTrue(builtin.needsFrame()); + assertFalse(builtin.autoRegister()); + + for (int size : new int[]{0, 2}) { + Object[] positional = new Object[parameters.size()]; + Arrays.setAll(positional, i -> new Object()); + Object[] extras = spec.vararg == -1 ? new Object[0] : new Object[size]; + Arrays.setAll(extras, i -> new Object()); + Object callable = new Object(); + Object closure = Long.valueOf(0x12345678L); + PKeyword[] defaults = spec.closure ? new PKeyword[]{new PKeyword(tsLiteral("$callable"), callable), new PKeyword(tsLiteral("$closure"), closure)} + : new PKeyword[]{new PKeyword(tsLiteral("$callable"), callable)}; + PKeyword[] keywords = spec.kwargs && size > 0 ? new PKeyword[]{new PKeyword(tsLiteral("user_a"), new Object()), new PKeyword(tsLiteral("user_b"), new Object())} + : PKeyword.EMPTY_KEYWORDS; + // Bind self and defining class through the same path as bound native methods. + Object cls = spec.enums.equals("METHOD") ? positional[1] : null; + int upfront = cls == null ? 1 : 2; + Object[] user = new Object[positional.length - upfront + extras.length]; + System.arraycopy(positional, upfront, user, 0, positional.length - upfront); + System.arraycopy(extras, 0, user, positional.length - upfront, extras.length); + Object[] bound = CreateArgumentsNode.executeUncached(NAME, user, keywords, signature, positional[0], cls, new Object[0], defaults, true); + WrapperBaseRoot body = (WrapperBaseRoot) production.getFactory().createNode(); + initializeReaders(body, signature); + new AdoptionRoot(body).getCallTarget(); + VirtualFrame frame = Truffle.getRuntime().createVirtualFrame(bound, FrameDescriptor.newBuilder().build()); + List firstReaders = null; + for (int invocation = 0; invocation < 2; invocation++) { + // Exercise the production callable-reader initialization and validation. + // An invalid pointer stops execution before any native conversion/downcall. + boolean rejected = false; + try { + body.execute(frame); + } catch (AssertionError expected) { + assertEquals("com.oracle.truffle.api.CompilerDirectives$ShouldNotReachHere", expected.getClass().getName()); + rejected = true; + } + assertTrue("invalid native pointer must be rejected", rejected); + List readers = checkReaders(body, spec, isStatic, frame, positional, callable, closure, extras, keywords); + if (firstReaders == null) { + firstReaders = readers; + } else { + assertEquals(firstReaders, readers); + } + } + } + } + } + } + + @Test + public void factoryClassesAndChildren() throws Exception { + int methods = 0; + int descriptors = 0; + for (Spec spec : SPECS) { + for (String convention : spec.enums.split(",")) { + NodeFactory factory = factory(spec, convention, false); + assertEquals(ExternalFunctionNodes.class.getName() + "$" + spec.body, factory.getNodeClass().getName()); + assertEquals(List.of(List.of()), factory.getNodeSignatures()); + assertEquals(List.of(), factory.getExecutionSignature()); + WrapperBaseRoot body = (WrapperBaseRoot) factory.createNode(); + WrapperBaseRoot other = (WrapperBaseRoot) factory.createNode(); + assertNotSame(body, other); + assertTrue(PythonBuiltinFrameArgsNode.class.isAssignableFrom(body.getClass())); + assertFalse(PythonBuiltinNode.class.isAssignableFrom(body.getClass())); + assertTrue(factory.getNodeClass().isInstance(body)); + assertEquals(0, factory.getNodeClass().getAnnotationsByType(Builtin.class).length); + initializeReaders(body, root(factory).getSignature()); + initializeReaders(other, root(factory).getSignature()); + new AdoptionRoot(body).getCallTarget(); + new AdoptionRoot(other).getCallTarget(); + Map counts = new IdentityHashMap<>(); + countChildren(body, counts); + Map otherCounts = new IdentityHashMap<>(); + countChildren(other, otherCounts); + for (Field field : readerFields(body)) { + ReadArgumentNode reader = (ReadArgumentNode) field.get(body); + if (reader != null) { + assertEquals(Integer.valueOf(1), counts.get(reader)); + assertSame(body, reader.getParent()); + assertFalse(otherCounts.containsKey(reader)); + } + } + Field self = WrapperBaseRoot.class.getDeclaredField("readSelfNode"); + self.setAccessible(true); + assertNotNull(self.get(body)); + if (spec.method && !convention.equals("METHOD")) { + Node staticBody = (Node) factory(spec, convention, true).createNode(); + assertSame(null, self.get(staticBody)); + } + if (spec.method) { + methods++; + } else { + descriptors++; + } + } + } + assertEquals(7, methods); + assertEquals(36, descriptors); + try { + factory(SPECS.get(7), "TRAVERSEPROC", false); + fail("TRAVERSEPROC must remain unsupported"); + } catch (InvocationTargetException expected) { + assertNotNull(expected.getCause()); + } + } + + private static void countChildren(Node node, Map counts) { + for (Node child : node.getChildren()) { + counts.merge(child, 1, Integer::sum); + countChildren(child, counts); + } + } + + @Test + public void framePoliciesAndClones() throws Exception { + for (Spec spec : SPECS) { + for (String convention : spec.enums.split(",")) { + BuiltinFunctionRootNode root = root(factory(spec, convention, false)); + assertPolicies(root, true, true); + assertWrapperRootIdentity(root, NAME); + DirectCallNode call = DirectCallNode.create(root.getCallTarget()); + new AdoptionRoot(call).getCallTarget(); + call.cloneCallTarget(); + RootCallTarget clonedTarget = (RootCallTarget) call.getCurrentCallTarget(); + assertNotSame("An optimized runtime with forced splitting is required", root.getCallTarget(), clonedTarget); + BuiltinFunctionRootNode clone = (BuiltinFunctionRootNode) clonedTarget.getRootNode(); + assertSame(root.getFactory(), clone.getFactory()); + assertSame(root.getSignature(), clone.getSignature()); + assertSame(root.getBuiltin(), clone.getBuiltin()); + assertPolicies(clone, true, true); + assertWrapperRootIdentity(clone, NAME); + } + } + Builtin builtin = OrdinaryNode.class.getAnnotation(Builtin.class); + assertPolicies(new BuiltinFunctionRootNode(PythonLanguage.get(null), builtin, new PrototypeNodeFactory<>(new OrdinaryNode()), true), false, false); + NodeFactory locals = GetLocalsNodeFactory.getInstance(); + Builtin localsBuiltin = locals.getNodeClass().getAnnotationsByType(Builtin.class)[0]; + assertPolicies(new BuiltinFunctionRootNode(PythonLanguage.get(null), localsBuiltin, GetLocalsNodeFactory.getInstance(), true), false, true); + } + + private static void assertPolicies(BuiltinFunctionRootNode root, boolean capture, boolean locals) { + assertEquals(capture, root.isCaptureFramesForTrace(false)); + assertEquals(capture, root.isCaptureFramesForTrace(true)); + root.updateCallerFlags(CallerFlags.NEEDS_MATERIALIZED_LOCALS); + assertEquals(locals, (root.getCallerFlags() & CallerFlags.NEEDS_MATERIALIZED_LOCALS) != 0); + assertTrue(root.isInternal()); + assertTrue(root.isPythonInternal()); + assertTrue(root.setsUpCalleeContext()); + } + + private static void assertWrapperRootIdentity(BuiltinFunctionRootNode root, TruffleString name) { + assertEquals(name.toJavaStringUncached(), root.getName()); + assertEquals(name.toJavaStringUncached(), root.getFunctionName()); + // The name and flags match the former wrapper root. The diagnostic string now uses + // BuiltinFunctionRootNode's format rather than the former "" format. + assertEquals("", root.toString()); + } + + @Test + public void cacheKeys() throws Exception { + PythonLanguage language = PythonLanguage.get(null); + for (Spec spec : SPECS) { + for (String convention : spec.enums.split(",")) { + BuiltinFunctionRootNode first = cached(spec, convention, NAME, false); + BuiltinFunctionRootNode second = cached(spec, convention, NAME, false); + assertSame(first, second); + assertSame(first, first.getCallTarget().getRootNode()); + assertSame(first.getCallTarget(), second.getCallTarget()); + BuiltinFunctionRootNode renamed = cached(spec, convention, tsLiteral("another_name"), false); + assertNotSame(first, renamed); + assertWrapperRootIdentity(renamed, tsLiteral("another_name")); + if (spec.method && !convention.equals("METHOD")) { + BuiltinFunctionRootNode staticRoot = cached(spec, convention, NAME, true); + assertNotSame(first, staticRoot); + assertWrapperRootIdentity(staticRoot, NAME); + assertTrue(staticRoot.isInternal()); + assertTrue(staticRoot.isPythonInternal()); + assertTrue(staticRoot.setsUpCalleeContext()); + } + } + } + BuiltinFunctionRootNode reference = cached(SPECS.get(0), "NOARGS", NAME, false); + assertSame(reference, language.createCachedExternalFunWrapperRootNode(l -> { + throw new AssertionError("cache miss"); + }, + reference.getFactory().getNodeClass(), MethodDescriptorWrapper.NOARGS, NAME, true, false)); + List variants = new ArrayList<>(); + variants.add(language.createCachedExternalFunWrapperRootNode(l -> freshRoot(), ExternalFunctionNodes.MethORoot.class, MethodDescriptorWrapper.NOARGS, NAME, true, false)); + variants.add(language.createCachedExternalFunWrapperRootNode(l -> freshRoot(), reference.getFactory().getNodeClass(), MethodDescriptorWrapper.O, NAME, true, false)); + variants.add(language.createCachedExternalFunWrapperRootNode(l -> freshRoot(), reference.getFactory().getNodeClass(), MethodDescriptorWrapper.NOARGS, NAME, false, false)); + variants.add(language.createCachedExternalFunWrapperRootNode(l -> freshRoot(), reference.getFactory().getNodeClass(), MethodDescriptorWrapper.NOARGS, NAME, true, true)); + for (BuiltinFunctionRootNode variant : variants) { + assertNotSame(reference, variant); + assertNotSame(reference.getCallTarget(), variant.getCallTarget()); + } + for (String kind : new String[]{"getter", "setter"}) { + BuiltinFunctionRootNode getset = (BuiltinFunctionRootNode) invoke(PythonCextTypeBuiltins.class, null, kind + "RootNode", + new Class[]{TruffleString.class, PythonLanguage.class}, NAME, language); + BuiltinFunctionRootNode descriptor = PExternalFunctionWrapper.getOrCreateRootNode(PExternalFunctionWrapper.valueOf(kind.toUpperCase(java.util.Locale.ROOT)), language, NAME); + assertSame(descriptor, getset); + assertSame(descriptor.getCallTarget(), getset.getCallTarget()); + } + } + + private static BuiltinFunctionRootNode freshRoot() { + return new BuiltinFunctionRootNode(PythonLanguage.get(null), OrdinaryNode.class.getAnnotation(Builtin.class), new PrototypeNodeFactory<>(new OrdinaryNode()), true); + } + + private static BuiltinFunctionRootNode cached(Spec spec, String convention, TruffleString name, boolean isStatic) throws Exception { + if (!spec.method) { + return PExternalFunctionWrapper.getOrCreateRootNode(PExternalFunctionWrapper.valueOf(convention), PythonLanguage.get(null), name); + } + return (BuiltinFunctionRootNode) invoke(MethodDescriptorWrapper.class, null, "getOrCreateRootNode", + new Class[]{PythonLanguage.class, MethodDescriptorWrapper.class, TruffleString.class, boolean.class}, + PythonLanguage.get(null), MethodDescriptorWrapper.valueOf(convention), name, isStatic); + } + + private static final class ZeroArgumentFactory implements NodeFactory { + private final Class nodeClass; + private final Supplier constructor; + + ZeroArgumentFactory(Class nodeClass, Supplier constructor) { + this.nodeClass = nodeClass; + this.constructor = constructor; + } + + @Override + public T createNode(Object... arguments) { + assertEquals(0, arguments.length); + return constructor.get(); + } + + @Override + public Class getNodeClass() { + return nodeClass; + } + + @Override + public List>> getNodeSignatures() { + return List.of(List.of()); + } + + @Override + public List> getExecutionSignature() { + return List.of(); + } + } + + private static final class FrameRecordingNode extends PythonBuiltinFrameArgsNode { + @Child private ReadIndexedArgumentNode reader = ReadIndexedArgumentNode.create(0); + + @Override + public Object execute(VirtualFrame frame) { + return reader.execute(frame); + } + } + + private static final class UnaryRecordingNode extends PythonUnaryBuiltinNode { + @Override + public Object execute(VirtualFrame frame, Object argument) { + return argument; + } + } + + private static final class RecordingFactory implements NodeFactory { + @Override + public RecordingNode createNode(Object... arguments) { + assertEquals(1, arguments.length); + return new RecordingNode((ReadArgumentNode[]) arguments[0]); + } + + @Override + public Class getNodeClass() { + return RecordingNode.class; + } + + @Override + public List>> getNodeSignatures() { + return List.of(List.of(ReadArgumentNode[].class)); + } + + @Override + public List> getExecutionSignature() { + return List.of(ReadArgumentNode.class); + } + } + + private static final class RecordingNode extends PythonBuiltinNode { + @Children private final ReadArgumentNode[] readers; + + RecordingNode(ReadArgumentNode[] readers) { + this.readers = readers; + } + + @Override + public Object execute(VirtualFrame frame) { + Object[] values = new Object[readers.length]; + for (int i = 0; i < readers.length; i++) { + values[i] = readers[i].execute(frame); + } + return values; + } + } + + private static final class AdoptionRoot extends RootNode { + @Child private Node child; + + AdoptionRoot(Node child) { + super(PythonLanguage.get(null)); + this.child = child; + } + + @Override + public Object execute(VirtualFrame frame) { + return child; + } + } + + @Builtin(name = "ordinary_wrapper_control", parameterNames = {"self"}, autoRegister = false) + private static final class OrdinaryNode extends PythonBuiltinNode { + @Override + public Object execute(VirtualFrame frame) { + return 42; + } + } +} diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_descr.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_descr.py index 1f560b88d3..ceed5dd8d1 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_descr.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_descr.py @@ -1,4 +1,4 @@ -# Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # The Universal Permissive License (UPL), Version 1.0 @@ -38,7 +38,7 @@ # SOFTWARE. import unittest -from . import CPyExtType, CPyExtTestCase, CPyExtFunction, unhandled_error_compare +from . import CPyExtType, CPyExtTestCase, CPyExtFunction, unhandled_error_compare, assert_raises def _reference_classmethod(args): @@ -48,6 +48,88 @@ def _reference_classmethod(args): class TestDescrObject(unittest.TestCase): + def test_shared_wrapper_pointer_and_closure_isolation(self): + def make_type(name, marker): + return CPyExtType( + name, + r''' + static PyObject* shared(PyObject* self, PyObject* arg) { + if (arg == Py_False) { + PyErr_SetString(PyExc_ValueError, "pointer MARKER"); + return NULL; + } + return Py_BuildValue("iO", MARKER, arg); + } + static PyObject* get_value(PyObject* self, void* closure) { + assert((intptr_t)closure == MARKER); + PyObject* value = ((TYPEObject*)self)->value; + if (!value) { + PyErr_SetString(PyExc_AttributeError, "closure MARKER absent"); + return NULL; + } + if (value == Py_False) { + PyErr_SetString(PyExc_ValueError, "closure MARKER get"); + return NULL; + } + return Py_NewRef(value); + } + static int set_value(PyObject* self, PyObject* value, void* closure) { + assert((intptr_t)closure == MARKER); + if (value == Py_False) { + PyErr_SetString(PyExc_ValueError, "closure MARKER set"); + return -1; + } + /* A deleted property is NULL; a stored None remains a real object. */ + Py_XINCREF(value); + Py_XSETREF(((TYPEObject*)self)->value, value); + return 0; + } + static PyObject* shared_noargs(PyObject* self, PyObject* ignored) { + assert(ignored == NULL); + return PyLong_FromLong(MARKER); + } + '''.replace('TYPE', name).replace('MARKER', str(marker)), + includes='#undef NDEBUG\n#include \n#include ', + cmembers='PyObject* value;', + tp_methods=''' + {"shared", shared, METH_O, ""}, + {"shared_noargs", shared_noargs, METH_NOARGS, ""} + ''', + tp_getset='{"value", get_value, set_value, "", (void*)%d}' % marker, + ) + + left_type = make_type('SharedWrapperLeft', 11) + right_type = make_type('SharedWrapperRight', 29) + left, right = left_type(), right_type() + left_value, right_value = object(), object() + for _ in range(5): + for obj, typ, marker, value in ((left, left_type, 11, left_value), (right, right_type, 29, right_value)): + received_marker, received_value = obj.shared(value) + assert received_marker == marker + assert received_value is value + assert obj.shared_noargs() == marker + with self.assertRaisesRegex(ValueError, '^pointer %d$' % marker): + obj.shared(False) + assert obj.shared(value)[1] is value + obj.value = value + assert obj.value is value + assert typ.value.__get__(obj, typ) is value + with self.assertRaisesRegex(ValueError, '^closure %d set$' % marker): + obj.value = False + assert obj.value is value + obj.value = None + assert obj.value is None + del obj.value + with self.assertRaisesRegex(AttributeError, '^closure %d absent$' % marker): + _ = obj.value + obj.value = value + assert obj.value is value + assert left.value is left_value + assert right.value is right_value + assert_raises(TypeError, left_type.shared, right, left_value) + assert_raises(TypeError, left_type.value.__get__, right, right_type) + assert_raises(TypeError, left_type.value.__set__, right, left_value) + def test_new_classmethod(self): TestNewClassMethod = CPyExtType("TestNewClassMethod", diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tp_slots.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tp_slots.py index da45148006..fb2263deca 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tp_slots.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tp_slots.py @@ -1670,6 +1670,29 @@ def __call__(self, *args, **kwargs): assert obj.__call__({'b': 2}, a=1) == {'a': 1, 'b': 2} +def test_tp_call_result_identity(): + NativeSlotProxy = CPyExtType( + name='TpCallIdentityProxy', + cmembers='PyObject* delegate;', + code=r''' + typedef TpCallIdentityProxyObject ProxyObject; + ''' + native_slot_proxy_template + r''' + static PyObject* proxy_tp_call(PyObject* self, PyObject* args, PyObject* kwargs) { + return PyObject_Call(get_delegate(self), args, kwargs); + } + ''', + tp_new='proxy_tp_new', + tp_call='proxy_tp_call', + ) + result = object() + obj = NativeSlotProxy(lambda *args, **kwargs: result) + for _ in range(4): + assert obj() is result + assert obj.__call__() is result + assert obj(None, user=None) is result + assert obj.__call__(None, user=None) is result + + def test_native_vectorcall(): NativeVectorcall = CPyExtType( name='NativeVectorcall', diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java index f8cb761b45..90cdb6b534 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java @@ -1220,7 +1220,7 @@ public T createCachedRootNode(Function r } public T createCachedExternalFunWrapperRootNode(Function rootNodeFunction, - Class klass, Enum signature, TruffleString name, + Class klass, Enum signature, TruffleString name, boolean doArgumentAndResultConversion, boolean isStatic) { return createCachedRootNodeUnsafe(rootNodeFunction, true, klass, signature, name, doArgumentAndResultConversion, isStatic); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTypeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTypeBuiltins.java index 6f289c9201..33c6a74bf5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTypeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTypeBuiltins.java @@ -75,12 +75,9 @@ import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.EnsurePythonObjectNode; import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.ToNativeBorrowedNode; import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes; -import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.GetterRoot; import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.PExternalFunctionWrapper; -import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.SetterRoot; import com.oracle.graal.python.builtins.objects.cext.capi.MethodDescriptorWrapper; import com.oracle.graal.python.builtins.objects.cext.capi.PyMethodFlags; -import com.oracle.graal.python.builtins.objects.cext.capi.WrapperDescriptorRootNodesGen; import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.NativeToPythonClassNode; import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.NativeToPythonNode; import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.PythonToNativeNewRefNode; @@ -111,6 +108,7 @@ import com.oracle.graal.python.nodes.HiddenAttr; import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.PRootNode; +import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode; import com.oracle.graal.python.nodes.SpecialAttributeNames; import com.oracle.graal.python.nodes.attributes.WriteAttributeToPythonObjectNode; import com.oracle.graal.python.nodes.object.GetDictIfExistsNode; @@ -121,7 +119,6 @@ import com.oracle.graal.python.runtime.nativeaccess.NativeFunctionPointer; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.graal.python.runtime.sequence.storage.MroSequenceStorage; -import com.oracle.graal.python.util.Function; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; @@ -438,15 +435,13 @@ public static GetSetDescriptor createGetSet(TruffleString name, Object cls, long } @TruffleBoundary - private static PRootNode getterRootNode(TruffleString name, PythonLanguage lang) { - Function rootNodeFunction = l -> WrapperDescriptorRootNodesGen.create(l, name, PExternalFunctionWrapper.GETTER); - return lang.createCachedExternalFunWrapperRootNode(rootNodeFunction, GetterRoot.class, PExternalFunctionWrapper.GETTER, name, true, false); + private static BuiltinFunctionRootNode getterRootNode(TruffleString name, PythonLanguage lang) { + return PExternalFunctionWrapper.getOrCreateRootNode(PExternalFunctionWrapper.GETTER, lang, name); } @TruffleBoundary - private static PRootNode setterRootNode(TruffleString name, PythonLanguage lang) { - Function rootNodeFunction = l -> WrapperDescriptorRootNodesGen.create(l, name, PExternalFunctionWrapper.SETTER); - return lang.createCachedExternalFunWrapperRootNode(rootNodeFunction, SetterRoot.class, PExternalFunctionWrapper.SETTER, name, true, false); + private static BuiltinFunctionRootNode setterRootNode(TruffleString name, PythonLanguage lang) { + return PExternalFunctionWrapper.getOrCreateRootNode(PExternalFunctionWrapper.SETTER, lang, name); } @CApiBuiltin(ret = ArgDescriptor.Void, args = {PyTypeObject, PyBufferProcs}, call = Ignored, retConversion = void.class, argConversions = {NativeToPythonClassNode.class, long.class}) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java index 27b0b29ec5..4b2d9a4d85 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java @@ -97,6 +97,7 @@ import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.annotations.ArgDescriptor; +import com.oracle.graal.python.annotations.Builtin; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.lib.PyLongAsIntNodeGen; @@ -156,9 +157,10 @@ import com.oracle.graal.python.nodes.argument.ReadVarArgsNode; import com.oracle.graal.python.nodes.argument.ReadVarKeywordsNode; import com.oracle.graal.python.nodes.classes.IsSubtypeNode; +import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode; +import com.oracle.graal.python.nodes.function.PythonBuiltinFrameArgsNode; import com.oracle.graal.python.nodes.object.IsForeignObjectNode; import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; -import com.oracle.graal.python.runtime.ExecutionContext.CalleeContext; import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonContext.GetThreadStateNode; @@ -402,8 +404,13 @@ public enum PExternalFunctionWrapper implements NativeCExtSymbol { } @TruffleBoundary - static PRootNode getOrCreateRootNode(PExternalFunctionWrapper sig, PythonLanguage language, TruffleString name) { - return language.createCachedExternalFunWrapperRootNode(l -> WrapperDescriptorRootNodesGen.create(l, name, sig), sig.rootNodeClass, sig, name, true, false); + public static BuiltinFunctionRootNode getOrCreateRootNode(PExternalFunctionWrapper sig, PythonLanguage language, TruffleString name) { + return language.createCachedExternalFunWrapperRootNode(l -> createFactory(sig, name).createRoot(l), sig.rootNodeClass, sig, name, true, false); + } + + static ExternalFunctionWrapperFactory createFactory(PExternalFunctionWrapper sig, TruffleString name) { + return new ExternalFunctionWrapperFactory(WrapperDescriptorRootNodesGen.getNodeClass(sig), WrapperDescriptorRootNodesGen.getSignature(sig), name, + () -> WrapperDescriptorRootNodesGen.create(name, sig)); } /** @@ -496,16 +503,15 @@ private static Signature createSignatureWithClosure(boolean takesVarKeywordArgs, return new Signature(-1, takesVarKeywordArgs, varArgIndex, parameters, KEYWORDS_HIDDEN_CALLABLE_AND_CLOSURE, checkEnclosingType, T_EMPTY_STRING, hidden); } - public abstract static class WrapperBaseRoot extends PRootNode { - @Child private CalleeContext calleeContext; + @Builtin(needsFrame = true, declaresExplicitSelf = true, autoRegister = false) + public abstract static class WrapperBaseRoot extends PythonBuiltinFrameArgsNode { @Child private ReadIndexedArgumentNode readSelfNode; @Child private ReadIndexedArgumentNode readCallableNode; @Child private EnsurePythonObjectNode ensurePythonObjectNode; protected final TruffleString name; - WrapperBaseRoot(PythonLanguage language, TruffleString name, boolean isStatic) { - super(language); + WrapperBaseRoot(TruffleString name, boolean isStatic) { CompilerAsserts.neverPartOfCompilation(); this.name = name; if (!isStatic) { @@ -513,29 +519,23 @@ public abstract static class WrapperBaseRoot extends PRootNode { } } + public abstract Signature getSignature(); + protected abstract Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, NativeFunctionPointer boundFunction); @Override public final Object execute(VirtualFrame frame) { - if (calleeContext == null) { + if (readCallableNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - assert readCallableNode == null; - assert calleeContext == null; // we insert a hidden argument at the end of the positional arguments int hiddenArg = getSignature().getParameterIds().length; readCallableNode = insert(ReadIndexedArgumentNode.create(hiddenArg)); - calleeContext = insert(CalleeContext.create()); } - calleeContext.enter(frame, this); - try { - Object callable = readCallableNode.execute(frame); - if (!(callable instanceof NativeFunctionPointer boundFunction)) { - throw CompilerDirectives.shouldNotReachHere(); - } - return readArgumentsAndInvokeExternalFunction(frame, boundFunction); - } finally { - calleeContext.exit(frame, this); + Object callable = readCallableNode.execute(frame); + if (!(callable instanceof NativeFunctionPointer boundFunction)) { + throw CompilerDirectives.shouldNotReachHere(); } + return readArgumentsAndInvokeExternalFunction(frame, boundFunction); } final Object ensurePythonObject(Object object) { @@ -546,31 +546,6 @@ final Object ensurePythonObject(Object object) { return ensurePythonObjectNode.execute(PythonContext.get(this), object, false); } - @Override - public String getName() { - return name.toJavaStringUncached(); - } - - @Override - public String toString() { - return ""; - } - - @Override - public boolean isPythonInternal() { - return true; - } - - @Override - public boolean isInternal() { - return true; - } - - @Override - public boolean setsUpCalleeContext() { - return true; - } - protected final Object readSelf(VirtualFrame frame) { if (readSelfNode != null) { return readSelfNode.execute(frame); @@ -590,8 +565,8 @@ public abstract static class MethodDescriptorRoot extends WrapperBaseRoot { final CApiTiming timing; - MethodDescriptorRoot(PythonLanguage language, TruffleString name, boolean isStatic, MethodDescriptorWrapper wrapper) { - super(language, name, isStatic); + MethodDescriptorRoot(TruffleString name, boolean isStatic, MethodDescriptorWrapper wrapper) { + super(name, isStatic); assert wrapper.returnValue == PyObject; this.timing = CApiTiming.create(true, name); } @@ -623,8 +598,8 @@ public abstract static class WrapperDescriptorRoot extends WrapperBaseRoot { private final BranchProfile exceptionProfile = BranchProfile.create(); - WrapperDescriptorRoot(PythonLanguage language, TruffleString name, @SuppressWarnings("unused") PExternalFunctionWrapper wrapper) { - super(language, name, false); + WrapperDescriptorRoot(TruffleString name, @SuppressWarnings("unused") PExternalFunctionWrapper wrapper) { + super(name, false); } protected final void transformExceptionFromNative() { @@ -653,9 +628,10 @@ public abstract static class ObjectWrapperDescriptorRoot extends WrapperDescript @Child private NativeToPythonReturnNode nativeToPythonReturnNode; - ObjectWrapperDescriptorRoot(PythonLanguage language, TruffleString name, PExternalFunctionWrapper wrapper) { - super(language, name, wrapper); - assert wrapper.signature.returnValue == PyObject; + ObjectWrapperDescriptorRoot(TruffleString name, PExternalFunctionWrapper wrapper) { + super(name, wrapper); + // SETATTR retains its existing integer-return invocation through this shared body. + assert wrapper.signature.returnValue == PyObject || wrapper == SETATTR; } final NativeToPythonReturnNode ensureNativeToPythonReturnNode() { @@ -676,7 +652,7 @@ final Object returnNativeObjectToPython(long lresult) { } public static final class MethVarargsRoot extends PyCFunctionRootNode { - private static final Signature SIGNATURE = createSignature(false, 1, tsArray("self"), true, true); + static final Signature SIGNATURE = createSignature(false, 1, tsArray("self"), true, true); @Child private ReadVarArgsNode readVarargsNode; @Child private PythonToNativeNode argsTupleToNativeNode; @Child private CreateNativeArgsTupleNode createNativeArgsTupleNode; @@ -684,8 +660,8 @@ public static final class MethVarargsRoot extends PyCFunctionRootNode { @CompilationFinal private boolean seenNativeArgsTupleStorage; - public MethVarargsRoot(PythonLanguage language, TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { - super(language, name, isStatic, provider); + public MethVarargsRoot(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { + super(name, isStatic, provider); this.readVarargsNode = ReadVarArgsNode.create(SIGNATURE.varArgsPArgumentsIndex()); this.argsTupleToNativeNode = PythonToNativeNode.create(); this.createNativeArgsTupleNode = CreateNativeArgsTupleNodeGen.create(); @@ -743,13 +719,12 @@ public Signature getSignature() { } static final class MethKeywordsRoot extends MethodDescriptorRoot { - private static final Signature SIGNATURE = createSignature(true, 1, tsArray("self"), true, true); + static final Signature SIGNATURE = createSignature(true, 1, tsArray("self"), true, true); @Child private ReadVarArgsNode readVarargsNode; @Child private ReadVarKeywordsNode readKwargsNode; @Child private CreateNativeArgsTupleNode createNativeArgsTupleNode; @Child private ReleaseNativeArgsTupleNode freeNode; - @Child private CalleeContext calleeContext; @Child private BoundaryCallData boundaryCallData; @Child private PythonToNativeNode selfToNativeNode; @@ -758,13 +733,13 @@ static final class MethKeywordsRoot extends MethodDescriptorRoot { @CompilationFinal private boolean seenNativeArgsTupleStorage; - public MethKeywordsRoot(PythonLanguage language, TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { - super(language, name, isStatic, provider); + public MethKeywordsRoot(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { + super(name, isStatic, provider); } @Override protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, NativeFunctionPointer boundFunction) { - if (calleeContext == null || boundaryCallData == null || selfToNativeNode == null || argsToNativeNode == null) { + if (kwargsToNativeNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); createNodes(); } @@ -811,7 +786,6 @@ private void createNodes() { readKwargsNode = insert(ReadVarKeywordsNode.create(SIGNATURE.varKeywordsPArgumentsIndex())); createNativeArgsTupleNode = insert(CreateNativeArgsTupleNodeGen.create()); freeNode = insert(ReleaseNativeArgsTupleNodeGen.create()); - calleeContext = insert(CalleeContext.create()); boundaryCallData = insert(BoundaryCallData.createFor(this)); selfToNativeNode = insert(PythonToNativeNode.create()); argsToNativeNode = insert(PythonToNativeNode.create()); @@ -827,10 +801,10 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_unaryfunc}. */ @CApiWrapperDescriptor(value = UNARYFUNC) abstract static class MethUnaryFunc extends ObjectWrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self"), true, false); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self"), true, false); - protected MethUnaryFunc(PythonLanguage lang, TruffleString name, PExternalFunctionWrapper provider) { - super(lang, name, provider); + protected MethUnaryFunc(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); } @InvokeExternalFunction(value = ExternalFunctionSignature.UNARYFUNC, argConversions = {PythonToNativeNode.class}) @@ -849,7 +823,7 @@ public Signature getSignature() { } public abstract static class MethNewOrCallRoot extends ObjectWrapperDescriptorRoot { - private static final Signature SIGNATURE = MethKeywordsRoot.SIGNATURE; + static final Signature SIGNATURE = MethKeywordsRoot.SIGNATURE; @Child ReadVarArgsNode readVarargsNode; @Child ReadVarKeywordsNode readKwargsNode; @Child PythonToNativeNode argsTupleToNativeNode; @@ -858,8 +832,8 @@ public abstract static class MethNewOrCallRoot extends ObjectWrapperDescriptorRo @CompilationFinal boolean seenNativeArgsTupleStorage; - public MethNewOrCallRoot(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + public MethNewOrCallRoot(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readVarargsNode = ReadVarArgsNode.create(SIGNATURE.varArgsPArgumentsIndex()); this.readKwargsNode = ReadVarKeywordsNode.create(SIGNATURE.varKeywordsPArgumentsIndex()); this.argsTupleToNativeNode = PythonToNativeNode.create(); @@ -926,8 +900,8 @@ abstract static class MethNewRoot extends MethNewOrCallRoot { @Child private ValidateNewArgumentNode validateNewArgumentNode; private final BranchProfile noArgumentsProfile = BranchProfile.create(); - public MethNewRoot(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + public MethNewRoot(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); } @InvokeExternalFunction(value = ExternalFunctionSignature.NEWFUNC, argConversions = {PythonToNativeNode.class, long.class, PythonToNativeNode.class}) @@ -965,7 +939,7 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati } PKeyword[] kwargs = readKwargsNode.execute(frame); - PythonLanguage language = getLanguage(PythonLanguage.class); + PythonLanguage language = PythonLanguage.get(this); Object kwargsDict = kwargs.length > 0 ? PFactory.createDict(language, kwargs) : PNone.NO_VALUE; try { @@ -984,8 +958,8 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati @CApiWrapperDescriptor(value = CALL) abstract static class MethCallRoot extends MethNewOrCallRoot { - public MethCallRoot(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + public MethCallRoot(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); } @InvokeExternalFunction(value = ExternalFunctionSignature.TERNARYFUNC, argConversions = {PythonToNativeNode.class, long.class, PythonToNativeNode.class}) @@ -1027,7 +1001,7 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati @CApiWrapperDescriptor(value = INIT) abstract static class MethInitRoot extends WrapperDescriptorRoot { - private static final Signature SIGNATURE = MethKeywordsRoot.SIGNATURE; + static final Signature SIGNATURE = MethKeywordsRoot.SIGNATURE; @Child private ReadVarArgsNode readVarargsNode; @Child private ReadVarKeywordsNode readKwargsNode; @@ -1037,8 +1011,8 @@ abstract static class MethInitRoot extends WrapperDescriptorRoot { @CompilationFinal boolean seenNativeArgsTupleStorage; - public MethInitRoot(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + public MethInitRoot(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readVarargsNode = ReadVarArgsNode.create(SIGNATURE.varArgsPArgumentsIndex()); this.readKwargsNode = ReadVarKeywordsNode.create(SIGNATURE.varKeywordsPArgumentsIndex()); this.argsTupleToNativeNode = PythonToNativeNode.create(); @@ -1094,10 +1068,10 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_inquirypred}. */ @CApiWrapperDescriptor(value = INQUIRYPRED) public abstract static class MethInquiryRoot extends WrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self"), true, false); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self"), true, false); - public MethInquiryRoot(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + public MethInquiryRoot(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); } @InvokeExternalFunction(value = ExternalFunctionSignature.INQUIRY, retConversion = int.class, argConversions = {PythonToNativeNode.class}) @@ -1120,10 +1094,10 @@ public Signature getSignature() { } static final class MethNoargsRoot extends PyCFunctionRootNode { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self"), true, true); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self"), true, true); - public MethNoargsRoot(PythonLanguage language, TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { - super(language, name, isStatic, provider); + public MethNoargsRoot(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { + super(name, isStatic, provider); } @Override @@ -1140,18 +1114,17 @@ public Signature getSignature() { } abstract static class PyCFunctionRootNode extends MethodDescriptorRoot { - @Child private CalleeContext calleeContext; @Child private BoundaryCallData boundaryCallData; @Child private PythonToNativeNode selfToNativeNode; - public PyCFunctionRootNode(PythonLanguage language, TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { - super(language, name, isStatic, provider); + public PyCFunctionRootNode(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { + super(name, isStatic, provider); } final Object invokeExternalFunction(VirtualFrame frame, NativeFunctionPointer boundFunction, Object self, long arg) { assert EnsurePythonObjectNode.doesNotNeedPromotion(self); - if (calleeContext == null || boundaryCallData == null || selfToNativeNode == null) { + if (selfToNativeNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); createNodes(); } @@ -1167,19 +1140,18 @@ final Object invokeExternalFunction(VirtualFrame frame, NativeFunctionPointer bo private void createNodes() { CompilerAsserts.neverPartOfCompilation(); - calleeContext = insert(CalleeContext.create()); boundaryCallData = insert(BoundaryCallData.createFor(this)); selfToNativeNode = insert(PythonToNativeNode.create()); } } public static final class MethORoot extends PyCFunctionRootNode { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "arg"), true, true); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "arg"), true, true); @Child private ReadIndexedArgumentNode readArgNode; @Child private PythonToNativeNode argToNativeNode; - public MethORoot(PythonLanguage language, TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { - super(language, name, isStatic, provider); + public MethORoot(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { + super(name, isStatic, provider); this.readArgNode = ReadIndexedArgumentNode.create(1); this.argToNativeNode = PythonToNativeNode.create(); } @@ -1206,7 +1178,7 @@ static final class MethFastcallWithKeywordsRoot extends MethodDescriptorRoot { * METH_KEYWORDS and METH_FASTCALL|METH_KEYWORDS have the same Python-level signature but * invoke a different C function signature. */ - private static final Signature SIGNATURE = MethKeywordsRoot.SIGNATURE; + static final Signature SIGNATURE = MethKeywordsRoot.SIGNATURE; @Child private ReadVarArgsNode readVarargsNode; @Child private ReadVarKeywordsNode readKwargsNode; @@ -1217,13 +1189,13 @@ static final class MethFastcallWithKeywordsRoot extends MethodDescriptorRoot { @Child private CreateNativeKwNamesTupleNode createNativeKwNamesTupleNode; @Child private ReleaseNativeArgsTupleNode releaseNativeKwNamesTupleNode; - public MethFastcallWithKeywordsRoot(PythonLanguage language, TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { - super(language, name, isStatic, provider); + public MethFastcallWithKeywordsRoot(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { + super(name, isStatic, provider); } @Override protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, NativeFunctionPointer boundFunction) { - if (readVarargsNode == null) { + if (releaseNativeKwNamesTupleNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); assert readKwargsNode == null; assert boundaryCallData == null; @@ -1291,7 +1263,7 @@ public Signature getSignature() { } static final class MethMethodRoot extends MethodDescriptorRoot { - private static final Signature SIGNATURE = createSignature(true, 1, tsArray("self", "cls"), true, true); + static final Signature SIGNATURE = createSignature(true, 1, tsArray("self", "cls"), true, true); @Child private ReadIndexedArgumentNode readClsNode; @Child private ReadVarArgsNode readVarargsNode; @@ -1301,13 +1273,13 @@ static final class MethMethodRoot extends MethodDescriptorRoot { @Child private PythonToNativeNode argToNativeNode; @Child private PythonToNativeNode kwNamesToNativeNode; - public MethMethodRoot(PythonLanguage language, TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { - super(language, name, isStatic, provider); + public MethMethodRoot(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { + super(name, isStatic, provider); } @Override protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, NativeFunctionPointer boundFunction) { - if (readClsNode == null) { + if (kwNamesToNativeNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); assert readVarargsNode == null; assert readKwargsNode == null; @@ -1374,20 +1346,20 @@ static final class MethFastcallRoot extends MethodDescriptorRoot { * METH_VARARGS and METH_FASTCALL have the same Python-level signature but invoke a * different C function signature. */ - private static final Signature SIGNATURE = MethVarargsRoot.SIGNATURE; + static final Signature SIGNATURE = MethVarargsRoot.SIGNATURE; @Child private ReadVarArgsNode readVarargsNode; @Child private BoundaryCallData boundaryCallData; @Child private PythonToNativeNode argToNativeNode; - public MethFastcallRoot(PythonLanguage language, TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { - super(language, name, isStatic, provider); + public MethFastcallRoot(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { + super(name, isStatic, provider); } @Override protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, NativeFunctionPointer boundFunction) { - if (readVarargsNode == null) { + if (argToNativeNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); assert boundaryCallData == null; assert argToNativeNode == null; @@ -1462,12 +1434,12 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_indexargfunc}. */ @CApiWrapperDescriptor(value = INDEXARGFUNC) public abstract static class IndexArgFuncRootNode extends ObjectWrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "i"), true, false); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "i"), true, false); @Child private ReadIndexedArgumentNode readINode; @Child private PyNumberAsSizeNode asSizeNode; - IndexArgFuncRootNode(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + IndexArgFuncRootNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readINode = ReadIndexedArgumentNode.create(1); this.asSizeNode = PyNumberAsSizeNode.create(); } @@ -1494,12 +1466,12 @@ public Signature getSignature() { @CApiWrapperDescriptor(value = GETATTR) public abstract static class GetAttrFuncRootNode extends ObjectWrapperDescriptorRoot { private static final TruffleLogger LOGGER = CApiContext.getLogger(GetAttrFuncRootNode.class); - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "key"), true, false); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "key"), true, false); @Child private ReadIndexedArgumentNode readArgNode; @Child private AsCharPointerNode asCharPointerNode; - GetAttrFuncRootNode(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + GetAttrFuncRootNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readArgNode = ReadIndexedArgumentNode.create(1); this.asCharPointerNode = AsCharPointerNodeGen.create(); } @@ -1533,13 +1505,13 @@ public Signature getSignature() { @CApiWrapperDescriptor(value = SETATTR) public abstract static class SetAttrFuncRootNode extends ObjectWrapperDescriptorRoot { private static final TruffleLogger LOGGER = CApiContext.getLogger(SetAttrFuncRootNode.class); - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "key", "value"), true, false); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "key", "value"), true, false); @Child private ReadIndexedArgumentNode readArg1Node; @Child private ReadIndexedArgumentNode readArg2Node; @Child private AsCharPointerNode asCharPointerNode; - SetAttrFuncRootNode(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + SetAttrFuncRootNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readArg1Node = ReadIndexedArgumentNode.create(1); this.readArg2Node = ReadIndexedArgumentNode.create(2); this.asCharPointerNode = AsCharPointerNodeGen.create(); @@ -1573,12 +1545,12 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_setattr} */ @CApiWrapperDescriptor(value = SETATTRO) public abstract static class SetAttrOFuncRootNode extends WrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "name", "value"), true, false); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "name", "value"), true, false); @Child private ReadIndexedArgumentNode readNameNode; @Child private ReadIndexedArgumentNode readValueNode; - SetAttrOFuncRootNode(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + SetAttrOFuncRootNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readNameNode = ReadIndexedArgumentNode.create(1); this.readValueNode = ReadIndexedArgumentNode.create(2); } @@ -1613,12 +1585,12 @@ public Signature getSignature() { */ @CApiWrapperDescriptor(value = RICHCMP) public abstract static class RichCmpFuncRootNode extends ObjectWrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "other", "op"), true, false); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "other", "op"), true, false); @Child private ReadIndexedArgumentNode readOtherNode; @Child private ReadIndexedArgumentNode readOpNode; - RichCmpFuncRootNode(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + RichCmpFuncRootNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readOtherNode = ReadIndexedArgumentNode.create(1); this.readOpNode = ReadIndexedArgumentNode.create(2); } @@ -1644,12 +1616,12 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_sq_item}. */ @CApiWrapperDescriptor(value = SQ_ITEM) public abstract static class GetItemRootNode extends ObjectWrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "i"), true, false); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "i"), true, false); @Child private ReadIndexedArgumentNode readArg1Node; @Child private GetIndexNode getIndexNode; - GetItemRootNode(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + GetItemRootNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readArg1Node = ReadIndexedArgumentNode.create(1); this.getIndexNode = GetIndexNode.create(); } @@ -1674,13 +1646,13 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_sq_setitem}. */ @CApiWrapperDescriptor(value = SQ_SETITEM) public abstract static class SetItemRootNode extends WrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "i", "value"), true, false); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "i", "value"), true, false); @Child private ReadIndexedArgumentNode readArg1Node; @Child private ReadIndexedArgumentNode readArg2Node; @Child private GetIndexNode getIndexNode; - SetItemRootNode(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + SetItemRootNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readArg1Node = ReadIndexedArgumentNode.create(1); this.readArg2Node = ReadIndexedArgumentNode.create(2); this.getIndexNode = GetIndexNode.create(); @@ -1710,12 +1682,12 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_sq_delitem}. */ @CApiWrapperDescriptor(value = SQ_DELITEM) public abstract static class SqDelItemRootNode extends WrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "key"), true, false); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "key"), true, false); @Child private ReadIndexedArgumentNode readKeyNode; @Child private GetIndexNode getIndexNode; - SqDelItemRootNode(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + SqDelItemRootNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readKeyNode = ReadIndexedArgumentNode.create(1); this.getIndexNode = GetIndexNode.create(); } @@ -1745,12 +1717,12 @@ public Signature getSignature() { */ @CApiWrapperDescriptor(value = DESCR_GET) public abstract static class DescrGetRootNode extends ObjectWrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "obj", "type"), true, false); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "obj", "type"), true, false); @Child private ReadIndexedArgumentNode readObj; @Child private ReadIndexedArgumentNode readType; - public DescrGetRootNode(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + public DescrGetRootNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readObj = ReadIndexedArgumentNode.create(1); this.readType = ReadIndexedArgumentNode.create(2); } @@ -1778,11 +1750,11 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_descr_delete} */ @CApiWrapperDescriptor(value = DESCR_DELETE) public abstract static class DescrDeleteRootNode extends WrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "obj"), true, false); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "obj"), true, false); @Child private ReadIndexedArgumentNode readObj; - public DescrDeleteRootNode(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + public DescrDeleteRootNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readObj = ReadIndexedArgumentNode.create(1); } @@ -1809,11 +1781,11 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_delattr}. */ @CApiWrapperDescriptor(value = DELATTRO) public abstract static class DelAttrRootNode extends WrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "obj"), true, false); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "obj"), true, false); @Child private ReadIndexedArgumentNode readObj; - public DelAttrRootNode(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + public DelAttrRootNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readObj = ReadIndexedArgumentNode.create(1); } @@ -1841,11 +1813,11 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_delitem}. */ @CApiWrapperDescriptor(value = MP_DELITEM) public abstract static class MpDelItemRootNode extends WrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "key"), true, false); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "key"), true, false); @Child private ReadIndexedArgumentNode readKeyNode; - MpDelItemRootNode(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + MpDelItemRootNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readKeyNode = ReadIndexedArgumentNode.create(1); } @@ -1875,15 +1847,15 @@ public Signature getSignature() { */ @CApiWrapperDescriptor(value = {TERNARYFUNC, TERNARYFUNC_R}) public abstract static class MethTernaryFuncRoot extends ObjectWrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "other", "third"), false, false); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "other", "third"), false, false); @Child private ReadIndexedArgumentNode readArg1Node; @Child private ReadIndexedArgumentNode readArg2Node; private final boolean reverse; - MethTernaryFuncRoot(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + MethTernaryFuncRoot(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readArg1Node = ReadIndexedArgumentNode.create(1); this.readArg2Node = ReadIndexedArgumentNode.create(2); this.reverse = provider == TERNARYFUNC_R; @@ -1925,14 +1897,14 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_richcmpfunc} */ @CApiWrapperDescriptor(value = {GT, GE, LE, LT, EQ, NE}) public abstract static class MethRichcmpOpRootNode extends ObjectWrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "other"), true, false); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "other"), true, false); @Child private ReadIndexedArgumentNode readArgNode; private final int op; - MethRichcmpOpRootNode(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + MethRichcmpOpRootNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readArgNode = ReadIndexedArgumentNode.create(1); this.op = getCompareOpCode(provider); } @@ -1969,11 +1941,12 @@ private static int getCompareOpCode(PExternalFunctionWrapper sig) { /** Implements semantics of {@code typeobject.c: wrap_next}. */ @CApiWrapperDescriptor(value = ITERNEXT) public abstract static class IterNextFuncRootNode extends ObjectWrapperDescriptorRoot { + static final Signature SIGNATURE = MethNoargsRoot.SIGNATURE; @Child private CheckIterNextResultNode checkIterNextResultNode; - IterNextFuncRootNode(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + IterNextFuncRootNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.checkIterNextResultNode = CheckIterNextResultNodeGen.create(); } @@ -2000,12 +1973,12 @@ public Signature getSignature() { */ @CApiWrapperDescriptor(value = GETTER) public abstract static class GetterRoot extends ObjectWrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignatureWithClosure(false, -1, tsArray("self"), true, false); + static final Signature SIGNATURE = createSignatureWithClosure(false, -1, tsArray("self"), true, false); @Child private ReadIndexedArgumentNode readClosureNode; - public GetterRoot(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + public GetterRoot(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); } @InvokeExternalFunction(value = ExternalFunctionSignature.GETTER, argConversions = {PythonToNativeNode.class, long.class}) @@ -2039,13 +2012,13 @@ public Signature getSignature() { */ @CApiWrapperDescriptor(value = SETTER) public abstract static class SetterRoot extends WrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignatureWithClosure(false, -1, tsArray("self", "value"), true, false); + static final Signature SIGNATURE = createSignatureWithClosure(false, -1, tsArray("self", "value"), true, false); @Child private ReadIndexedArgumentNode readClosureNode; @Child private ReadIndexedArgumentNode readArgNode; - public SetterRoot(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + public SetterRoot(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); } @InvokeExternalFunction(value = ExternalFunctionSignature.SETTER, retConversion = int.class, argConversions = {PythonToNativeNode.class, PythonToNativeNode.class, long.class}) @@ -2083,10 +2056,10 @@ private ReadIndexedArgumentNode ensureReadArgNode() { /** Implements semantics of {@code typeobject.c: wrap_lenfunc} */ @CApiWrapperDescriptor(value = {LENFUNC, HASHFUNC}) public abstract static class MethLenfuncRoot extends WrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self"), true, false); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self"), true, false); - public MethLenfuncRoot(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + public MethLenfuncRoot(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); } @InvokeExternalFunction(value = ExternalFunctionSignature.LENFUNC, argConversions = {PythonToNativeNode.class}) @@ -2111,12 +2084,12 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_objobjproc}. */ @CApiWrapperDescriptor(value = OBJOBJPROC) public abstract static class MethObjObjProcRoot extends WrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "value"), true, false); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "value"), true, false); @Child private ReadIndexedArgumentNode readValueNode; - MethObjObjProcRoot(PythonLanguage lang, TruffleString name, PExternalFunctionWrapper provider) { - super(lang, name, provider); + MethObjObjProcRoot(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readValueNode = ReadIndexedArgumentNode.create(1); } @@ -2144,13 +2117,13 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_objobjargproc}. */ @CApiWrapperDescriptor(value = OBJOBJARGPROC) public abstract static class MethObjObjArgProcRoot extends WrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "key", "value"), true, false); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "key", "value"), true, false); @Child private ReadIndexedArgumentNode readKeyNode; @Child private ReadIndexedArgumentNode readValueNode; - MethObjObjArgProcRoot(PythonLanguage lang, TruffleString name, PExternalFunctionWrapper provider) { - super(lang, name, provider); + MethObjObjArgProcRoot(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readKeyNode = ReadIndexedArgumentNode.create(1); this.readValueNode = ReadIndexedArgumentNode.create(2); } @@ -2183,14 +2156,14 @@ public Signature getSignature() { */ @CApiWrapperDescriptor(value = {BINARYFUNC, BINARYFUNC_L, BINARYFUNC_R}) public abstract static class MethBinaryRoot extends ObjectWrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "other"), true, false); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "other"), true, false); @Child private ReadIndexedArgumentNode readOtherNode; private final boolean reverse; - MethBinaryRoot(PythonLanguage lang, TruffleString name, PExternalFunctionWrapper provider) { - super(lang, name, provider); + MethBinaryRoot(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readOtherNode = ReadIndexedArgumentNode.create(1); this.reverse = provider == BINARYFUNC_R; } @@ -2225,12 +2198,12 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_descr_set} */ @CApiWrapperDescriptor(value = DESCR_SET) public abstract static class MethDescrSetRoot extends WrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "instance", "value"), true, false); + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "instance", "value"), true, false); @Child private ReadIndexedArgumentNode readInstanceNode; @Child private ReadIndexedArgumentNode readValueNode; - MethDescrSetRoot(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + MethDescrSetRoot(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readInstanceNode = ReadIndexedArgumentNode.create(1); this.readValueNode = ReadIndexedArgumentNode.create(2); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionWrapperFactory.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionWrapperFactory.java new file mode 100644 index 0000000000..49d1afeb7d --- /dev/null +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionWrapperFactory.java @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2026, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.graal.python.builtins.objects.cext.capi; + +import java.lang.annotation.Annotation; +import java.util.List; +import java.util.function.Supplier; + +import com.oracle.graal.python.PythonLanguage; +import com.oracle.graal.python.annotations.Builtin; +import com.oracle.graal.python.annotations.PythonOS; +import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.WrapperBaseRoot; +import com.oracle.graal.python.builtins.objects.function.Signature; +import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode; +import com.oracle.truffle.api.dsl.NodeFactory; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.strings.TruffleString; + +/** Creates configured native wrapper bodies that read their own frame arguments. */ +final class ExternalFunctionWrapperFactory implements NodeFactory { + private final Class nodeClass; + private final Signature signature; + private final Builtin builtin; + private final Supplier constructor; + + ExternalFunctionWrapperFactory(Class nodeClass, Signature signature, TruffleString name, + Supplier constructor) { + this.nodeClass = nodeClass; + this.signature = signature; + this.builtin = new NamedBuiltin(name.toJavaStringUncached(), WrapperBaseRoot.class.getAnnotation(Builtin.class)); + this.constructor = constructor; + } + + BuiltinFunctionRootNode createRoot(PythonLanguage language) { + return new BuiltinFunctionRootNode(language, signature, builtin, this, true, null); + } + + @Override + public WrapperBaseRoot createNode(Object... arguments) { + assert arguments.length == 0; + WrapperBaseRoot body = constructor.get(); + assert nodeClass.isInstance(body); + return body; + } + + @Override + @SuppressWarnings("unchecked") + public Class getNodeClass() { + return (Class) nodeClass; + } + + @Override + public List>> getNodeSignatures() { + return List.of(List.of()); + } + + @Override + public List> getExecutionSignature() { + return List.of(); + } + + /** Give the common wrapper metadata the enclosing root's runtime name. */ + private record NamedBuiltin(String name, Builtin annotation) implements Builtin { + NamedBuiltin { + assert annotation != null; + } + + @Override + public Class annotationType() { + return Builtin.class; + } + + @Override + public String doc() { + return annotation.doc(); + } + + @Override + public PythonOS os() { + return annotation.os(); + } + + @Override + public int minNumOfPositionalArgs() { + return annotation.minNumOfPositionalArgs(); + } + + @Override + public int maxNumOfPositionalArgs() { + return annotation.maxNumOfPositionalArgs(); + } + + @Override + public int numOfPositionalOnlyArgs() { + return annotation.numOfPositionalOnlyArgs(); + } + + @Override + public boolean isGetter() { + return annotation.isGetter(); + } + + @Override + public boolean isSetter() { + return annotation.isSetter(); + } + + @Override + public boolean allowsDelete() { + return annotation.allowsDelete(); + } + + @Override + public boolean takesVarArgs() { + return annotation.takesVarArgs(); + } + + @Override + public boolean takesVarKeywordArgs() { + return annotation.takesVarKeywordArgs(); + } + + @Override + public String[] parameterNames() { + return annotation.parameterNames(); + } + + @Override + public String[] keywordOnlyNames() { + return annotation.keywordOnlyNames(); + } + + @Override + public boolean isClassmethod() { + return annotation.isClassmethod(); + } + + @Override + public boolean isStaticmethod() { + return annotation.isStaticmethod(); + } + + @Override + public boolean needsFrame() { + return annotation.needsFrame(); + } + + @Override + public int callerFlags() { + return annotation.callerFlags(); + } + + @Override + public boolean declaresExplicitSelf() { + return annotation.declaresExplicitSelf(); + } + + @Override + public String raiseErrorName() { + return annotation.raiseErrorName(); + } + + @Override + public boolean forceSplitDirectCalls() { + return annotation.forceSplitDirectCalls(); + } + + @Override + public boolean autoRegister() { + return annotation.autoRegister(); + } + } +} diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/MethodDescriptorWrapper.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/MethodDescriptorWrapper.java index c17079c510..5d3df75248 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/MethodDescriptorWrapper.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/MethodDescriptorWrapper.java @@ -60,8 +60,8 @@ import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction; import com.oracle.graal.python.builtins.objects.function.PKeyword; import com.oracle.graal.python.nodes.PRootNode; +import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode; import com.oracle.graal.python.runtime.object.PFactory; -import com.oracle.graal.python.util.Function; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -116,39 +116,28 @@ public ArgDescriptor[] getArguments() { private static final TruffleLogger LOGGER = CApiContext.getLogger(MethodDescriptorWrapper.class); @TruffleBoundary - static PRootNode getOrCreateRootNode(PythonLanguage language, MethodDescriptorWrapper sig, TruffleString name, boolean isStatic) { - Class nodeKlass; - Function rootNodeFunction = switch (sig) { - case KEYWORDS -> { - nodeKlass = MethKeywordsRoot.class; - yield l -> new MethKeywordsRoot(l, name, isStatic, sig); - } - case VARARGS -> { - nodeKlass = MethVarargsRoot.class; - yield (l -> new MethVarargsRoot(l, name, isStatic, sig)); - } - case NOARGS -> { - nodeKlass = MethNoargsRoot.class; - yield (l -> new MethNoargsRoot(l, name, isStatic, sig)); - } - case O -> { - nodeKlass = MethORoot.class; - yield (l -> new MethORoot(l, name, isStatic, sig)); - } - case FASTCALL -> { - nodeKlass = MethFastcallRoot.class; - yield (l -> new MethFastcallRoot(l, name, isStatic, sig)); - } - case FASTCALL_WITH_KEYWORDS -> { - nodeKlass = MethFastcallWithKeywordsRoot.class; - yield (l -> new MethFastcallWithKeywordsRoot(l, name, isStatic, sig)); - } - case METHOD -> { - nodeKlass = MethMethodRoot.class; - yield (l -> new MethMethodRoot(l, name, isStatic, sig)); - } + static BuiltinFunctionRootNode getOrCreateRootNode(PythonLanguage language, MethodDescriptorWrapper sig, TruffleString name, boolean isStatic) { + ExternalFunctionWrapperFactory factory = createFactory(sig, name, isStatic); + return language.createCachedExternalFunWrapperRootNode(factory::createRoot, factory.getNodeClass(), sig, name, true, isStatic); + } + + static ExternalFunctionWrapperFactory createFactory(MethodDescriptorWrapper sig, TruffleString name, boolean isStatic) { + return switch (sig) { + case KEYWORDS -> new ExternalFunctionWrapperFactory(MethKeywordsRoot.class, MethKeywordsRoot.SIGNATURE, name, + () -> new MethKeywordsRoot(name, isStatic, sig)); + case VARARGS -> new ExternalFunctionWrapperFactory(MethVarargsRoot.class, MethVarargsRoot.SIGNATURE, name, + () -> new MethVarargsRoot(name, isStatic, sig)); + case NOARGS -> new ExternalFunctionWrapperFactory(MethNoargsRoot.class, MethNoargsRoot.SIGNATURE, name, + () -> new MethNoargsRoot(name, isStatic, sig)); + case O -> new ExternalFunctionWrapperFactory(MethORoot.class, MethORoot.SIGNATURE, name, + () -> new MethORoot(name, isStatic, sig)); + case FASTCALL -> new ExternalFunctionWrapperFactory(MethFastcallRoot.class, MethFastcallRoot.SIGNATURE, name, + () -> new MethFastcallRoot(name, isStatic, sig)); + case FASTCALL_WITH_KEYWORDS -> new ExternalFunctionWrapperFactory(MethFastcallWithKeywordsRoot.class, MethFastcallWithKeywordsRoot.SIGNATURE, name, + () -> new MethFastcallWithKeywordsRoot(name, isStatic, sig)); + case METHOD -> new ExternalFunctionWrapperFactory(MethMethodRoot.class, MethMethodRoot.SIGNATURE, name, + () -> new MethMethodRoot(name, isStatic, sig)); }; - return language.createCachedExternalFunWrapperRootNode(rootNodeFunction, nodeKlass, sig, name, true, isStatic); } /** diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PRootNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PRootNode.java index 423ac950ed..13f910083c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PRootNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PRootNode.java @@ -41,6 +41,7 @@ package com.oracle.graal.python.nodes; import com.oracle.graal.python.PythonLanguage; +import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.WrapperBaseRoot; import com.oracle.graal.python.builtins.objects.frame.FrameBuiltinsFactory; import com.oracle.graal.python.builtins.objects.function.Signature; import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode; @@ -109,7 +110,8 @@ public int getCallerFlags() { } public void updateCallerFlags(int flags) { - if (this instanceof BuiltinFunctionRootNode functionRootNode && !(functionRootNode.getFactory() instanceof FrameBuiltinsFactory.GetLocalsNodeFactory)) { + if (this instanceof BuiltinFunctionRootNode functionRootNode && !(functionRootNode.getFactory() instanceof FrameBuiltinsFactory.GetLocalsNodeFactory) && + !WrapperBaseRoot.class.isAssignableFrom(functionRootNode.getFactory().getNodeClass())) { /* * Our callee-side tracking of the caller flags is too broad and causes "poisoning" of common builtins that * are calling many other things, like object.__getattribute__ or type.__new__. For materialized frames this diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/BuiltinFunctionRootNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/BuiltinFunctionRootNode.java index 3a0549f5c7..b2a78cd987 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/BuiltinFunctionRootNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/BuiltinFunctionRootNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. * Copyright (c) 2013, Regents of the University of California * * All rights reserved. @@ -36,6 +36,7 @@ import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.annotations.Builtin; import com.oracle.graal.python.builtins.PythonBuiltinClassType; +import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.WrapperBaseRoot; import com.oracle.graal.python.builtins.objects.function.Signature; import com.oracle.graal.python.nodes.PRootNode; import com.oracle.graal.python.nodes.argument.ReadArgumentNode; @@ -46,13 +47,11 @@ import com.oracle.graal.python.nodes.function.builtins.BuiltinCallNode.BuiltinAnyCallNode; import com.oracle.graal.python.nodes.function.builtins.BuiltinCallNode.BuiltinBinaryCallNode; import com.oracle.graal.python.nodes.function.builtins.BuiltinCallNode.BuiltinQuaternaryCallNode; -import com.oracle.graal.python.nodes.function.builtins.BuiltinCallNode.BuiltinSenaryCallNode; import com.oracle.graal.python.nodes.function.builtins.BuiltinCallNode.BuiltinTernaryCallNode; import com.oracle.graal.python.nodes.function.builtins.BuiltinCallNode.BuiltinUnaryCallNode; import com.oracle.graal.python.nodes.function.builtins.BuiltinCallNode.BuiltinVarArgsCallNode; import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode; import com.oracle.graal.python.nodes.function.builtins.PythonQuaternaryBuiltinNode; -import com.oracle.graal.python.nodes.function.builtins.PythonSenaryBuiltinNode; import com.oracle.graal.python.nodes.function.builtins.PythonTernaryBuiltinNode; import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; import com.oracle.graal.python.nodes.function.builtins.PythonVarargsBuiltinNode; @@ -62,6 +61,7 @@ import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff; import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.RootNode; @@ -90,6 +90,7 @@ public final class BuiltinFunctionRootNode extends PRootNode { @Child private BuiltinCallNode body; @Child private CalleeContext calleeContext = CalleeContext.create(); private final PythonBuiltinClassType wrapsSlotForClass; + private final boolean isCaptureForTraces; public BuiltinFunctionRootNode(PythonLanguage language, Signature signature, Builtin builtin, NodeFactory factory, boolean declaresExplicitSelf, PythonBuiltinClassType wrapsSlotForClass) { @@ -101,6 +102,7 @@ public BuiltinFunctionRootNode(PythonLanguage language, Signature signature, Bui this.factory = factory; this.declaresExplicitSelf = declaresExplicitSelf; this.wrapsSlotForClass = wrapsSlotForClass; + this.isCaptureForTraces = WrapperBaseRoot.class.isAssignableFrom(factory.getNodeClass()); if (builtin.callerFlags() != 0) { updateCallerFlags(builtin.callerFlags()); } @@ -275,7 +277,7 @@ public boolean isCloningAllowed() { @Override public boolean isCaptureFramesForTrace(boolean compiledFrame) { - return false; + return isCaptureForTraces; } @Override @@ -292,45 +294,7 @@ public boolean setsUpCalleeContext() { public Object execute(VirtualFrame frame) { if (body == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - BuiltinCallNode newBody; - ReadArgumentNode[] argumentsList = createArgumentsList(builtin, declaresExplicitSelf); - if (PythonBuiltinNode.class.isAssignableFrom(factory.getNodeClass())) { - newBody = new BuiltinAnyCallNode((PythonBuiltinNode) factory.createNode((Object) argumentsList)); - } else { - PythonBuiltinBaseNode node = factory.createNode(); - if (node instanceof PythonUnaryBuiltinNode) { - assert argumentsList.length == 1 : "mismatch in number of arguments for " + node.getClass().getName() + ", expected 1, got " + argumentsList.length; - newBody = new BuiltinUnaryCallNode((PythonUnaryBuiltinNode) node, argumentsList[0]); - } else if (node instanceof PythonBinaryBuiltinNode) { - assert argumentsList.length == 2 : "mismatch in number of arguments for " + node.getClass().getName() + ", expected 2, got " + argumentsList.length; - newBody = new BuiltinBinaryCallNode((PythonBinaryBuiltinNode) node, argumentsList[0], argumentsList[1]); - } else if (node instanceof PythonTernaryBuiltinNode) { - assert argumentsList.length == 3 : "mismatch in number of arguments for " + node.getClass().getName() + ", expected 3, got " + argumentsList.length; - newBody = new BuiltinTernaryCallNode((PythonTernaryBuiltinNode) node, argumentsList[0], argumentsList[1], argumentsList[2]); - } else if (node instanceof PythonQuaternaryBuiltinNode) { - assert argumentsList.length == 4 : "mismatch in number of arguments for " + node.getClass().getName() + ", expected 4, got " + argumentsList.length; - newBody = new BuiltinQuaternaryCallNode((PythonQuaternaryBuiltinNode) node, argumentsList[0], argumentsList[1], argumentsList[2], argumentsList[3]); - } else if (node instanceof PythonSenaryBuiltinNode) { - assert argumentsList.length == 6 : "mismatch in number of arguments for " + node.getClass().getName() + ", expected 6, got " + argumentsList.length; - newBody = new BuiltinSenaryCallNode((PythonSenaryBuiltinNode) node, argumentsList[0], argumentsList[1], argumentsList[2], argumentsList[3], argumentsList[4], argumentsList[5]); - } else if (node instanceof PythonVarargsBuiltinNode) { - assert argumentsList.length == 3 : "mismatch in number of arguments for " + node.getClass().getName() + ", expected 3, got " + argumentsList.length; - assert argumentsList[0] != null && argumentsList[1] != null && argumentsList[2] != null; - newBody = new BuiltinVarArgsCallNode((PythonVarargsBuiltinNode) node, argumentsList[0], argumentsList[1], argumentsList[2]); - } else { - throw new RuntimeException("unexpected builtin node type: " + node.getClass()); - } - } - - if (wrapsSlotForClass != null) { - if (declaresExplicitSelf) { - body = insert(new WrapperDescrCall(newBody, name, wrapsSlotForClass)); - } else { - body = insert(new WrapTpNew(newBody, wrapsSlotForClass)); - } - } else { - body = insert(newBody); - } + body = insert(initializeBody()); } calleeContext.enter(frame, this); try { @@ -340,6 +304,48 @@ public Object execute(VirtualFrame frame) { } } + @InliningCutoff + private BuiltinCallNode initializeBody() { + BuiltinCallNode newBody; + if (PythonBuiltinNode.class.isAssignableFrom(factory.getNodeClass())) { + ReadArgumentNode[] argumentsList = createArgumentsList(builtin, declaresExplicitSelf); + newBody = new BuiltinAnyCallNode((PythonBuiltinNode) factory.createNode((Object) argumentsList)); + } else if (PythonBuiltinFrameArgsNode.class.isAssignableFrom(factory.getNodeClass())) { + newBody = new BuiltinAnyCallNode((PythonBuiltinFrameArgsNode) factory.createNode()); + } else { + ReadArgumentNode[] argumentsList = createArgumentsList(builtin, declaresExplicitSelf); + PythonBuiltinBaseNode node = factory.createNode(); + if (node instanceof PythonUnaryBuiltinNode) { + assert argumentsList.length == 1 : "mismatch in number of arguments for " + node.getClass().getName() + ", expected 1, got " + argumentsList.length; + newBody = new BuiltinUnaryCallNode((PythonUnaryBuiltinNode) node, argumentsList[0]); + } else if (node instanceof PythonBinaryBuiltinNode) { + assert argumentsList.length == 2 : "mismatch in number of arguments for " + node.getClass().getName() + ", expected 2, got " + argumentsList.length; + newBody = new BuiltinBinaryCallNode((PythonBinaryBuiltinNode) node, argumentsList[0], argumentsList[1]); + } else if (node instanceof PythonTernaryBuiltinNode) { + assert argumentsList.length == 3 : "mismatch in number of arguments for " + node.getClass().getName() + ", expected 3, got " + argumentsList.length; + newBody = new BuiltinTernaryCallNode((PythonTernaryBuiltinNode) node, argumentsList[0], argumentsList[1], argumentsList[2]); + } else if (node instanceof PythonQuaternaryBuiltinNode) { + assert argumentsList.length == 4 : "mismatch in number of arguments for " + node.getClass().getName() + ", expected 4, got " + argumentsList.length; + newBody = new BuiltinQuaternaryCallNode((PythonQuaternaryBuiltinNode) node, argumentsList[0], argumentsList[1], argumentsList[2], argumentsList[3]); + } else if (node instanceof PythonVarargsBuiltinNode) { + assert argumentsList.length == 3 : "mismatch in number of arguments for " + node.getClass().getName() + ", expected 3, got " + argumentsList.length; + assert argumentsList[0] != null && argumentsList[1] != null && argumentsList[2] != null; + newBody = new BuiltinVarArgsCallNode((PythonVarargsBuiltinNode) node, argumentsList[0], argumentsList[1], argumentsList[2]); + } else { + throw new RuntimeException("unexpected builtin node type: " + node.getClass()); + } + } + + if (wrapsSlotForClass != null) { + if (declaresExplicitSelf) { + return new WrapperDescrCall(newBody, name, wrapsSlotForClass); + } else { + return new WrapTpNew(newBody, wrapsSlotForClass); + } + } + return newBody; + } + public String getFunctionName() { return name; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/builtins/PythonSenaryBuiltinNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/PythonBuiltinFrameArgsNode.java similarity index 82% rename from graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/builtins/PythonSenaryBuiltinNode.java rename to graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/PythonBuiltinFrameArgsNode.java index c16e09a3da..5161fb4d79 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/builtins/PythonSenaryBuiltinNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/PythonBuiltinFrameArgsNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -38,12 +38,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.oracle.graal.python.nodes.function.builtins; +package com.oracle.graal.python.nodes.function; -import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; import com.oracle.truffle.api.frame.VirtualFrame; -public abstract class PythonSenaryBuiltinNode extends PythonBuiltinBaseNode { - - public abstract Object execute(VirtualFrame frame, Object arg, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6); +/** + * Base class for builtins that extract their arguments from {@link VirtualFrame#getArguments()}. + */ +public abstract class PythonBuiltinFrameArgsNode extends PythonBuiltinBaseNode { + public abstract Object execute(VirtualFrame frame); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/PythonBuiltinNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/PythonBuiltinNode.java index 8f29e88918..11152fa2e5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/PythonBuiltinNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/PythonBuiltinNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. * Copyright (c) 2013, Regents of the University of California * * All rights reserved. @@ -30,6 +30,6 @@ import com.oracle.truffle.api.frame.VirtualFrame; @NodeChild(value = "arguments", type = ReadArgumentNode[].class) -public abstract class PythonBuiltinNode extends PythonBuiltinBaseNode { +public abstract class PythonBuiltinNode extends PythonBuiltinFrameArgsNode { public abstract Object execute(VirtualFrame frame); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/builtins/BuiltinCallNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/builtins/BuiltinCallNode.java index e1df46e4fd..b982032470 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/builtins/BuiltinCallNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/builtins/BuiltinCallNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -43,7 +43,7 @@ import com.oracle.graal.python.builtins.objects.function.PKeyword; import com.oracle.graal.python.nodes.argument.ReadArgumentNode; import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; -import com.oracle.graal.python.nodes.function.PythonBuiltinNode; +import com.oracle.graal.python.nodes.function.PythonBuiltinFrameArgsNode; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; @@ -53,9 +53,9 @@ public abstract class BuiltinCallNode extends Node { protected abstract PythonBuiltinBaseNode getNode(); public static final class BuiltinAnyCallNode extends BuiltinCallNode { - @Child private PythonBuiltinNode node; + @Child private PythonBuiltinFrameArgsNode node; - public BuiltinAnyCallNode(PythonBuiltinNode node) { + public BuiltinAnyCallNode(PythonBuiltinFrameArgsNode node) { this.node = node; } @@ -162,37 +162,6 @@ protected PythonBuiltinBaseNode getNode() { } } - public static final class BuiltinSenaryCallNode extends BuiltinCallNode { - @Child private PythonSenaryBuiltinNode node; - @Child private ReadArgumentNode arg1; - @Child private ReadArgumentNode arg2; - @Child private ReadArgumentNode arg3; - @Child private ReadArgumentNode arg4; - @Child private ReadArgumentNode arg5; - @Child private ReadArgumentNode arg6; - - public BuiltinSenaryCallNode(PythonSenaryBuiltinNode node, ReadArgumentNode arg1, ReadArgumentNode arg2, ReadArgumentNode arg3, ReadArgumentNode arg4, ReadArgumentNode arg5, - ReadArgumentNode arg6) { - this.node = node; - this.arg1 = arg1; - this.arg2 = arg2; - this.arg3 = arg3; - this.arg4 = arg4; - this.arg5 = arg5; - this.arg6 = arg6; - } - - @Override - public Object execute(VirtualFrame frame) { - return node.execute(frame, arg1.execute(frame), arg2.execute(frame), arg3.execute(frame), arg4.execute(frame), arg5.execute(frame), arg6.execute(frame)); - } - - @Override - protected PythonBuiltinBaseNode getNode() { - return node; - } - } - public static final class BuiltinVarArgsCallNode extends BuiltinCallNode { @Child private PythonVarargsBuiltinNode node; @Child private ReadArgumentNode arg1; From ed49504c180226f51d8ca94c73fab5a045d76043 Mon Sep 17 00:00:00 2001 From: stepan Date: Thu, 15 Oct 2026 12:37:49 +0200 Subject: [PATCH 2/6] Narrow PBuiltinFunction root node type --- .../modules/cext/PythonCextTypeBuiltins.java | 5 ++--- .../objects/cext/capi/ExternalFunctionNodes.java | 2 +- .../cext/capi/MethodDescriptorWrapper.java | 2 +- .../objects/function/PBuiltinFunction.java | 16 ++++++++-------- .../graal/python/nodes/call/CallDispatchers.java | 7 ++++--- .../nodes/call/special/CallBinaryMethodNode.java | 8 ++++---- .../call/special/CallQuaternaryMethodNode.java | 6 +++--- .../call/special/CallTernaryMethodNode.java | 8 ++++---- .../nodes/call/special/CallUnaryMethodNode.java | 8 ++++---- .../graal/python/runtime/object/PFactory.java | 11 ++++++----- 10 files changed, 37 insertions(+), 36 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTypeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTypeBuiltins.java index 33c6a74bf5..28471b9db8 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTypeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTypeBuiltins.java @@ -107,7 +107,6 @@ import com.oracle.graal.python.nodes.ErrorMessages; import com.oracle.graal.python.nodes.HiddenAttr; import com.oracle.graal.python.nodes.PRaiseNode; -import com.oracle.graal.python.nodes.PRootNode; import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode; import com.oracle.graal.python.nodes.SpecialAttributeNames; import com.oracle.graal.python.nodes.attributes.WriteAttributeToPythonObjectNode; @@ -416,7 +415,7 @@ public static GetSetDescriptor createGetSet(TruffleString name, Object cls, long PBuiltinFunction get = null; PythonLanguage language = PythonLanguage.get(null); if (getter != NULLPTR) { - PRootNode getterRoot = getterRootNode(name, language); + BuiltinFunctionRootNode getterRoot = getterRootNode(name, language); NativeFunctionPointer getterFun = CExtCommonNodes.bindFunctionPointer(getter, PExternalFunctionWrapper.GETTER); get = PFactory.createBuiltinFunction(language, name, cls, EMPTY_OBJECT_ARRAY, ExternalFunctionNodes.createKwDefaults(getterFun, closure), 0, getterRoot); } @@ -424,7 +423,7 @@ public static GetSetDescriptor createGetSet(TruffleString name, Object cls, long PBuiltinFunction set = null; boolean hasSetter = setter != NULLPTR; if (hasSetter) { - PRootNode setterRoot = setterRootNode(name, language); + BuiltinFunctionRootNode setterRoot = setterRootNode(name, language); NativeFunctionPointer setterFun = CExtCommonNodes.bindFunctionPointer(setter, PExternalFunctionWrapper.SETTER); set = PFactory.createBuiltinFunction(language, name, cls, EMPTY_OBJECT_ARRAY, ExternalFunctionNodes.createKwDefaults(setterFun, closure), 0, setterRoot); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java index 4b2d9a4d85..06aca87496 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java @@ -433,7 +433,7 @@ static ExternalFunctionWrapperFactory createFactory(PExternalFunctionWrapper sig @TruffleBoundary public static PythonBuiltinObject createDescrWrapperFunction(TruffleString name, NativeFunctionPointer callable, Object enclosingType, PExternalFunctionWrapper sig, PythonLanguage language) { LOGGER.finer(() -> PythonUtils.formatJString("ExternalFunctions.createDescrWrapperFunction(%s, %s)", name, callable)); - PRootNode rootNode = getOrCreateRootNode(sig, language, name); + BuiltinFunctionRootNode rootNode = getOrCreateRootNode(sig, language, name); // ensure that 'callable' is executable via InteropLibrary PKeyword[] kwDefaults = ExternalFunctionNodes.createKwDefaults(callable); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/MethodDescriptorWrapper.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/MethodDescriptorWrapper.java index 5d3df75248..fdfbd8df3b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/MethodDescriptorWrapper.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/MethodDescriptorWrapper.java @@ -160,7 +160,7 @@ public static PBuiltinFunction createWrapperFunction(PythonLanguage language, Tr return null; } - PRootNode rootNode = getOrCreateRootNode(language, methodDescriptorWrapper, name, PyMethodFlags.isMethStatic(flags)); + BuiltinFunctionRootNode rootNode = getOrCreateRootNode(language, methodDescriptorWrapper, name, PyMethodFlags.isMethStatic(flags)); PKeyword[] kwDefaults = ExternalFunctionNodes.createKwDefaults(CExtCommonNodes.bindFunctionPointer(callable, methodDescriptorWrapper)); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/function/PBuiltinFunction.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/function/PBuiltinFunction.java index a10346a095..be401cb93b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/function/PBuiltinFunction.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/function/PBuiltinFunction.java @@ -57,7 +57,6 @@ import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; -import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.strings.TruffleString; @@ -75,7 +74,7 @@ public final class PBuiltinFunction extends PythonBuiltinObject implements Bound private final PString name; private final TruffleString qualname; private final Object enclosingType; - private final RootNode functionRootNode; + private final BuiltinFunctionRootNode functionRootNode; private final Signature signature; private final int flags; private final TpSlot slot; @@ -85,7 +84,8 @@ public final class PBuiltinFunction extends PythonBuiltinObject implements Bound @CompilationFinal private RootCallTarget callTarget; - public PBuiltinFunction(PythonBuiltinClassType cls, Shape shape, TruffleString name, Object enclosingType, Object[] defaults, PKeyword[] kwDefaults, int flags, RootNode functionRootNode, + public PBuiltinFunction(PythonBuiltinClassType cls, Shape shape, TruffleString name, Object enclosingType, Object[] defaults, PKeyword[] kwDefaults, int flags, + BuiltinFunctionRootNode functionRootNode, Signature signature, TpSlot slot, PExternalFunctionWrapper slotWrapper) { super(cls, shape); @@ -127,7 +127,7 @@ public static Object[] generateDefaults(int numDefaults) { return defaults; } - public RootNode getFunctionRootNode() { + public BuiltinFunctionRootNode getFunctionRootNode() { return functionRootNode; } @@ -148,7 +148,7 @@ public PExternalFunctionWrapper getSlotWrapper() { } public NodeFactory getBuiltinNodeFactory() { - return functionRootNode instanceof BuiltinFunctionRootNode builtinRoot ? builtinRoot.getFactory() : null; + return functionRootNode.getFactory(); } public int getFlags() { @@ -192,7 +192,7 @@ public static int getFlags(Builtin builtin, Signature signature) { } public Class getNodeClass() { - return getBuiltinNodeFactory() != null ? getBuiltinNodeFactory().getNodeClass() : null; + return getBuiltinNodeFactory().getNodeClass(); } public Signature getSignature() { @@ -221,11 +221,11 @@ private RootCallTarget initializeCallTarget() { } public boolean declaresExplicitSelf() { - return !(functionRootNode instanceof BuiltinFunctionRootNode builtinRoot) || builtinRoot.declaresExplicitSelf(); + return functionRootNode.declaresExplicitSelf(); } public boolean forceSplitDirectCalls() { - return functionRootNode instanceof BuiltinFunctionRootNode builtinRoot && builtinRoot.getBuiltin().forceSplitDirectCalls(); + return functionRootNode.getBuiltin().forceSplitDirectCalls(); } public TruffleString getName() { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/CallDispatchers.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/CallDispatchers.java index 796808c5e5..e20f721586 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/CallDispatchers.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/CallDispatchers.java @@ -51,6 +51,7 @@ import com.oracle.graal.python.nodes.PNodeWithContext; import com.oracle.graal.python.nodes.argument.CreateArgumentsNode; import com.oracle.graal.python.nodes.call.CallDispatchersFactory.FunctionIndirectInvokeNodeGen; +import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode; import com.oracle.graal.python.runtime.ExecutionContext; import com.oracle.graal.python.runtime.ExecutionContext.IndirectCalleeContext; import com.oracle.graal.python.runtime.PythonContext; @@ -195,7 +196,7 @@ static Object callBuiltinFunctionCached(VirtualFrame frame, Node inliningTarget, @Specialization(guards = "callee.getFunctionRootNode() == rootNode", limit = "getCallSiteInlineCacheMaxDepth()", replaces = "callBuiltinFunctionCached") static Object callBuiltinFunctionCachedCt(VirtualFrame frame, Node inliningTarget, @SuppressWarnings("unused") PBuiltinFunction callee, Object[] arguments, - @SuppressWarnings("unused") @Cached(value = "callee.getFunctionRootNode()", adopt = false) RootNode rootNode, + @SuppressWarnings("unused") @Cached(value = "callee.getFunctionRootNode()", adopt = false) BuiltinFunctionRootNode rootNode, @Cached("createDirectCallNodeFor(callee)") DirectCallNode callNode, @Exclusive @Cached SimpleDirectInvokeNode invoke) { return invoke.execute(frame, inliningTarget, callNode, arguments); @@ -235,7 +236,7 @@ static Object callBuiltinFunctionCached(VirtualFrame frame, Node inliningTarget, @Specialization(guards = "callee.getFunctionRootNode() == rootNode", limit = "getCallSiteInlineCacheMaxDepth()", replaces = "callBuiltinFunctionCached") static Object callBuiltinFunctionCachedCt(VirtualFrame frame, Node inliningTarget, PBuiltinFunction callee, Object[] arguments, PKeyword[] keywords, - @SuppressWarnings("unused") @Cached(value = "callee.getFunctionRootNode()", adopt = false) RootNode rootNode, + @SuppressWarnings("unused") @Cached(value = "callee.getFunctionRootNode()", adopt = false) BuiltinFunctionRootNode rootNode, @Exclusive @Cached CreateArgumentsNode createArgs, @Cached("createDirectCallNodeFor(callee)") DirectCallNode callNode, @Exclusive @Cached SimpleDirectInvokeNode invoke) { @@ -293,7 +294,7 @@ static Object callBuiltinMethodCached(VirtualFrame frame, Node inliningTarget, @ @Specialization(guards = "function.getFunctionRootNode() == rootNode", limit = "getCallSiteInlineCacheMaxDepth()", replaces = "callBuiltinMethodCached") static Object callBuiltinMethodCachedCt(VirtualFrame frame, Node inliningTarget, PBuiltinMethod callee, Object[] arguments, PKeyword[] keywords, @Bind("callee.getBuiltinFunction()") PBuiltinFunction function, - @SuppressWarnings("unused") @Cached(value = "function.getFunctionRootNode()", adopt = false) RootNode rootNode, + @SuppressWarnings("unused") @Cached(value = "function.getFunctionRootNode()", adopt = false) BuiltinFunctionRootNode rootNode, @Exclusive @Cached CreateArgumentsNode createArgs, @Cached("createDirectCallNodeFor(function)") DirectCallNode callNode, @Exclusive @Cached SimpleDirectInvokeNode invoke) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/CallBinaryMethodNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/CallBinaryMethodNode.java index d103527582..8544ec8a0b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/CallBinaryMethodNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/CallBinaryMethodNode.java @@ -50,6 +50,7 @@ import com.oracle.graal.python.nodes.call.CallDispatchers; import com.oracle.graal.python.nodes.call.CallDispatchers.FunctionDirectInvokeNode; import com.oracle.graal.python.nodes.call.CallNode; +import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode; import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff; import com.oracle.truffle.api.bytecode.ForceQuickening; @@ -67,7 +68,6 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.nodes.UnexpectedResultException; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -104,7 +104,7 @@ public static Object callObjectSingleContext(VirtualFrame frame, @SuppressWarnin @Specialization(guards = {"func.getFunctionRootNode() == rootNode", "builtinNode != null"}, // limit = "getCallSiteInlineCacheMaxDepth()") public static Object callObject(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinFunction func, Object arg1, Object arg2, - @SuppressWarnings("unused") @Cached(value = "func.getFunctionRootNode()", adopt = false) RootNode rootNode, + @SuppressWarnings("unused") @Cached(value = "func.getFunctionRootNode()", adopt = false) BuiltinFunctionRootNode rootNode, @Cached("getBuiltin(frame, func, 2, $node)") PythonBuiltinBaseNode builtinNode) { return callBinaryBuiltin(frame, builtinNode, arg1, arg2); } @@ -119,7 +119,7 @@ public static Object callMethodSingleContext(VirtualFrame frame, @SuppressWarnin @Specialization(guards = {"builtinNode != null", "func.getBuiltinFunction().getFunctionRootNode() == rootNode", "!takesSelfArg"}, limit = "getCallSiteInlineCacheMaxDepth()") public static Object callMethod(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinMethod func, Object arg1, Object arg2, - @SuppressWarnings("unused") @Cached(value = "func.getBuiltinFunction().getFunctionRootNode()", adopt = false) RootNode rootNode, + @SuppressWarnings("unused") @Cached(value = "func.getBuiltinFunction().getFunctionRootNode()", adopt = false) BuiltinFunctionRootNode rootNode, @SuppressWarnings("unused") @Cached("takesSelfArg(func)") boolean takesSelfArg, @Cached("getBuiltin(frame, func.getBuiltinFunction(), 2, $node)") PythonBuiltinBaseNode builtinNode) { return callBinaryBuiltin(frame, builtinNode, arg1, arg2); @@ -135,7 +135,7 @@ public static Object callMethodSingleContextSelf(VirtualFrame frame, @SuppressWa @Specialization(guards = {"builtinNode != null", "func.getBuiltinFunction().getFunctionRootNode() == rootNode", "takesSelfArg"}, limit = "getCallSiteInlineCacheMaxDepth()") public static Object callMethodSelf(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinMethod func, Object arg1, Object arg2, - @SuppressWarnings("unused") @Cached(value = "func.getBuiltinFunction().getFunctionRootNode()", adopt = false) RootNode rootNode, + @SuppressWarnings("unused") @Cached(value = "func.getBuiltinFunction().getFunctionRootNode()", adopt = false) BuiltinFunctionRootNode rootNode, @SuppressWarnings("unused") @Cached("takesSelfArg(func)") boolean takesSelfArg, @Cached("getBuiltin(frame, func.getBuiltinFunction(), 3, $node)") PythonBuiltinBaseNode builtinNode) { return callTernaryBuiltin(frame, builtinNode, func.getSelf(), arg1, arg2); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/CallQuaternaryMethodNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/CallQuaternaryMethodNode.java index c4ba9e1305..2b7a801119 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/CallQuaternaryMethodNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/CallQuaternaryMethodNode.java @@ -50,6 +50,7 @@ import com.oracle.graal.python.nodes.call.CallDispatchers; import com.oracle.graal.python.nodes.call.CallDispatchers.FunctionDirectInvokeNode; import com.oracle.graal.python.nodes.call.CallNode; +import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode; import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff; import com.oracle.truffle.api.bytecode.ForceQuickening; @@ -66,7 +67,6 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @GenerateUncached @@ -97,7 +97,7 @@ public static Object callSingle(VirtualFrame frame, @SuppressWarnings("unused") @Specialization(guards = {"func.getFunctionRootNode() == rootNode", "builtinNode != null"}, // limit = "getCallSiteInlineCacheMaxDepth()") public static Object call(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinFunction func, Object arg1, Object arg2, Object arg3, Object arg4, - @SuppressWarnings("unused") @Cached(value = "func.getFunctionRootNode()", adopt = false) RootNode rootNode, + @SuppressWarnings("unused") @Cached(value = "func.getFunctionRootNode()", adopt = false) BuiltinFunctionRootNode rootNode, @Cached("getBuiltin(frame, func, 4, $node)") PythonBuiltinBaseNode builtinNode) { return callQuaternaryBuiltin(frame, builtinNode, arg1, arg2, arg3, arg4); } @@ -112,7 +112,7 @@ public static Object callMethodSingle(VirtualFrame frame, @SuppressWarnings("unu @Specialization(guards = {"builtinNode != null", "func.getBuiltinFunction().getFunctionRootNode() == rootNode", "!takesSelfArg"}, limit = "getCallSiteInlineCacheMaxDepth()") public static Object callMethod(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinMethod func, Object arg1, Object arg2, Object arg3, Object arg4, - @SuppressWarnings("unused") @Cached(value = "func.getBuiltinFunction().getFunctionRootNode()", adopt = false) RootNode rootNode, + @SuppressWarnings("unused") @Cached(value = "func.getBuiltinFunction().getFunctionRootNode()", adopt = false) BuiltinFunctionRootNode rootNode, @SuppressWarnings("unused") @Cached("takesSelfArg(func)") boolean takesSelfArg, @Cached("getBuiltin(frame, func.getBuiltinFunction(), 4, $node)") PythonBuiltinBaseNode builtinNode) { return callQuaternaryBuiltin(frame, builtinNode, arg1, arg2, arg3, arg4); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/CallTernaryMethodNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/CallTernaryMethodNode.java index 7c0158454d..c135a27e4f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/CallTernaryMethodNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/CallTernaryMethodNode.java @@ -50,6 +50,7 @@ import com.oracle.graal.python.nodes.call.CallDispatchers; import com.oracle.graal.python.nodes.call.CallDispatchers.FunctionDirectInvokeNode; import com.oracle.graal.python.nodes.call.CallNode; +import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode; import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff; import com.oracle.truffle.api.bytecode.ForceQuickening; @@ -67,7 +68,6 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @GenerateUncached @@ -97,7 +97,7 @@ public static Object doBuiltinFunctionCached(VirtualFrame frame, @SuppressWarnin @Specialization(guards = {"func.getFunctionRootNode() == rootNode", "builtinNode != null"}, // limit = "getCallSiteInlineCacheMaxDepth()") public static Object doBuiltinFunctionCtCached(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinFunction func, Object arg1, Object arg2, Object arg3, - @SuppressWarnings("unused") @Cached(value = "func.getFunctionRootNode()", adopt = false) RootNode rootNode, + @SuppressWarnings("unused") @Cached(value = "func.getFunctionRootNode()", adopt = false) BuiltinFunctionRootNode rootNode, @Cached("getBuiltin(frame, func, 3, $node)") PythonBuiltinBaseNode builtinNode) { return callTernaryBuiltin(frame, builtinNode, arg1, arg2, arg3); } @@ -112,7 +112,7 @@ public static Object doBuiltinMethodCached(VirtualFrame frame, @SuppressWarnings @Specialization(guards = {"builtinNode != null", "func.getBuiltinFunction().getFunctionRootNode() == rootNode", "!takesSelfArg"}, limit = "getCallSiteInlineCacheMaxDepth()") public static Object doBuiltinMethodCtCached(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinMethod func, Object arg1, Object arg2, Object arg3, - @SuppressWarnings("unused") @Cached(value = "func.getBuiltinFunction().getFunctionRootNode()", adopt = false) RootNode rootNode, + @SuppressWarnings("unused") @Cached(value = "func.getBuiltinFunction().getFunctionRootNode()", adopt = false) BuiltinFunctionRootNode rootNode, @SuppressWarnings("unused") @Cached("takesSelfArg(func)") boolean takesSelfArg, @Cached("getBuiltin(frame, func.getBuiltinFunction(), 3, $node)") PythonBuiltinBaseNode builtinNode) { return callTernaryBuiltin(frame, builtinNode, arg1, arg2, arg3); @@ -128,7 +128,7 @@ public static Object callSelfMethodSingleContext(VirtualFrame frame, @SuppressWa @Specialization(guards = {"builtinNode != null", "func.getBuiltinFunction().getFunctionRootNode() == rootNode", "takesSelfArg"}, limit = "getCallSiteInlineCacheMaxDepth()") public static Object callSelfMethod(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinMethod func, Object arg1, Object arg2, Object arg3, - @SuppressWarnings("unused") @Cached(value = "func.getBuiltinFunction().getFunctionRootNode()", adopt = false) RootNode rootNode, + @SuppressWarnings("unused") @Cached(value = "func.getBuiltinFunction().getFunctionRootNode()", adopt = false) BuiltinFunctionRootNode rootNode, @SuppressWarnings("unused") @Cached("takesSelfArg(func)") boolean takesSelfArg, @Cached("getBuiltin(frame, func.getBuiltinFunction(), 4, $node)") PythonBuiltinBaseNode builtinNode) { return callQuaternaryBuiltin(frame, builtinNode, func.getSelf(), arg1, arg2, arg3); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/CallUnaryMethodNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/CallUnaryMethodNode.java index 8055b08d48..ed6aa65333 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/CallUnaryMethodNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/CallUnaryMethodNode.java @@ -50,6 +50,7 @@ import com.oracle.graal.python.nodes.call.CallDispatchers; import com.oracle.graal.python.nodes.call.CallDispatchers.FunctionDirectInvokeNode; import com.oracle.graal.python.nodes.call.CallNode; +import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode; import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff; @@ -68,7 +69,6 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @GenerateUncached @@ -104,7 +104,7 @@ public static Object callObjectSingle(VirtualFrame frame, @SuppressWarnings("unu @Specialization(guards = {"func.getFunctionRootNode() == rootNode", "builtinNode != null"}, // limit = "getCallSiteInlineCacheMaxDepth()") public static Object callObject(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinFunction func, Object receiver, - @SuppressWarnings("unused") @Cached(value = "func.getFunctionRootNode()", adopt = false) RootNode rootNode, + @SuppressWarnings("unused") @Cached(value = "func.getFunctionRootNode()", adopt = false) BuiltinFunctionRootNode rootNode, @Cached("getBuiltin(frame, func, 1, $node)") PythonBuiltinBaseNode builtinNode) { return callUnaryBuiltin(frame, builtinNode, receiver); } @@ -119,7 +119,7 @@ public static Object callMethodSingleContext(VirtualFrame frame, @SuppressWarnin @Specialization(guards = {"builtinNode != null", "func.getBuiltinFunction().getFunctionRootNode() == rootNode", "!takesSelfArg"}, limit = "getCallSiteInlineCacheMaxDepth()") public static Object callMethod(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinMethod func, Object receiver, - @SuppressWarnings("unused") @Cached(value = "func.getBuiltinFunction().getFunctionRootNode()", adopt = false) RootNode rootNode, + @SuppressWarnings("unused") @Cached(value = "func.getBuiltinFunction().getFunctionRootNode()", adopt = false) BuiltinFunctionRootNode rootNode, @SuppressWarnings("unused") @Cached("takesSelfArg(func)") boolean takesSelfArg, @Cached("getBuiltin(frame, func.getBuiltinFunction(), 1, $node)") PythonBuiltinBaseNode builtinNode) { return callUnaryBuiltin(frame, builtinNode, receiver); @@ -135,7 +135,7 @@ public static Object callSelfMethodSingleContext(VirtualFrame frame, @SuppressWa @Specialization(guards = {"builtinNode != null", "func.getBuiltinFunction().getFunctionRootNode() == rootNode", "takesSelfArg"}, limit = "getCallSiteInlineCacheMaxDepth()") public static Object callSelfMethod(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinMethod func, Object arg, - @SuppressWarnings("unused") @Cached(value = "func.getBuiltinFunction().getFunctionRootNode()", adopt = false) RootNode rootNode, + @SuppressWarnings("unused") @Cached(value = "func.getBuiltinFunction().getFunctionRootNode()", adopt = false) BuiltinFunctionRootNode rootNode, @SuppressWarnings("unused") @Cached("takesSelfArg(func)") boolean takesSelfArg, @Cached("getBuiltin(frame, func.getBuiltinFunction(), 2, $node)") PythonBuiltinBaseNode builtinNode) { return callBinaryBuiltin(frame, builtinNode, func.getSelf(), arg); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PFactory.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PFactory.java index 7f6f1a653a..d1aa5753b7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PFactory.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PFactory.java @@ -242,6 +242,7 @@ import com.oracle.graal.python.nodes.PRootNode; import com.oracle.graal.python.nodes.bytecode_dsl.BytecodeDSLCodeUnit; import com.oracle.graal.python.nodes.bytecode_dsl.PBytecodeDSLRootNode; +import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode; import com.oracle.graal.python.runtime.NativeZlibSupport; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.sequence.storage.ByteSequenceStorage; @@ -566,29 +567,29 @@ public static PFunction createFunction(PythonLanguage language, TruffleString na return new PFunction(language, name, qualname, code, globals, defaultValues, kwDefaultValues, closure, codeStableAssumption); } - public static PBuiltinFunction createBuiltinFunction(PythonLanguage language, TruffleString name, Object type, int numDefaults, int flags, PRootNode rootNode) { + public static PBuiltinFunction createBuiltinFunction(PythonLanguage language, TruffleString name, Object type, int numDefaults, int flags, BuiltinFunctionRootNode rootNode) { return new PBuiltinFunction(PythonBuiltinClassType.PBuiltinFunction, PythonBuiltinClassType.PBuiltinFunction.getInstanceShape(language), name, type, PBuiltinFunction.generateDefaults(numDefaults), null, flags, rootNode, rootNode.getSignature(), null, null); } - public static PBuiltinFunction createBuiltinFunction(PythonLanguage language, TruffleString name, Object type, Object[] defaults, PKeyword[] kw, int flags, PRootNode rootNode) { + public static PBuiltinFunction createBuiltinFunction(PythonLanguage language, TruffleString name, Object type, Object[] defaults, PKeyword[] kw, int flags, BuiltinFunctionRootNode rootNode) { return new PBuiltinFunction(PythonBuiltinClassType.PBuiltinFunction, PythonBuiltinClassType.PBuiltinFunction.getInstanceShape(language), name, type, defaults, kw, flags, rootNode, rootNode.getSignature(), null, null); } - public static PBuiltinFunction createWrapperDescriptor(PythonLanguage language, TruffleString name, Object type, int numDefaults, int flags, PRootNode rootNode, TpSlot slot, + public static PBuiltinFunction createWrapperDescriptor(PythonLanguage language, TruffleString name, Object type, int numDefaults, int flags, BuiltinFunctionRootNode rootNode, TpSlot slot, PExternalFunctionWrapper slotWrapper) { return new PBuiltinFunction(PythonBuiltinClassType.WrapperDescriptor, PythonBuiltinClassType.WrapperDescriptor.getInstanceShape(language), name, type, PBuiltinFunction.generateDefaults(numDefaults), null, flags, rootNode, rootNode.getSignature(), slot, slotWrapper); } - public static PBuiltinFunction createWrapperDescriptor(PythonLanguage language, TruffleString name, Object type, Object[] defaults, PKeyword[] kw, int flags, PRootNode rootNode, + public static PBuiltinFunction createWrapperDescriptor(PythonLanguage language, TruffleString name, Object type, Object[] defaults, PKeyword[] kw, int flags, BuiltinFunctionRootNode rootNode, TpSlot slot, PExternalFunctionWrapper slotWrapper) { return new PBuiltinFunction(PythonBuiltinClassType.WrapperDescriptor, PythonBuiltinClassType.WrapperDescriptor.getInstanceShape(language), name, type, defaults, kw, flags, rootNode, rootNode.getSignature(), slot, slotWrapper); } - public static PBuiltinMethod createNewWrapper(PythonLanguage language, Object type, Object[] defaults, PKeyword[] kwdefaults, PRootNode rootNode, TpSlot slot) { + public static PBuiltinMethod createNewWrapper(PythonLanguage language, Object type, Object[] defaults, PKeyword[] kwdefaults, BuiltinFunctionRootNode rootNode, TpSlot slot) { PBuiltinFunction func = createWrapperDescriptor(language, T___NEW__, type, defaults, kwdefaults, PyMethodFlags.METH_VARARGS | PyMethodFlags.METH_KEYWORDS, rootNode, slot, PExternalFunctionWrapper.NEW); return createBuiltinMethod(language, type, func); From 4af12c2397759e68c5c50d9525ab51c252d365ec Mon Sep 17 00:00:00 2001 From: stepan Date: Thu, 15 Oct 2026 13:54:17 +0200 Subject: [PATCH 3/6] Narrow PCode root node type Keep PCode roots as PBytecodeDSLRootNode and simplify metadata extraction. For sources parsed with arguments, store the synthetic module root while retaining RootNodeWithArguments as the polyglot entry point. Re-executing captured module code now returns the synthetic function instead of raising an internal ClassCastException. Add coverage for module code re-execution and argument wrapper behavior. --- .../ParseWithArgumentsInstrumentTests.java | 48 +++++- .../builtins/objects/code/CodeBuiltins.java | 4 +- .../builtins/objects/code/CodeNodes.java | 11 +- .../python/builtins/objects/code/PCode.java | 150 +++++------------- .../bytecode_dsl/PBytecodeDSLRootNode.java | 2 +- .../python/nodes/call/CallDispatchers.java | 6 +- .../exception/TopLevelExceptionHandler.java | 5 +- .../graal/python/runtime/object/PFactory.java | 15 +- 8 files changed, 109 insertions(+), 132 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/runtime/ParseWithArgumentsInstrumentTests.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/runtime/ParseWithArgumentsInstrumentTests.java index 9646117a32..00039a5a95 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/runtime/ParseWithArgumentsInstrumentTests.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/runtime/ParseWithArgumentsInstrumentTests.java @@ -72,6 +72,52 @@ public void instrumentParseWithArgumentsDuringLanguageContextInitializationExecu } } + @SuppressWarnings("unchecked") + @Test + public void parsedModuleCodeReexecutionReturnsFunction() { + try (Engine engine = Engine.create(); + Context context = Context.newBuilder("python").engine(engine).allowExperimentalOptions(true).allowAllAccess(true).build()) { + context.eval("python", """ + import sys + parsed_module_codes = [] + def capture_module_code(frame, event, arg): + # Capture the synthetic module while it defines execute(x). By the + # time the supplied source runs inside execute, this frame has returned. + if event == 'call' and frame.f_code.co_filename == 'parse-with-arguments.py' and frame.f_code.co_name == '': + parsed_module_codes.append(frame.f_code) + sys.setprofile(capture_module_code) + """); + Function registrar = engine.getInstruments().get(TEST_INSTRUMENT_ID).lookup(Function.class); + context.enter(); + try { + // The polyglot entry point still runs the module and then calls execute(41), returning 42. + registrar.apply(org.graalvm.polyglot.Source.newBuilder("python", "x + 1", "parse-with-arguments.py").buildLiteral()); + } finally { + context.leave(); + } + assertEquals(42, context.eval("python", """ + sys.setprofile(None) + assert len(parsed_module_codes) == 1 + module_code = parsed_module_codes[0] + # Previously this code object stored RootNodeWithArguments: its target + # included both module execution and the subsequent call to execute(x). + # eval() actually crashed with ClassCastException because Python's call + # machinery expects a PRootNode, which that wrapper is not. + # Storing the module root changes the code object's executable target: + # re-execution now only defines and returns execute, without calling it. + function = eval(module_code, {}) + assert callable(function) + assert function.__code__ in module_code.co_consts + assert module_code.co_argcount == 0 + assert function.__code__.co_argcount == 1 + assert function.__code__.co_varnames[0] == 'x' + # co_code was empty for the wrapper; it now exposes the module bytecode. + assert module_code.co_code + function(41) + """).asInt()); + } + } + @TruffleInstrument.Registration(id = TEST_INSTRUMENT_ID, services = Function.class) public static final class ParseWithArgumentsInitializationInstrument extends TruffleInstrument { private final ContextLocal parsed = locals.createContextLocal((ctx) -> new boolean[1]); @@ -109,7 +155,7 @@ public void onLanguageContextInitialized(TruffleContext context, LanguageInfo la } seen[0] = true; try { - env.parse(source, "x").call(41); + assertEquals(42, env.parse(source, "x").call(41)); } catch (IOException e) { throw new AssertionError(e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/CodeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/CodeBuiltins.java index fc443384e2..df952dc8ba 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/CodeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/CodeBuiltins.java @@ -387,7 +387,7 @@ static Object lines(PCode self) { PTuple tuple; BytecodeDSLCodeUnit co = self.getCodeUnit(); if (co != null) { - PBytecodeDSLRootNode rootNode = (PBytecodeDSLRootNode) self.getRootNodeForExtraction(); + PBytecodeDSLRootNode rootNode = self.getRootNode(); List lines = computeLinesForBytecodeDSLInterpreter(rootNode); tuple = PFactory.createTuple(language, lines.toArray()); } else { @@ -494,7 +494,7 @@ Object positions(PCode self) { BytecodeDSLCodeUnit co = self.getCodeUnit(); if (co != null) { List lines = new ArrayList<>(); - PBytecodeDSLRootNode rootNode = (PBytecodeDSLRootNode) self.getRootNodeForExtraction(); + PBytecodeDSLRootNode rootNode = self.getRootNode(); BytecodeNode bytecodeNode = rootNode.getBytecodeNode(); if (!bytecodeNode.hasSourceInformation()) { bytecodeNode = bytecodeNode.ensureSourceInformation(); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/CodeNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/CodeNodes.java index d602cacd75..131cc8b76a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/CodeNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/CodeNodes.java @@ -47,7 +47,6 @@ import com.oracle.graal.python.builtins.objects.function.PFunction; import com.oracle.graal.python.builtins.objects.function.Signature; import com.oracle.graal.python.nodes.PNodeWithContext; -import com.oracle.graal.python.nodes.PRootNode; import com.oracle.graal.python.nodes.bytecode_dsl.BytecodeDSLCodeUnit; import com.oracle.graal.python.nodes.bytecode_dsl.PBytecodeDSLRootNode; import com.oracle.graal.python.runtime.ExecutionContext.BoundaryCallContext; @@ -67,7 +66,6 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.strings.TruffleString; public abstract class CodeNodes { @@ -135,7 +133,7 @@ private static PCode createCode(PythonLanguage language, int argCount, TruffleString name = PythonUtils.internString(uninternedName); qualname = PythonUtils.internString(qualname); - PRootNode rootNode; + PBytecodeDSLRootNode rootNode; Signature signature; if (codedata.length == 0) { rootNode = language.createCachedRootNode(l -> PBytecodeDSLRootNode.createBadOpcode(l, name), CreateCodeNode.class, name.toJavaStringUncached()); @@ -168,15 +166,12 @@ private static PCode createCode(PythonLanguage language, int argCount, return PFactory.createCode(language, rootNode, signature, nlocals, stacksize, flags, constants, names, varnames, freevars, cellvars, filename, name, qualname, firstlineno, linetable); } - private static PRootNode deserializeForBytecodeInterpreter(PythonLanguage language, byte[] data, TruffleString[] cellvars, TruffleString[] freevars, int flags) { - RootNode rootNode; - + private static PBytecodeDSLRootNode deserializeForBytecodeInterpreter(PythonLanguage language, byte[] data, TruffleString[] cellvars, TruffleString[] freevars, int flags) { BytecodeDSLCodeUnit code = MarshalModuleBuiltins.deserializeCodeUnit(null, language, data); if (code.flags != flags) { code = code.withFlags(flags); } - rootNode = code.createRootNode(language, false); - return (PRootNode) rootNode; + return code.createRootNode(language, false); } @NeverDefault diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/PCode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/PCode.java index 1b2c482e53..deca047769 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/PCode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/PCode.java @@ -40,8 +40,6 @@ */ package com.oracle.graal.python.builtins.objects.code; -import static com.oracle.graal.python.nodes.StringLiterals.J_EMPTY_STRING; -import static com.oracle.graal.python.util.PythonUtils.EMPTY_TRUFFLESTRING_ARRAY; import static com.oracle.graal.python.util.PythonUtils.toInternedTruffleStringUncached; import java.math.BigInteger; @@ -50,10 +48,8 @@ import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.builtins.objects.bytes.PBytes; import com.oracle.graal.python.builtins.objects.function.Signature; -import com.oracle.graal.python.builtins.objects.generator.PGenerator; import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject; import com.oracle.graal.python.builtins.objects.tuple.PTuple; -import com.oracle.graal.python.nodes.PRootNode; import com.oracle.graal.python.nodes.bytecode_dsl.BytecodeDSLCodeUnit; import com.oracle.graal.python.nodes.bytecode_dsl.PBytecodeDSLRootNode; import com.oracle.graal.python.nodes.object.IsForeignObjectNode; @@ -75,7 +71,6 @@ import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.api.strings.TruffleString; @@ -95,7 +90,7 @@ public final class PCode extends PythonBuiltinObject { /* GraalPy-specific */ public static final int CO_GRAALPYHON_MODULE = 0x1000; - private final RootNode rootNode; + private final PBytecodeDSLRootNode rootNode; @CompilationFinal private RootCallTarget callTarget; private final Signature signature; @@ -131,7 +126,7 @@ public final class PCode extends PythonBuiltinObject { // tuple of names of cell variables (referenced by containing scopes) private TruffleString[] cellvars; - public PCode(Object cls, Shape instanceShape, RootNode rootNode, Signature signature, int nlocals, + public PCode(Object cls, Shape instanceShape, PBytecodeDSLRootNode rootNode, Signature signature, int nlocals, int stacksize, int flags, Object[] constants, TruffleString[] names, TruffleString[] varnames, TruffleString[] freevars, TruffleString[] cellvars, TruffleString filename, TruffleString name, TruffleString qualname, @@ -155,37 +150,28 @@ public PCode(Object cls, Shape instanceShape, RootNode rootNode, Signature signa assert signature != null; } - private static TruffleString[] extractFreeVars(RootNode rootNode) { - BytecodeDSLCodeUnit code = getCodeUnit(rootNode); - if (code != null) { - return Arrays.copyOf(code.freevars, code.freevars.length); - } else { - return PythonUtils.EMPTY_TRUFFLESTRING_ARRAY; - } + private static TruffleString[] extractFreeVars(PBytecodeDSLRootNode rootNode) { + BytecodeDSLCodeUnit code = rootNode.getCodeUnit(); + return Arrays.copyOf(code.freevars, code.freevars.length); } - private static TruffleString[] extractCellVars(RootNode rootNode) { - BytecodeDSLCodeUnit code = getCodeUnit(rootNode); - if (code != null) { - return Arrays.copyOf(code.cellvars, code.cellvars.length); - } else { - return PythonUtils.EMPTY_TRUFFLESTRING_ARRAY; - } + private static TruffleString[] extractCellVars(PBytecodeDSLRootNode rootNode) { + BytecodeDSLCodeUnit code = rootNode.getCodeUnit(); + return Arrays.copyOf(code.cellvars, code.cellvars.length); } @TruffleBoundary - public static TruffleString extractFileName(RootNode rootNode) { - RootNode funcRootNode = rootNodeForExtraction(rootNode); - SourceSection sourceSection = funcRootNode.getSourceSection(); - if (sourceSection == null && funcRootNode instanceof PBytecodeDSLRootNode bytecodeDSLRootNode) { - bytecodeDSLRootNode.getRootNodes().ensureSourceInformation(); - sourceSection = funcRootNode.getSourceSection(); + public static TruffleString extractFileName(PBytecodeDSLRootNode rootNode) { + SourceSection sourceSection = rootNode.getSourceSection(); + if (sourceSection == null) { + rootNode.getRootNodes().ensureSourceInformation(); + sourceSection = rootNode.getSourceSection(); } String fileName = getSourceSectionFileName(sourceSection); if (fileName != null) { return toInternedTruffleStringUncached(fileName); } - return toInternedTruffleStringUncached(funcRootNode.getName()); + return toInternedTruffleStringUncached(rootNode.getName()); } @TruffleBoundary @@ -201,51 +187,33 @@ private static String getSourceSectionFileName(SourceSection src) { } @TruffleBoundary - private static int extractFirstLineno(RootNode rootNode) { - RootNode funcRootNode = rootNodeForExtraction(rootNode); - BytecodeDSLCodeUnit co = getCodeUnit(funcRootNode); - if (co != null) { - if ((co.flags & CO_GRAALPYHON_MODULE) != 0) { - return 1; - } - return co.startLine; - } - - SourceSection sourceSection = funcRootNode.getSourceSection(); - if (sourceSection != null) { - return sourceSection.getStartLine(); + private static int extractFirstLineno(PBytecodeDSLRootNode rootNode) { + BytecodeDSLCodeUnit co = rootNode.getCodeUnit(); + if ((co.flags & CO_GRAALPYHON_MODULE) != 0) { + return 1; } - return 1; + return co.startLine; } @TruffleBoundary - private static TruffleString extractName(RootNode rootNode) { - BytecodeDSLCodeUnit code = getCodeUnit(rootNode); - if (code != null) { - return code.name; - } - return toInternedTruffleStringUncached(rootNode.getName()); + private static TruffleString extractName(PBytecodeDSLRootNode rootNode) { + return rootNode.getCodeUnit().name; } @TruffleBoundary - private static int extractStackSize(RootNode rootNode) { - RootNode funcRootNode = rootNodeForExtraction(rootNode); - return funcRootNode.getFrameDescriptor().getNumberOfSlots(); + private static int extractStackSize(PBytecodeDSLRootNode rootNode) { + return rootNode.getFrameDescriptor().getNumberOfSlots(); } @TruffleBoundary - private static TruffleString[] extractVarnames(RootNode node) { - BytecodeDSLCodeUnit code = getCodeUnit(node); - if (code != null) { - return Arrays.copyOf(code.varnames, code.varnames.length); - } - return EMPTY_TRUFFLESTRING_ARRAY; + private static TruffleString[] extractVarnames(PBytecodeDSLRootNode node) { + BytecodeDSLCodeUnit code = node.getCodeUnit(); + return Arrays.copyOf(code.varnames, code.varnames.length); } private Object[] ensureConstants() { if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, constants == null)) { - BytecodeDSLCodeUnit codeUnit = getCodeUnit(getRootNode()); - constants = codeUnit != null ? new Object[codeUnit.constants.length] : PythonUtils.EMPTY_OBJECT_ARRAY; + constants = new Object[getCodeUnit().constants.length]; } return constants; } @@ -262,45 +230,20 @@ private Object getOrCreateConstant(int index) { } @TruffleBoundary - private static TruffleString[] extractNames(RootNode node) { - BytecodeDSLCodeUnit code = getCodeUnit(node); - if (code != null) { - return Arrays.copyOf(code.names, code.names.length); - } - return EMPTY_TRUFFLESTRING_ARRAY; - } - - private static RootNode rootNodeForExtraction(RootNode rootNodeArg) { - RootNode rootNode = PythonLanguage.unwrapRootNode(rootNodeArg); - return PGenerator.unwrapContinuationRoot(rootNode); + private static TruffleString[] extractNames(PBytecodeDSLRootNode node) { + BytecodeDSLCodeUnit code = node.getCodeUnit(); + return Arrays.copyOf(code.names, code.names.length); } @TruffleBoundary - private static int extractFlags(RootNode node) { - int flags = 0; - BytecodeDSLCodeUnit code = getCodeUnit(node); - if (code != null) { - flags = code.flags; - } - return flags; - } - - private static BytecodeDSLCodeUnit getCodeUnit(RootNode node) { - RootNode rootNode = rootNodeForExtraction(node); - if (rootNode instanceof PBytecodeDSLRootNode bytecodeDSLRootNode) { - return bytecodeDSLRootNode.getCodeUnit(); - } - return null; + private static int extractFlags(PBytecodeDSLRootNode node) { + return node.getCodeUnit().flags; } - public RootNode getRootNode() { + public PBytecodeDSLRootNode getRootNode() { return rootNode; } - RootNode getRootNodeForExtraction() { - return rootNodeForExtraction(getRootNode()); - } - public TruffleString[] getFreeVars() { if (freevars == null) { freevars = extractFreeVars(getRootNode()); @@ -349,12 +292,8 @@ public int getFirstLineNo() { @TruffleBoundary public int lastiToLine(int lasti) { - RootNode funcRootNode = rootNodeForExtraction(getRootNode()); - if (funcRootNode instanceof PBytecodeDSLRootNode bytecodeDSLRootNode) { - BytecodeNode bytecodeNode = bytecodeDSLRootNode.getBytecodeNode(); - return bytecodeDSLRootNode.bciToLine(PBytecodeDSLRootNode.lastiToBci(lasti, bytecodeNode), bytecodeNode); - } - return -1; + BytecodeNode bytecodeNode = rootNode.getBytecodeNode(); + return rootNode.bciToLine(PBytecodeDSLRootNode.lastiToBci(lasti, bytecodeNode), bytecodeNode); } public TruffleString getName() { @@ -413,16 +352,11 @@ public TruffleString[] getVarnames() { } public byte[] getCodestring(Node node) { - RootNode rN = getRootNode(); - if (rN instanceof PRootNode) { - return ((PRootNode) rN).getCode(node); - } else { - return PythonUtils.EMPTY_BYTE_ARRAY; - } + return rootNode.getCode(node); } public BytecodeDSLCodeUnit getCodeUnit() { - return getCodeUnit(getRootNode()); + return rootNode.getCodeUnit(); } public Object[] getConstants() { @@ -445,7 +379,7 @@ public PCode getOrCreateChildCode(int index, BytecodeDSLCodeUnit codeUnit) { @TruffleBoundary private PCode createCode(BytecodeDSLCodeUnit codeUnit) { - PBytecodeDSLRootNode outerRootNode = (PBytecodeDSLRootNode) getRootNodeForExtraction(); + PBytecodeDSLRootNode outerRootNode = getRootNode(); PythonLanguage language = outerRootNode.getLanguage(); PBytecodeDSLRootNode rN = outerRootNode.getOrCreateChildRootNode(codeUnit); return PFactory.createCode(language, rN, rN.getSignature(), codeUnit, getFilename()); @@ -581,7 +515,7 @@ public String toString() { * This might be called without an active context (i.e. when dumping graphs), we cannot use * getFilename */ - String codeFilename = getSourceSectionFileName(rootNodeForExtraction(getRootNode()).getSourceSection()); + String codeFilename = getSourceSectionFileName(rootNode.getSourceSection()); if (codeFilename == null) { codeFilename = "None"; } @@ -591,11 +525,7 @@ public String toString() { @TruffleBoundary public String toDisassembledString(boolean quickened) { - RootNode rN = getRootNode(); - if (rN instanceof PBytecodeDSLRootNode dslRoot) { - return dslRoot.getCodeUnit().toString(quickened, dslRoot); - } - return J_EMPTY_STRING; + return rootNode.getCodeUnit().toString(quickened, rootNode); } private static PTuple createTuple(PythonLanguage language, Object[] array) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/PBytecodeDSLRootNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/PBytecodeDSLRootNode.java index f66ac243b7..382dcc6130 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/PBytecodeDSLRootNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/PBytecodeDSLRootNode.java @@ -1854,7 +1854,7 @@ protected static boolean isSingleContext(Node node) { @NeverDefault static Assumption getCodeStableAssumption(PCode code) { - PBytecodeDSLRootNode rootNode = (PBytecodeDSLRootNode) code.getRootNode(); + PBytecodeDSLRootNode rootNode = code.getRootNode(); return rootNode.getFunctionCodeFinalAssumption(); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/CallDispatchers.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/CallDispatchers.java index e20f721586..768b4693f0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/CallDispatchers.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/CallDispatchers.java @@ -50,6 +50,7 @@ import com.oracle.graal.python.builtins.objects.module.PythonModule; import com.oracle.graal.python.nodes.PNodeWithContext; import com.oracle.graal.python.nodes.argument.CreateArgumentsNode; +import com.oracle.graal.python.nodes.bytecode_dsl.PBytecodeDSLRootNode; import com.oracle.graal.python.nodes.call.CallDispatchersFactory.FunctionIndirectInvokeNodeGen; import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode; import com.oracle.graal.python.runtime.ExecutionContext; @@ -76,7 +77,6 @@ import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.IndirectCallNode; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.profiles.InlinedConditionProfile; public class CallDispatchers { @@ -397,7 +397,7 @@ static Object callFunctionCached(VirtualFrame frame, Node inliningTarget, @Suppr // We have multiple contexts, don't cache the objects so that contexts can be cleaned up @Specialization(guards = {"callee.getCode().getRootNode() == rootNode"}, limit = "getCallSiteInlineCacheMaxDepth()", replaces = "callFunctionCached") static Object callFunctionCachedCt(VirtualFrame frame, Node inliningTarget, PFunction callee, Object[] arguments, - @SuppressWarnings("unused") @Cached(value = "callee.getCode().getRootNode()", adopt = false) RootNode rootNode, + @SuppressWarnings("unused") @Cached(value = "callee.getCode().getRootNode()", adopt = false) PBytecodeDSLRootNode rootNode, @Cached("createDirectCallNodeFor(callee)") DirectCallNode callNode, @Exclusive @Cached FunctionDirectInvokeNode invoke) { return invoke.execute(frame, inliningTarget, callNode, callee, arguments); @@ -438,7 +438,7 @@ static Object callFunctionCached(VirtualFrame frame, Node inliningTarget, @Suppr // We have multiple contexts, don't cache the objects so that contexts can be cleaned up @Specialization(guards = {"callee.getCode().getRootNode() == rootNode"}, limit = "getCallSiteInlineCacheMaxDepth()", replaces = "callFunctionCached") static Object callFunctionCachedCt(VirtualFrame frame, Node inliningTarget, PFunction callee, Object[] arguments, PKeyword[] keywords, - @SuppressWarnings("unused") @Cached(value = "callee.getCode().getRootNode()", adopt = false) RootNode rootNode, + @SuppressWarnings("unused") @Cached(value = "callee.getCode().getRootNode()", adopt = false) PBytecodeDSLRootNode rootNode, @Exclusive @Cached CreateArgumentsNode createArgs, @Cached("createDirectCallNodeFor(callee)") DirectCallNode callNode, @Exclusive @Cached FunctionDirectInvokeNode invoke) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/TopLevelExceptionHandler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/TopLevelExceptionHandler.java index 3e092484b2..41570a44f0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/TopLevelExceptionHandler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/TopLevelExceptionHandler.java @@ -60,6 +60,7 @@ import com.oracle.graal.python.lib.PyObjectCallMethodObjArgs; import com.oracle.graal.python.lib.PyObjectStrAsObjectNode; import com.oracle.graal.python.nodes.BuiltinNames; +import com.oracle.graal.python.nodes.bytecode_dsl.PBytecodeDSLRootNode; import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinClassProfile; import com.oracle.graal.python.nodes.object.GetClassNode; import com.oracle.graal.python.nodes.object.GetClassNode.GetPythonObjectClassNode; @@ -311,7 +312,9 @@ private Object run(VirtualFrame frame) { PythonContext pythonContext = getContext(); PythonModule mainModule = null; PythonLanguage language = getPythonLanguage(); - PCode code = PFactory.createCode(language, innerCallTarget, PythonUtils.internString(TruffleString.fromJavaStringUncached(source.getName(), TS_ENCODING))); + // The code object describes the module; polyglot argument adaptation stays in innerCallTarget. + PBytecodeDSLRootNode moduleRoot = (PBytecodeDSLRootNode) PythonLanguage.unwrapRootNode(innerCallTarget.getRootNode()); + PCode code = PFactory.createCode(language, moduleRoot, PythonUtils.internString(TruffleString.fromJavaStringUncached(source.getName(), TS_ENCODING))); TruffleString originalFilename = code.getFilename(); if (source.isInteractive()) { code.fixCoFilename(pythonContext.getNextInteractiveSourceFilename(originalFilename)); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PFactory.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PFactory.java index d1aa5753b7..2b10e0bc5d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PFactory.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PFactory.java @@ -239,7 +239,6 @@ import com.oracle.graal.python.builtins.objects.typing.PTypeVar; import com.oracle.graal.python.builtins.objects.typing.PTypeVarTuple; import com.oracle.graal.python.lib.PyTupleCheckNode; -import com.oracle.graal.python.nodes.PRootNode; import com.oracle.graal.python.nodes.bytecode_dsl.BytecodeDSLCodeUnit; import com.oracle.graal.python.nodes.bytecode_dsl.PBytecodeDSLRootNode; import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode; @@ -265,7 +264,6 @@ import com.oracle.truffle.api.bytecode.ContinuationRootNode; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.tools.profiler.CPUSampler; @@ -1138,21 +1136,26 @@ public static PCode createCode(PythonLanguage language, RootCallTarget ct) { } public static PCode createCode(PythonLanguage language, RootCallTarget ct, TruffleString filename) { - return new PCode(PythonBuiltinClassType.PCode, PythonBuiltinClassType.PCode.getInstanceShape(language), ct.getRootNode(), Signature.fromCallTarget(ct), + return createCode(language, (PBytecodeDSLRootNode) ct.getRootNode(), filename); + } + + public static PCode createCode(PythonLanguage language, PBytecodeDSLRootNode rootNode, TruffleString filename) { + return new PCode(PythonBuiltinClassType.PCode, PythonBuiltinClassType.PCode.getInstanceShape(language), rootNode, rootNode.getSignature(), -1, -1, -1, null, null, null, null, null, filename, null, null, -1, null); } public static PCode createCode(PythonLanguage language, RootCallTarget ct, int flags, int firstlineno, byte[] linetable, TruffleString filename) { - return new PCode(PythonBuiltinClassType.PCode, PythonBuiltinClassType.PCode.getInstanceShape(language), ct.getRootNode(), Signature.fromCallTarget(ct), + PBytecodeDSLRootNode rootNode = (PBytecodeDSLRootNode) ct.getRootNode(); + return new PCode(PythonBuiltinClassType.PCode, PythonBuiltinClassType.PCode.getInstanceShape(language), rootNode, rootNode.getSignature(), -1, -1, flags, null, null, null, null, null, filename, null, null, firstlineno, linetable); } - public static PCode createCode(PythonLanguage language, RootNode rootNode, Signature signature, BytecodeDSLCodeUnit codeUnit, TruffleString filename) { + public static PCode createCode(PythonLanguage language, PBytecodeDSLRootNode rootNode, Signature signature, BytecodeDSLCodeUnit codeUnit, TruffleString filename) { return new PCode(PythonBuiltinClassType.PCode, PythonBuiltinClassType.PCode.getInstanceShape(language), rootNode, signature, codeUnit.varnames.length, -1, -1, null, null, null, null, null, filename, codeUnit.name, codeUnit.qualname, -1, null); } - public static PCode createCode(PythonLanguage language, RootNode rootNode, Signature signature, int nlocals, + public static PCode createCode(PythonLanguage language, PBytecodeDSLRootNode rootNode, Signature signature, int nlocals, int stacksize, int flags, Object[] constants, TruffleString[] names, TruffleString[] varnames, TruffleString[] freevars, TruffleString[] cellvars, From 3ad3f9167210a51b28e1058e5c5c06ae135a0f58 Mon Sep 17 00:00:00 2001 From: stepan Date: Fri, 23 Oct 2026 12:05:31 +0200 Subject: [PATCH 4/6] Rename external function wrapper nodes --- .../processor/CApiBuiltinsProcessor.java | 24 +- .../test/ExternalFunctionWrapperTest.java | 96 +++--- .../cext/capi/ExternalFunctionNodes.java | 276 +++++++++--------- .../capi/ExternalFunctionWrapperFactory.java | 22 +- .../cext/capi/MethodDescriptorWrapper.java | 42 +-- .../oracle/graal/python/nodes/PRootNode.java | 4 +- .../call/special/AbstractCallMethodNode.java | 2 +- .../function/BuiltinFunctionRootNode.java | 4 +- 8 files changed, 236 insertions(+), 234 deletions(-) diff --git a/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/CApiBuiltinsProcessor.java b/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/CApiBuiltinsProcessor.java index 5ff044c88c..eb6a4a0e79 100644 --- a/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/CApiBuiltinsProcessor.java +++ b/graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/CApiBuiltinsProcessor.java @@ -1397,9 +1397,9 @@ private boolean isCannotRaise(VariableElement signature) { return Boolean.parseBoolean(initArgs[0].strip()); } - private boolean isWrapperRootInvoke(InvokeExternalFunctionDesc wrapper) { - TypeMirror wrapperBaseRoot = processingEnv.getElementUtils().getTypeElement(EXFUNC_INVOKER_PACKAGE + ".ExternalFunctionNodes.WrapperBaseRoot").asType(); - return processingEnv.getTypeUtils().isSubtype(wrapper.origin.getEnclosingElement().asType(), wrapperBaseRoot); + private boolean isWrapperInvoke(InvokeExternalFunctionDesc wrapper) { + TypeMirror wrapperBase = processingEnv.getElementUtils().getTypeElement(EXFUNC_INVOKER_PACKAGE + ".ExternalFunctionNodes.WrapperBase").asType(); + return processingEnv.getTypeUtils().isSubtype(wrapper.origin.getEnclosingElement().asType(), wrapperBase); } private static String getGeneratedExternalInvokeHelperClassName(Element clazz) { @@ -1874,7 +1874,7 @@ private ExecutableElement findMethod(Element location, TypeMirror enclosingType, return null; } - private static final String WRAPPER_DESCRIPTOR_GEN_CLASS_NAME = "WrapperDescriptorRootNodesGen"; + private static final String WRAPPER_DESCRIPTOR_GEN_CLASS_NAME = "WrapperDescriptorNodesGen"; private void generateExternalFunctionHelperNodes(List externalFunctionDescs) throws IOException { final Types typeUtils = processingEnv.getTypeUtils(); @@ -1883,7 +1883,7 @@ private void generateExternalFunctionHelperNodes(List> helperInvokeDescsByClass = new LinkedHashMap<>(); for (InvokeExternalFunctionDesc desc : externalFunctionDescs) { - if (!isWrapperRootInvoke(desc)) { + if (!isWrapperInvoke(desc)) { TypeElement clazz = (TypeElement) desc.origin.getEnclosingElement(); helperInvokeDescsByClass.computeIfAbsent(clazz, k -> new ArrayList<>()).add(desc); } @@ -1992,10 +1992,10 @@ private void generateExternalFunctionHelperNodes(List externalFunctionDescs, List wrappers, + private void generateExternalFunctionWrapperNodes(List externalFunctionDescs, List wrappers, @SuppressWarnings("unused") Map externalFunctionSignatures) throws IOException { final Types typeUtils = processingEnv.getTypeUtils(); - List wrapperInvokeDescs = externalFunctionDescs.stream().filter(this::isWrapperRootInvoke).toList(); + List wrapperInvokeDescs = externalFunctionDescs.stream().filter(this::isWrapperInvoke).toList(); ArrayList lines = new ArrayList<>(); lines.add("// @formatter:off"); @@ -2011,7 +2011,7 @@ private void generateExternalFunctionRootNodes(List lines.add("import " + EXFUNC_INVOKER_PACKAGE + "." + clazz.getEnclosingElement().getSimpleName() + "." + clazz.getSimpleName() + ";"); } lines.add("import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.PExternalFunctionWrapper;"); - lines.add("import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.WrapperDescriptorRoot;"); + lines.add("import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.WrapperDescriptor;"); lines.add("import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTiming;"); lines.add("import " + NATIVE_FUNCTION_POINTER + ";"); lines.add("import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData;"); @@ -2182,13 +2182,13 @@ private void generateExternalFunctionRootNodes(List // generate factory method lines.add(" @TruffleBoundary"); - lines.add(" public static WrapperDescriptorRoot create(TruffleString name, PExternalFunctionWrapper wrapper) {"); + lines.add(" public static WrapperDescriptor create(TruffleString name, PExternalFunctionWrapper wrapper) {"); lines.add(" return switch (wrapper) {"); for (CApiExternalFunctionWrapperDesc wrapper : wrappers) { String wrapperList = wrapper.wrapperNames.stream().map(CApiBuiltinsProcessor::name).collect(Collectors.joining(", ")); lines.add(" case " + wrapperList + " -> new " + name(wrapper.origin) + "Gen(name, wrapper);"); } - lines.add(" default -> throw CompilerDirectives.shouldNotReachHere(\"no root node for wrapper \" + wrapper);"); + lines.add(" default -> throw CompilerDirectives.shouldNotReachHere(\"no node for wrapper \" + wrapper);"); lines.add(" };"); lines.add(" }"); @@ -2196,7 +2196,7 @@ private void generateExternalFunctionRootNodes(List for (boolean signature : new boolean[]{false, true}) { lines.add(" @TruffleBoundary"); lines.add(signature ? " public static Signature getSignature(PExternalFunctionWrapper wrapper) {" - : " public static Class getNodeClass(PExternalFunctionWrapper wrapper) {"); + : " public static Class getNodeClass(PExternalFunctionWrapper wrapper) {"); lines.add(" return switch (wrapper) {"); for (CApiExternalFunctionWrapperDesc wrapper : wrappers) { String wrapperList = wrapper.wrapperNames.stream().map(CApiBuiltinsProcessor::name).collect(Collectors.joining(", ")); @@ -2340,7 +2340,7 @@ public boolean process(Set annotations, RoundEnvironment generateCApiHeader(javaBuiltins, javaConstants, capiSymbols); generateExternalFunctionInvoker(new ArrayList<>(sigs.values())); generateExternalFunctionHelperNodes(externalFunctionDescs); - generateExternalFunctionRootNodes(externalFunctionDescs, cApiExternalFunctionWrapperDescs, sigs); + generateExternalFunctionWrapperNodes(externalFunctionDescs, cApiExternalFunctionWrapperDescs, sigs); } generateBuiltinRegistry(javaBuiltins); generateUpcallConfig(javaBuiltins, explicitUpcallTargets); diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/ExternalFunctionWrapperTest.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/ExternalFunctionWrapperTest.java index 8c16324cf1..cb1c9aeca2 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/ExternalFunctionWrapperTest.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/ExternalFunctionWrapperTest.java @@ -40,6 +40,7 @@ */ package com.oracle.graal.python.test; +import static com.oracle.graal.python.util.PythonUtils.tsLiteral; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -48,7 +49,6 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import static com.oracle.graal.python.util.PythonUtils.tsLiteral; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -68,16 +68,17 @@ import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.annotations.Builtin; +import com.oracle.graal.python.builtins.modules.cext.PythonCextTypeBuiltins; import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes; +import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.Getter; +import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.MethO; import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.PExternalFunctionWrapper; -import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.WrapperBaseRoot; +import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.WrapperBase; import com.oracle.graal.python.builtins.objects.cext.capi.MethodDescriptorWrapper; -import com.oracle.graal.python.builtins.modules.cext.PythonCextTypeBuiltins; import com.oracle.graal.python.builtins.objects.frame.FrameBuiltinsFactory.GetLocalsNodeFactory; import com.oracle.graal.python.builtins.objects.function.PArguments; import com.oracle.graal.python.builtins.objects.function.PKeyword; import com.oracle.graal.python.builtins.objects.function.Signature; -import com.oracle.graal.python.runtime.CallerFlags; import com.oracle.graal.python.nodes.argument.CreateArgumentsNode; import com.oracle.graal.python.nodes.argument.ReadArgumentNode; import com.oracle.graal.python.nodes.argument.ReadIndexedArgumentNode; @@ -88,6 +89,7 @@ import com.oracle.graal.python.nodes.function.PythonBuiltinFrameArgsNode; import com.oracle.graal.python.nodes.function.PythonBuiltinNode; import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; +import com.oracle.graal.python.runtime.CallerFlags; import com.oracle.graal.python.util.PythonUtils.PrototypeNodeFactory; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.Truffle; @@ -117,40 +119,40 @@ private static Spec descriptor(String body, String wrappers, String parameters, } private static final List SPECS = List.of( - method("MethNoargsRoot", "NOARGS", "self", -1, false), - method("MethORoot", "O", "self,arg", -1, false), - method("MethVarargsRoot", "VARARGS", "self", 1, false), - method("MethKeywordsRoot", "KEYWORDS", "self", 1, true), - method("MethFastcallRoot", "FASTCALL", "self", 1, false), - method("MethFastcallWithKeywordsRoot", "FASTCALL_WITH_KEYWORDS", "self", 1, true), - method("MethMethodRoot", "METHOD", "self,cls", 1, true), + method("MethNoargs", "NOARGS", "self", -1, false), + method("MethO", "O", "self,arg", -1, false), + method("MethVarargs", "VARARGS", "self", 1, false), + method("MethKeywords", "KEYWORDS", "self", 1, true), + method("MethFastcall", "FASTCALL", "self", 1, false), + method("MethFastcallWithKeywords", "FASTCALL_WITH_KEYWORDS", "self", 1, true), + method("MethMethod", "METHOD", "self,cls", 1, true), descriptor("MethUnaryFunc", "UNARYFUNC", "self", -1, false, false, true, false), - descriptor("MethNewRoot", "NEW", "self", 1, true, true, true, false), - descriptor("MethCallRoot", "CALL", "self", 1, true, true, true, false), - descriptor("MethInitRoot", "INIT", "self", 1, true, true, true, false), - descriptor("MethInquiryRoot", "INQUIRYPRED", "self", -1, false, false, true, false), - descriptor("IndexArgFuncRootNode", "INDEXARGFUNC", "self,i", -1, false, false, true, false), - descriptor("GetAttrFuncRootNode", "GETATTR", "self,key", -1, false, false, true, false), - descriptor("SetAttrFuncRootNode", "SETATTR", "self,key,value", -1, false, false, true, false), - descriptor("SetAttrOFuncRootNode", "SETATTRO", "self,name,value", -1, false, false, true, false), - descriptor("RichCmpFuncRootNode", "RICHCMP", "self,other,op", -1, false, false, true, false), - descriptor("GetItemRootNode", "SQ_ITEM", "self,i", -1, false, false, true, false), - descriptor("SetItemRootNode", "SQ_SETITEM", "self,i,value", -1, false, false, true, false), - descriptor("SqDelItemRootNode", "SQ_DELITEM", "self,key", -1, false, false, true, false), - descriptor("DescrGetRootNode", "DESCR_GET", "self,obj,type", -1, false, false, true, false), - descriptor("DescrDeleteRootNode", "DESCR_DELETE", "self,obj", -1, false, false, true, false), - descriptor("DelAttrRootNode", "DELATTRO", "self,obj", -1, false, false, true, false), - descriptor("MpDelItemRootNode", "MP_DELITEM", "self,key", -1, false, false, true, false), - descriptor("MethTernaryFuncRoot", "TERNARYFUNC,TERNARYFUNC_R", "self,other,third", -1, false, false, false, false), - descriptor("MethRichcmpOpRootNode", "GT,GE,LE,LT,EQ,NE", "self,other", -1, false, false, true, false), - descriptor("IterNextFuncRootNode", "ITERNEXT", "self", -1, false, true, true, false), - descriptor("GetterRoot", "GETTER", "self", -1, false, false, true, true), - descriptor("SetterRoot", "SETTER", "self,value", -1, false, false, true, true), - descriptor("MethLenfuncRoot", "LENFUNC,HASHFUNC", "self", -1, false, false, true, false), - descriptor("MethObjObjProcRoot", "OBJOBJPROC", "self,value", -1, false, false, true, false), - descriptor("MethObjObjArgProcRoot", "OBJOBJARGPROC", "self,key,value", -1, false, false, true, false), - descriptor("MethBinaryRoot", "BINARYFUNC,BINARYFUNC_L,BINARYFUNC_R", "self,other", -1, false, false, true, false), - descriptor("MethDescrSetRoot", "DESCR_SET", "self,instance,value", -1, false, false, true, false)); + descriptor("MethNew", "NEW", "self", 1, true, true, true, false), + descriptor("MethCall", "CALL", "self", 1, true, true, true, false), + descriptor("MethInit", "INIT", "self", 1, true, true, true, false), + descriptor("MethInquiry", "INQUIRYPRED", "self", -1, false, false, true, false), + descriptor("IndexArgFuncNode", "INDEXARGFUNC", "self,i", -1, false, false, true, false), + descriptor("GetAttrFuncNode", "GETATTR", "self,key", -1, false, false, true, false), + descriptor("SetAttrFuncNode", "SETATTR", "self,key,value", -1, false, false, true, false), + descriptor("SetAttrOFuncNode", "SETATTRO", "self,name,value", -1, false, false, true, false), + descriptor("RichCmpFuncNode", "RICHCMP", "self,other,op", -1, false, false, true, false), + descriptor("GetItemNode", "SQ_ITEM", "self,i", -1, false, false, true, false), + descriptor("SetItemNode", "SQ_SETITEM", "self,i,value", -1, false, false, true, false), + descriptor("SqDelItemNode", "SQ_DELITEM", "self,key", -1, false, false, true, false), + descriptor("DescrGetNode", "DESCR_GET", "self,obj,type", -1, false, false, true, false), + descriptor("DescrDeleteNode", "DESCR_DELETE", "self,obj", -1, false, false, true, false), + descriptor("DelAttrNode", "DELATTRO", "self,obj", -1, false, false, true, false), + descriptor("MpDelItemNode", "MP_DELITEM", "self,key", -1, false, false, true, false), + descriptor("MethTernaryFunc", "TERNARYFUNC,TERNARYFUNC_R", "self,other,third", -1, false, false, false, false), + descriptor("MethRichcmpOpNode", "GT,GE,LE,LT,EQ,NE", "self,other", -1, false, false, true, false), + descriptor("IterNextFuncNode", "ITERNEXT", "self", -1, false, true, true, false), + descriptor("Getter", "GETTER", "self", -1, false, false, true, true), + descriptor("Setter", "SETTER", "self,value", -1, false, false, true, true), + descriptor("MethLenfunc", "LENFUNC,HASHFUNC", "self", -1, false, false, true, false), + descriptor("MethObjObjProc", "OBJOBJPROC", "self,value", -1, false, false, true, false), + descriptor("MethObjObjArgProc", "OBJOBJARGPROC", "self,key,value", -1, false, false, true, false), + descriptor("MethBinary", "BINARYFUNC,BINARYFUNC_L,BINARYFUNC_R", "self,other", -1, false, false, true, false), + descriptor("MethDescrSet", "DESCR_SET", "self,instance,value", -1, false, false, true, false)); @Before public void enter() { @@ -189,7 +191,7 @@ private static List names(TruffleString[] names) { return Arrays.stream(names).map(TruffleString::toJavaStringUncached).toList(); } - private static List readerFields(WrapperBaseRoot body) { + private static List readerFields(WrapperBase body) { List fields = new ArrayList<>(); for (Class owner = body.getClass(); owner != null; owner = owner.getSuperclass()) { for (Field field : owner.getDeclaredFields()) { @@ -202,7 +204,7 @@ private static List readerFields(WrapperBaseRoot body) { return fields; } - private static void initializeReaders(WrapperBaseRoot body, Signature signature) throws Exception { + private static void initializeReaders(WrapperBase body, Signature signature) throws Exception { // Initialize the production helper groups without making a native call. The C API suite // separately exercises the guards on first and repeated real wrapper invocations. for (Class owner = body.getClass(); owner != null; owner = owner.getSuperclass()) { @@ -215,12 +217,12 @@ private static void initializeReaders(WrapperBaseRoot body, Signature signature) } for (Field field : readerFields(body)) { if (field.getName().equals("readClosureNode")) { - field.set(body, invoke(ExternalFunctionNodes.GetterRoot.class, null, "createReadClosureNode", new Class[]{Signature.class}, signature)); + field.set(body, invoke(Getter.class, null, "createReadClosureNode", new Class[]{Signature.class}, signature)); } } } - private static List checkReaders(WrapperBaseRoot body, Spec spec, boolean isStatic, VirtualFrame frame, Object[] positional, + private static List checkReaders(WrapperBase body, Spec spec, boolean isStatic, VirtualFrame frame, Object[] positional, Object callable, Object closure, Object[] extras, PKeyword[] keywords) throws Exception { List readers = new ArrayList<>(); Map counts = new IdentityHashMap<>(); @@ -267,7 +269,7 @@ private static List checkReaders(WrapperBaseRoot body, Spec sp assertEquals(spec.vararg == -1 ? 0 : 1, varargs); assertEquals(spec.kwargs ? 1 : 0, kwargs); assertSame(isStatic ? com.oracle.graal.python.builtins.objects.PNone.NO_VALUE : positional[0], - invoke(WrapperBaseRoot.class, body, "readSelf", new Class[]{VirtualFrame.class}, frame)); + invoke(WrapperBase.class, body, "readSelf", new Class[]{VirtualFrame.class}, frame)); return readers; } @@ -345,7 +347,7 @@ public void readerLayouts() throws Exception { System.arraycopy(positional, upfront, user, 0, positional.length - upfront); System.arraycopy(extras, 0, user, positional.length - upfront, extras.length); Object[] bound = CreateArgumentsNode.executeUncached(NAME, user, keywords, signature, positional[0], cls, new Object[0], defaults, true); - WrapperBaseRoot body = (WrapperBaseRoot) production.getFactory().createNode(); + WrapperBase body = (WrapperBase) production.getFactory().createNode(); initializeReaders(body, signature); new AdoptionRoot(body).getCallTarget(); VirtualFrame frame = Truffle.getRuntime().createVirtualFrame(bound, FrameDescriptor.newBuilder().build()); @@ -383,8 +385,8 @@ public void factoryClassesAndChildren() throws Exception { assertEquals(ExternalFunctionNodes.class.getName() + "$" + spec.body, factory.getNodeClass().getName()); assertEquals(List.of(List.of()), factory.getNodeSignatures()); assertEquals(List.of(), factory.getExecutionSignature()); - WrapperBaseRoot body = (WrapperBaseRoot) factory.createNode(); - WrapperBaseRoot other = (WrapperBaseRoot) factory.createNode(); + WrapperBase body = (WrapperBase) factory.createNode(); + WrapperBase other = (WrapperBase) factory.createNode(); assertNotSame(body, other); assertTrue(PythonBuiltinFrameArgsNode.class.isAssignableFrom(body.getClass())); assertFalse(PythonBuiltinNode.class.isAssignableFrom(body.getClass())); @@ -406,7 +408,7 @@ public void factoryClassesAndChildren() throws Exception { assertFalse(otherCounts.containsKey(reader)); } } - Field self = WrapperBaseRoot.class.getDeclaredField("readSelfNode"); + Field self = WrapperBase.class.getDeclaredField("readSelfNode"); self.setAccessible(true); assertNotNull(self.get(body)); if (spec.method && !convention.equals("METHOD")) { @@ -511,7 +513,7 @@ public void cacheKeys() throws Exception { }, reference.getFactory().getNodeClass(), MethodDescriptorWrapper.NOARGS, NAME, true, false)); List variants = new ArrayList<>(); - variants.add(language.createCachedExternalFunWrapperRootNode(l -> freshRoot(), ExternalFunctionNodes.MethORoot.class, MethodDescriptorWrapper.NOARGS, NAME, true, false)); + variants.add(language.createCachedExternalFunWrapperRootNode(l -> freshRoot(), MethO.class, MethodDescriptorWrapper.NOARGS, NAME, true, false)); variants.add(language.createCachedExternalFunWrapperRootNode(l -> freshRoot(), reference.getFactory().getNodeClass(), MethodDescriptorWrapper.O, NAME, true, false)); variants.add(language.createCachedExternalFunWrapperRootNode(l -> freshRoot(), reference.getFactory().getNodeClass(), MethodDescriptorWrapper.NOARGS, NAME, false, false)); variants.add(language.createCachedExternalFunWrapperRootNode(l -> freshRoot(), reference.getFactory().getNodeClass(), MethodDescriptorWrapper.NOARGS, NAME, true, true)); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java index 06aca87496..c1324cce83 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java @@ -100,7 +100,6 @@ import com.oracle.graal.python.annotations.Builtin; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.objects.PNone; -import com.oracle.graal.python.lib.PyLongAsIntNodeGen; import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject; import com.oracle.graal.python.builtins.objects.cext.capi.CApiGCSupport.PyObjectGCTrackNode; import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.AsCharPointerNode; @@ -147,6 +146,7 @@ import com.oracle.graal.python.builtins.objects.type.slots.TpSlot; import com.oracle.graal.python.builtins.objects.type.slots.TpSlot.TpSlotNative; import com.oracle.graal.python.builtins.objects.type.slots.TpSlot.TpSlotPythonSingle; +import com.oracle.graal.python.lib.PyLongAsIntNodeGen; import com.oracle.graal.python.lib.PyNumberAsSizeNode; import com.oracle.graal.python.lib.RichCmpOp; import com.oracle.graal.python.nodes.ErrorMessages; @@ -286,118 +286,118 @@ public static ToPythonStringNode getUncached() { /** Enum of all slot wrapper functions in {@code typeobject.c}. */ public enum PExternalFunctionWrapper implements NativeCExtSymbol { - GETATTR(GetAttrFuncRootNode.class, ExternalFunctionSignature.GETATTRFUNC), - SETATTR(SetAttrFuncRootNode.class, ExternalFunctionSignature.SETATTRFUNC), + GETATTR(GetAttrFuncNode.class, ExternalFunctionSignature.GETATTRFUNC), + SETATTR(SetAttrFuncNode.class, ExternalFunctionSignature.SETATTRFUNC), - RICHCMP(RichCmpFuncRootNode.class, ExternalFunctionSignature.RICHCMPFUNC), + RICHCMP(RichCmpFuncNode.class, ExternalFunctionSignature.RICHCMPFUNC), // wrap_sq_setitem - SQ_SETITEM(SetItemRootNode.class, ExternalFunctionSignature.SSIZEOBJARGPROC), + SQ_SETITEM(SetItemNode.class, ExternalFunctionSignature.SSIZEOBJARGPROC), // wrap_unaryfunc UNARYFUNC(MethUnaryFunc.class, ExternalFunctionSignature.UNARYFUNC), // wrap_binaryfunc - BINARYFUNC(MethBinaryRoot.class, ExternalFunctionSignature.BINARYFUNC), + BINARYFUNC(MethBinary.class, ExternalFunctionSignature.BINARYFUNC), // wrap_binaryfunc_l - BINARYFUNC_L(MethBinaryRoot.class, ExternalFunctionSignature.BINARYFUNC), + BINARYFUNC_L(MethBinary.class, ExternalFunctionSignature.BINARYFUNC), // wrap_binaryfunc_r - BINARYFUNC_R(MethBinaryRoot.class, ExternalFunctionSignature.BINARYFUNC), + BINARYFUNC_R(MethBinary.class, ExternalFunctionSignature.BINARYFUNC), // wrap_ternaryfunc - TERNARYFUNC(MethTernaryFuncRoot.class, ExternalFunctionSignature.TERNARYFUNC, 1), + TERNARYFUNC(MethTernaryFunc.class, ExternalFunctionSignature.TERNARYFUNC, 1), // wrap_ternaryfunc_r - TERNARYFUNC_R(MethTernaryFuncRoot.class, ExternalFunctionSignature.TERNARYFUNC, 1), + TERNARYFUNC_R(MethTernaryFunc.class, ExternalFunctionSignature.TERNARYFUNC, 1), // richcmp_lt - LT(MethRichcmpOpRootNode.class, ExternalFunctionSignature.RICHCMPFUNC), + LT(MethRichcmpOpNode.class, ExternalFunctionSignature.RICHCMPFUNC), // richcmp_le - LE(MethRichcmpOpRootNode.class, ExternalFunctionSignature.RICHCMPFUNC), + LE(MethRichcmpOpNode.class, ExternalFunctionSignature.RICHCMPFUNC), // richcmp_eq - EQ(MethRichcmpOpRootNode.class, ExternalFunctionSignature.RICHCMPFUNC), + EQ(MethRichcmpOpNode.class, ExternalFunctionSignature.RICHCMPFUNC), // richcmp_ne - NE(MethRichcmpOpRootNode.class, ExternalFunctionSignature.RICHCMPFUNC), + NE(MethRichcmpOpNode.class, ExternalFunctionSignature.RICHCMPFUNC), // richcmp_gt - GT(MethRichcmpOpRootNode.class, ExternalFunctionSignature.RICHCMPFUNC), + GT(MethRichcmpOpNode.class, ExternalFunctionSignature.RICHCMPFUNC), // richcmp_ge - GE(MethRichcmpOpRootNode.class, ExternalFunctionSignature.RICHCMPFUNC), + GE(MethRichcmpOpNode.class, ExternalFunctionSignature.RICHCMPFUNC), // wrap_next - ITERNEXT(IterNextFuncRootNode.class, ExternalFunctionSignature.UNARYFUNC), + ITERNEXT(IterNextFuncNode.class, ExternalFunctionSignature.UNARYFUNC), // wrap_inquirypred - INQUIRYPRED(MethInquiryRoot.class, ExternalFunctionSignature.INQUIRY), + INQUIRYPRED(MethInquiry.class, ExternalFunctionSignature.INQUIRY), // wrap_sq_delitem - SQ_DELITEM(SqDelItemRootNode.class, ExternalFunctionSignature.SSIZEOBJARGPROC), + SQ_DELITEM(SqDelItemNode.class, ExternalFunctionSignature.SSIZEOBJARGPROC), // wrap_sq_item - SQ_ITEM(GetItemRootNode.class, ExternalFunctionSignature.SSIZEARGFUNC), + SQ_ITEM(GetItemNode.class, ExternalFunctionSignature.SSIZEARGFUNC), // wrap_init - INIT(MethInitRoot.class, ExternalFunctionSignature.INITPROC), + INIT(MethInit.class, ExternalFunctionSignature.INITPROC), // wrap_hashfunc - HASHFUNC(MethLenfuncRoot.class, ExternalFunctionSignature.HASHFUNC), + HASHFUNC(MethLenfunc.class, ExternalFunctionSignature.HASHFUNC), // wrap_call - CALL(MethInitRoot.class, ExternalFunctionSignature.TERNARYFUNC), + CALL(MethInit.class, ExternalFunctionSignature.TERNARYFUNC), // wrap_setattr - SETATTRO(SetAttrOFuncRootNode.class, ExternalFunctionSignature.SETATTROFUNC), + SETATTRO(SetAttrOFuncNode.class, ExternalFunctionSignature.SETATTROFUNC), - DESCR_GET(DescrGetRootNode.class, ExternalFunctionSignature.DESCRGETFUNC, 1), + DESCR_GET(DescrGetNode.class, ExternalFunctionSignature.DESCRGETFUNC, 1), // wrap_descr_set - DESCR_SET(MethDescrSetRoot.class, ExternalFunctionSignature.DESCRSETFUNC), + DESCR_SET(MethDescrSet.class, ExternalFunctionSignature.DESCRSETFUNC), // wrap_lenfunc - LENFUNC(MethLenfuncRoot.class, ExternalFunctionSignature.LENFUNC), + LENFUNC(MethLenfunc.class, ExternalFunctionSignature.LENFUNC), // wrap_objobjproc - OBJOBJPROC(MethObjObjProcRoot.class, ExternalFunctionSignature.OBJOBJPROC), + OBJOBJPROC(MethObjObjProc.class, ExternalFunctionSignature.OBJOBJPROC), // wrap_objobjargproc - OBJOBJARGPROC(MethObjObjArgProcRoot.class, ExternalFunctionSignature.OBJOBJARGPROC), + OBJOBJARGPROC(MethObjObjArgProc.class, ExternalFunctionSignature.OBJOBJARGPROC), // tp_new_wrapper - NEW(MethNewRoot.class, ExternalFunctionSignature.NEWFUNC), + NEW(MethNew.class, ExternalFunctionSignature.NEWFUNC), // wrap_delitem - MP_DELITEM(MpDelItemRootNode.class, ExternalFunctionSignature.OBJOBJARGPROC), + MP_DELITEM(MpDelItemNode.class, ExternalFunctionSignature.OBJOBJARGPROC), // wrap_descr_delete - DESCR_DELETE(DescrDeleteRootNode.class, ExternalFunctionSignature.DESCRSETFUNC), + DESCR_DELETE(DescrDeleteNode.class, ExternalFunctionSignature.DESCRSETFUNC), // wrap_delattr - DELATTRO(DelAttrRootNode.class, ExternalFunctionSignature.SETATTROFUNC), + DELATTRO(DelAttrNode.class, ExternalFunctionSignature.SETATTROFUNC), - INDEXARGFUNC(IndexArgFuncRootNode.class, ExternalFunctionSignature.SSIZEARGFUNC), + INDEXARGFUNC(IndexArgFuncNode.class, ExternalFunctionSignature.SSIZEARGFUNC), - GETTER(GetterRoot.class, ExternalFunctionSignature.GETTER), - SETTER(SetterRoot.class, ExternalFunctionSignature.SETTER), + GETTER(Getter.class, ExternalFunctionSignature.GETTER), + SETTER(Setter.class, ExternalFunctionSignature.SETTER), // TRAVERSEPROC(null, Int, PyObject, Pointer, Pointer); TRAVERSEPROC(null, null); - final Class rootNodeClass; + final Class rootNodeClass; public final ExternalFunctionSignature signature; public final int numDefaults; - PExternalFunctionWrapper(Class rootNodeClass, ExternalFunctionSignature signature) { + PExternalFunctionWrapper(Class rootNodeClass, ExternalFunctionSignature signature) { this(rootNodeClass, signature, 0); } - PExternalFunctionWrapper(Class rootNodeClass, ExternalFunctionSignature signature, int numDefaults) { + PExternalFunctionWrapper(Class rootNodeClass, ExternalFunctionSignature signature, int numDefaults) { this.rootNodeClass = rootNodeClass; this.signature = signature; this.numDefaults = numDefaults; @@ -409,8 +409,8 @@ public static BuiltinFunctionRootNode getOrCreateRootNode(PExternalFunctionWrapp } static ExternalFunctionWrapperFactory createFactory(PExternalFunctionWrapper sig, TruffleString name) { - return new ExternalFunctionWrapperFactory(WrapperDescriptorRootNodesGen.getNodeClass(sig), WrapperDescriptorRootNodesGen.getSignature(sig), name, - () -> WrapperDescriptorRootNodesGen.create(name, sig)); + return new ExternalFunctionWrapperFactory(WrapperDescriptorNodesGen.getNodeClass(sig), WrapperDescriptorNodesGen.getSignature(sig), name, + () -> WrapperDescriptorNodesGen.create(name, sig)); } /** @@ -504,14 +504,14 @@ private static Signature createSignatureWithClosure(boolean takesVarKeywordArgs, } @Builtin(needsFrame = true, declaresExplicitSelf = true, autoRegister = false) - public abstract static class WrapperBaseRoot extends PythonBuiltinFrameArgsNode { + public abstract static class WrapperBase extends PythonBuiltinFrameArgsNode { @Child private ReadIndexedArgumentNode readSelfNode; @Child private ReadIndexedArgumentNode readCallableNode; @Child private EnsurePythonObjectNode ensurePythonObjectNode; protected final TruffleString name; - WrapperBaseRoot(TruffleString name, boolean isStatic) { + WrapperBase(TruffleString name, boolean isStatic) { CompilerAsserts.neverPartOfCompilation(); this.name = name; if (!isStatic) { @@ -558,14 +558,14 @@ protected final Object readSelf(VirtualFrame frame) { * Base class for all native {@link PythonBuiltinClassType#PBuiltinFunction} (CPython type * {@code PyMethodDescr_Type}) functions. */ - public abstract static class MethodDescriptorRoot extends WrapperBaseRoot { + public abstract static class MethodDescriptor extends WrapperBase { @Child private GetThreadStateNode getThreadStateNode; @Child private NativeToPythonReturnNode nativeToPythonReturnNode; @Child private PyObjectCheckFunctionResultNode checkResultNode; final CApiTiming timing; - MethodDescriptorRoot(TruffleString name, boolean isStatic, MethodDescriptorWrapper wrapper) { + MethodDescriptor(TruffleString name, boolean isStatic, MethodDescriptorWrapper wrapper) { super(name, isStatic); assert wrapper.returnValue == PyObject; this.timing = CApiTiming.create(true, name); @@ -594,11 +594,11 @@ final Object nativeToPython(PythonContext context, long lresult) { * {@code PyWrapperDescr_Type}) functions. Those are used for the slot wrapper functions of C * function type {@code wrapperfunc}. */ - public abstract static class WrapperDescriptorRoot extends WrapperBaseRoot { + public abstract static class WrapperDescriptor extends WrapperBase { private final BranchProfile exceptionProfile = BranchProfile.create(); - WrapperDescriptorRoot(TruffleString name, @SuppressWarnings("unused") PExternalFunctionWrapper wrapper) { + WrapperDescriptor(TruffleString name, @SuppressWarnings("unused") PExternalFunctionWrapper wrapper) { super(name, false); } @@ -624,11 +624,11 @@ private void transformExceptionFromNative(PythonContext context, boolean strict) /** * Base class for wrapper functions that return an object (i.e. {@code PyObject*}). */ - public abstract static class ObjectWrapperDescriptorRoot extends WrapperDescriptorRoot { + public abstract static class ObjectWrapperDescriptor extends WrapperDescriptor { @Child private NativeToPythonReturnNode nativeToPythonReturnNode; - ObjectWrapperDescriptorRoot(TruffleString name, PExternalFunctionWrapper wrapper) { + ObjectWrapperDescriptor(TruffleString name, PExternalFunctionWrapper wrapper) { super(name, wrapper); // SETATTR retains its existing integer-return invocation through this shared body. assert wrapper.signature.returnValue == PyObject || wrapper == SETATTR; @@ -651,7 +651,7 @@ final Object returnNativeObjectToPython(long lresult) { } } - public static final class MethVarargsRoot extends PyCFunctionRootNode { + public static final class MethVarargs extends PyCFunctionNode { static final Signature SIGNATURE = createSignature(false, 1, tsArray("self"), true, true); @Child private ReadVarArgsNode readVarargsNode; @Child private PythonToNativeNode argsTupleToNativeNode; @@ -660,7 +660,7 @@ public static final class MethVarargsRoot extends PyCFunctionRootNode { @CompilationFinal private boolean seenNativeArgsTupleStorage; - public MethVarargsRoot(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { + public MethVarargs(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { super(name, isStatic, provider); this.readVarargsNode = ReadVarArgsNode.create(SIGNATURE.varArgsPArgumentsIndex()); this.argsTupleToNativeNode = PythonToNativeNode.create(); @@ -718,7 +718,7 @@ public Signature getSignature() { } } - static final class MethKeywordsRoot extends MethodDescriptorRoot { + static final class MethKeywords extends MethodDescriptor { static final Signature SIGNATURE = createSignature(true, 1, tsArray("self"), true, true); @Child private ReadVarArgsNode readVarargsNode; @@ -733,7 +733,7 @@ static final class MethKeywordsRoot extends MethodDescriptorRoot { @CompilationFinal private boolean seenNativeArgsTupleStorage; - public MethKeywordsRoot(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { + public MethKeywords(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { super(name, isStatic, provider); } @@ -770,7 +770,7 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati return nativeToPython(context, l); } finally { Reference.reachabilityFence(self); - boolean hadNativeSequenceStorage = MethVarargsRoot.postprocessArgsTuple(managedArgsTuple, argsTuplePtr, args, freeNode); + boolean hadNativeSequenceStorage = MethVarargs.postprocessArgsTuple(managedArgsTuple, argsTuplePtr, args, freeNode); if (!seenNativeArgsTupleStorage && hadNativeSequenceStorage) { CompilerDirectives.transferToInterpreterAndInvalidate(); seenNativeArgsTupleStorage = true; @@ -800,7 +800,7 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_unaryfunc}. */ @CApiWrapperDescriptor(value = UNARYFUNC) - abstract static class MethUnaryFunc extends ObjectWrapperDescriptorRoot { + abstract static class MethUnaryFunc extends ObjectWrapperDescriptor { static final Signature SIGNATURE = createSignature(false, -1, tsArray("self"), true, false); protected MethUnaryFunc(TruffleString name, PExternalFunctionWrapper provider) { @@ -822,8 +822,8 @@ public Signature getSignature() { } } - public abstract static class MethNewOrCallRoot extends ObjectWrapperDescriptorRoot { - static final Signature SIGNATURE = MethKeywordsRoot.SIGNATURE; + public abstract static class MethNewOrCall extends ObjectWrapperDescriptor { + static final Signature SIGNATURE = MethKeywords.SIGNATURE; @Child ReadVarArgsNode readVarargsNode; @Child ReadVarKeywordsNode readKwargsNode; @Child PythonToNativeNode argsTupleToNativeNode; @@ -832,7 +832,7 @@ public abstract static class MethNewOrCallRoot extends ObjectWrapperDescriptorRo @CompilationFinal boolean seenNativeArgsTupleStorage; - public MethNewOrCallRoot(TruffleString name, PExternalFunctionWrapper provider) { + public MethNewOrCall(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); this.readVarargsNode = ReadVarArgsNode.create(SIGNATURE.varArgsPArgumentsIndex()); this.readKwargsNode = ReadVarKeywordsNode.create(SIGNATURE.varKeywordsPArgumentsIndex()); @@ -895,12 +895,12 @@ static void check(Object owner, Object cls, } @CApiWrapperDescriptor(value = NEW) - abstract static class MethNewRoot extends MethNewOrCallRoot { + abstract static class MethNew extends MethNewOrCall { @Child private ValidateNewArgumentNode validateNewArgumentNode; private final BranchProfile noArgumentsProfile = BranchProfile.create(); - public MethNewRoot(TruffleString name, PExternalFunctionWrapper provider) { + public MethNew(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); } @@ -945,7 +945,7 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati try { return returnNativeObjectToPython(invokeExternalFunction(frame, boundFunction, self, argsTuplePtr, kwargsDict)); } finally { - boolean hadNativeSequenceStorage = MethVarargsRoot.postprocessArgsTuple(managedArgsTuple, argsTuplePtr, args, freeNode); + boolean hadNativeSequenceStorage = MethVarargs.postprocessArgsTuple(managedArgsTuple, argsTuplePtr, args, freeNode); if (!seenNativeArgsTupleStorage && hadNativeSequenceStorage) { CompilerDirectives.transferToInterpreterAndInvalidate(); seenNativeArgsTupleStorage = true; @@ -956,9 +956,9 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati } @CApiWrapperDescriptor(value = CALL) - abstract static class MethCallRoot extends MethNewOrCallRoot { + abstract static class MethCall extends MethNewOrCall { - public MethCallRoot(TruffleString name, PExternalFunctionWrapper provider) { + public MethCall(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); } @@ -989,7 +989,7 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati try { return returnNativeObjectToPython(invokeExternalFunction(frame, boundFunction, self, argsTuplePtr, kwargsDict)); } finally { - boolean hadNativeSequenceStorage = MethVarargsRoot.postprocessArgsTuple(managedArgsTuple, argsTuplePtr, args, freeNode); + boolean hadNativeSequenceStorage = MethVarargs.postprocessArgsTuple(managedArgsTuple, argsTuplePtr, args, freeNode); if (!seenNativeArgsTupleStorage && hadNativeSequenceStorage) { CompilerDirectives.transferToInterpreterAndInvalidate(); seenNativeArgsTupleStorage = true; @@ -1000,8 +1000,8 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati } @CApiWrapperDescriptor(value = INIT) - abstract static class MethInitRoot extends WrapperDescriptorRoot { - static final Signature SIGNATURE = MethKeywordsRoot.SIGNATURE; + abstract static class MethInit extends WrapperDescriptor { + static final Signature SIGNATURE = MethKeywords.SIGNATURE; @Child private ReadVarArgsNode readVarargsNode; @Child private ReadVarKeywordsNode readKwargsNode; @@ -1011,7 +1011,7 @@ abstract static class MethInitRoot extends WrapperDescriptorRoot { @CompilationFinal boolean seenNativeArgsTupleStorage; - public MethInitRoot(TruffleString name, PExternalFunctionWrapper provider) { + public MethInit(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); this.readVarargsNode = ReadVarArgsNode.create(SIGNATURE.varArgsPArgumentsIndex()); this.readKwargsNode = ReadVarKeywordsNode.create(SIGNATURE.varKeywordsPArgumentsIndex()); @@ -1050,7 +1050,7 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati } return PNone.NONE; } finally { - boolean hadNativeSequenceStorage = MethVarargsRoot.postprocessArgsTuple(managedArgsTuple, argsTuplePtr, args, freeNode); + boolean hadNativeSequenceStorage = MethVarargs.postprocessArgsTuple(managedArgsTuple, argsTuplePtr, args, freeNode); if (!seenNativeArgsTupleStorage && hadNativeSequenceStorage) { CompilerDirectives.transferToInterpreterAndInvalidate(); seenNativeArgsTupleStorage = true; @@ -1067,10 +1067,10 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_inquirypred}. */ @CApiWrapperDescriptor(value = INQUIRYPRED) - public abstract static class MethInquiryRoot extends WrapperDescriptorRoot { + public abstract static class MethInquiry extends WrapperDescriptor { static final Signature SIGNATURE = createSignature(false, -1, tsArray("self"), true, false); - public MethInquiryRoot(TruffleString name, PExternalFunctionWrapper provider) { + public MethInquiry(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); } @@ -1093,10 +1093,10 @@ public Signature getSignature() { } } - static final class MethNoargsRoot extends PyCFunctionRootNode { + static final class MethNoargs extends PyCFunctionNode { static final Signature SIGNATURE = createSignature(false, -1, tsArray("self"), true, true); - public MethNoargsRoot(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { + public MethNoargs(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { super(name, isStatic, provider); } @@ -1113,12 +1113,12 @@ public Signature getSignature() { } } - abstract static class PyCFunctionRootNode extends MethodDescriptorRoot { + abstract static class PyCFunctionNode extends MethodDescriptor { @Child private BoundaryCallData boundaryCallData; @Child private PythonToNativeNode selfToNativeNode; - public PyCFunctionRootNode(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { + public PyCFunctionNode(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { super(name, isStatic, provider); } @@ -1145,12 +1145,12 @@ private void createNodes() { } } - public static final class MethORoot extends PyCFunctionRootNode { + public static final class MethO extends PyCFunctionNode { static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "arg"), true, true); @Child private ReadIndexedArgumentNode readArgNode; @Child private PythonToNativeNode argToNativeNode; - public MethORoot(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { + public MethO(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { super(name, isStatic, provider); this.readArgNode = ReadIndexedArgumentNode.create(1); this.argToNativeNode = PythonToNativeNode.create(); @@ -1173,12 +1173,12 @@ public Signature getSignature() { } } - static final class MethFastcallWithKeywordsRoot extends MethodDescriptorRoot { + static final class MethFastcallWithKeywords extends MethodDescriptor { /* * METH_KEYWORDS and METH_FASTCALL|METH_KEYWORDS have the same Python-level signature but * invoke a different C function signature. */ - static final Signature SIGNATURE = MethKeywordsRoot.SIGNATURE; + static final Signature SIGNATURE = MethKeywords.SIGNATURE; @Child private ReadVarArgsNode readVarargsNode; @Child private ReadVarKeywordsNode readKwargsNode; @@ -1189,7 +1189,7 @@ static final class MethFastcallWithKeywordsRoot extends MethodDescriptorRoot { @Child private CreateNativeKwNamesTupleNode createNativeKwNamesTupleNode; @Child private ReleaseNativeArgsTupleNode releaseNativeKwNamesTupleNode; - public MethFastcallWithKeywordsRoot(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { + public MethFastcallWithKeywords(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { super(name, isStatic, provider); } @@ -1228,16 +1228,16 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati kwnamesTuplePtr = createNativeKwNamesTupleNode.execute(context, fastcallKwnames); } LoopNode.reportLoopCount(this, fastcallArgs.length); - long nativeFastcallArgs = MethFastcallRoot.createFastcallArgsArray(this, fastcallArgs, argToNativeNode); + long nativeFastcallArgs = MethFastcall.createFastcallArgsArray(this, fastcallArgs, argToNativeNode); try { long l = ExternalFunctionInvoker.invokePYCFUNCTION_FAST_WITH_KEYWORDS(frame, timing, context.ensureNativeContext(), boundaryCallData, ensureGetThreadStateNode().executeCached(context), boundFunction, argToNativeNode.execute(self), nativeFastcallArgs, args.length, kwnamesTuplePtr); return nativeToPython(context, l); } finally { - MethFastcallRoot.freeFastcallArgsArray(nativeFastcallArgs); + MethFastcall.freeFastcallArgsArray(nativeFastcallArgs); if (fastcallKwnames != null) { - MethVarargsRoot.postprocessArgsTuple(null, kwnamesTuplePtr, fastcallKwnames, releaseNativeKwNamesTupleNode); + MethVarargs.postprocessArgsTuple(null, kwnamesTuplePtr, fastcallKwnames, releaseNativeKwNamesTupleNode); } Reference.reachabilityFence(self); Reference.reachabilityFence(fastcallArgs); @@ -1262,7 +1262,7 @@ public Signature getSignature() { } } - static final class MethMethodRoot extends MethodDescriptorRoot { + static final class MethMethod extends MethodDescriptor { static final Signature SIGNATURE = createSignature(true, 1, tsArray("self", "cls"), true, true); @Child private ReadIndexedArgumentNode readClsNode; @@ -1273,7 +1273,7 @@ static final class MethMethodRoot extends MethodDescriptorRoot { @Child private PythonToNativeNode argToNativeNode; @Child private PythonToNativeNode kwNamesToNativeNode; - public MethMethodRoot(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { + public MethMethod(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { super(name, isStatic, provider); } @@ -1311,14 +1311,14 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati kwnamesTuple = PFactory.createTuple(context.getLanguage(), fastcallKwnames); } LoopNode.reportLoopCount(this, fastcallArgs.length); - long nativeFastcallArgs = MethFastcallRoot.createFastcallArgsArray(this, fastcallArgs, argToNativeNode); + long nativeFastcallArgs = MethFastcall.createFastcallArgsArray(this, fastcallArgs, argToNativeNode); try { long l = ExternalFunctionInvoker.invokePYCMETHOD(frame, timing, context.ensureNativeContext(), boundaryCallData, ensureGetThreadStateNode().executeCached(context), boundFunction, argToNativeNode.execute(self), argToNativeNode.execute(cls), nativeFastcallArgs, args.length, kwNamesToNativeNode.execute(kwnamesTuple)); return nativeToPython(context, l); } finally { - MethFastcallRoot.freeFastcallArgsArray(nativeFastcallArgs); + MethFastcall.freeFastcallArgsArray(nativeFastcallArgs); Reference.reachabilityFence(self); Reference.reachabilityFence(fastcallArgs); Reference.reachabilityFence(kwnamesTuple); @@ -1341,19 +1341,19 @@ public Signature getSignature() { } } - static final class MethFastcallRoot extends MethodDescriptorRoot { + static final class MethFastcall extends MethodDescriptor { /* * METH_VARARGS and METH_FASTCALL have the same Python-level signature but invoke a * different C function signature. */ - static final Signature SIGNATURE = MethVarargsRoot.SIGNATURE; + static final Signature SIGNATURE = MethVarargs.SIGNATURE; @Child private ReadVarArgsNode readVarargsNode; @Child private BoundaryCallData boundaryCallData; @Child private PythonToNativeNode argToNativeNode; - public MethFastcallRoot(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { + public MethFastcall(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { super(name, isStatic, provider); } @@ -1433,12 +1433,12 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_indexargfunc}. */ @CApiWrapperDescriptor(value = INDEXARGFUNC) - public abstract static class IndexArgFuncRootNode extends ObjectWrapperDescriptorRoot { + public abstract static class IndexArgFuncNode extends ObjectWrapperDescriptor { static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "i"), true, false); @Child private ReadIndexedArgumentNode readINode; @Child private PyNumberAsSizeNode asSizeNode; - IndexArgFuncRootNode(TruffleString name, PExternalFunctionWrapper provider) { + IndexArgFuncNode(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); this.readINode = ReadIndexedArgumentNode.create(1); this.asSizeNode = PyNumberAsSizeNode.create(); @@ -1464,13 +1464,13 @@ public Signature getSignature() { * Wrapper root node for a get attribute function (C type {@code getattrfunc}). */ @CApiWrapperDescriptor(value = GETATTR) - public abstract static class GetAttrFuncRootNode extends ObjectWrapperDescriptorRoot { - private static final TruffleLogger LOGGER = CApiContext.getLogger(GetAttrFuncRootNode.class); + public abstract static class GetAttrFuncNode extends ObjectWrapperDescriptor { + private static final TruffleLogger LOGGER = CApiContext.getLogger(GetAttrFuncNode.class); static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "key"), true, false); @Child private ReadIndexedArgumentNode readArgNode; @Child private AsCharPointerNode asCharPointerNode; - GetAttrFuncRootNode(TruffleString name, PExternalFunctionWrapper provider) { + GetAttrFuncNode(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); this.readArgNode = ReadIndexedArgumentNode.create(1); this.asCharPointerNode = AsCharPointerNodeGen.create(); @@ -1503,14 +1503,14 @@ public Signature getSignature() { * Wrapper root node for a set attribute function (C type {@code setattrfunc}). */ @CApiWrapperDescriptor(value = SETATTR) - public abstract static class SetAttrFuncRootNode extends ObjectWrapperDescriptorRoot { - private static final TruffleLogger LOGGER = CApiContext.getLogger(SetAttrFuncRootNode.class); + public abstract static class SetAttrFuncNode extends ObjectWrapperDescriptor { + private static final TruffleLogger LOGGER = CApiContext.getLogger(SetAttrFuncNode.class); static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "key", "value"), true, false); @Child private ReadIndexedArgumentNode readArg1Node; @Child private ReadIndexedArgumentNode readArg2Node; @Child private AsCharPointerNode asCharPointerNode; - SetAttrFuncRootNode(TruffleString name, PExternalFunctionWrapper provider) { + SetAttrFuncNode(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); this.readArg1Node = ReadIndexedArgumentNode.create(1); this.readArg2Node = ReadIndexedArgumentNode.create(2); @@ -1544,12 +1544,12 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_setattr} */ @CApiWrapperDescriptor(value = SETATTRO) - public abstract static class SetAttrOFuncRootNode extends WrapperDescriptorRoot { + public abstract static class SetAttrOFuncNode extends WrapperDescriptor { static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "name", "value"), true, false); @Child private ReadIndexedArgumentNode readNameNode; @Child private ReadIndexedArgumentNode readValueNode; - SetAttrOFuncRootNode(TruffleString name, PExternalFunctionWrapper provider) { + SetAttrOFuncNode(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); this.readNameNode = ReadIndexedArgumentNode.create(1); this.readValueNode = ReadIndexedArgumentNode.create(2); @@ -1584,12 +1584,12 @@ public Signature getSignature() { * {@code tp_richcompare}. */ @CApiWrapperDescriptor(value = RICHCMP) - public abstract static class RichCmpFuncRootNode extends ObjectWrapperDescriptorRoot { + public abstract static class RichCmpFuncNode extends ObjectWrapperDescriptor { static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "other", "op"), true, false); @Child private ReadIndexedArgumentNode readOtherNode; @Child private ReadIndexedArgumentNode readOpNode; - RichCmpFuncRootNode(TruffleString name, PExternalFunctionWrapper provider) { + RichCmpFuncNode(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); this.readOtherNode = ReadIndexedArgumentNode.create(1); this.readOpNode = ReadIndexedArgumentNode.create(2); @@ -1615,12 +1615,12 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_sq_item}. */ @CApiWrapperDescriptor(value = SQ_ITEM) - public abstract static class GetItemRootNode extends ObjectWrapperDescriptorRoot { + public abstract static class GetItemNode extends ObjectWrapperDescriptor { static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "i"), true, false); @Child private ReadIndexedArgumentNode readArg1Node; @Child private GetIndexNode getIndexNode; - GetItemRootNode(TruffleString name, PExternalFunctionWrapper provider) { + GetItemNode(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); this.readArg1Node = ReadIndexedArgumentNode.create(1); this.getIndexNode = GetIndexNode.create(); @@ -1645,13 +1645,13 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_sq_setitem}. */ @CApiWrapperDescriptor(value = SQ_SETITEM) - public abstract static class SetItemRootNode extends WrapperDescriptorRoot { + public abstract static class SetItemNode extends WrapperDescriptor { static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "i", "value"), true, false); @Child private ReadIndexedArgumentNode readArg1Node; @Child private ReadIndexedArgumentNode readArg2Node; @Child private GetIndexNode getIndexNode; - SetItemRootNode(TruffleString name, PExternalFunctionWrapper provider) { + SetItemNode(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); this.readArg1Node = ReadIndexedArgumentNode.create(1); this.readArg2Node = ReadIndexedArgumentNode.create(2); @@ -1681,12 +1681,12 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_sq_delitem}. */ @CApiWrapperDescriptor(value = SQ_DELITEM) - public abstract static class SqDelItemRootNode extends WrapperDescriptorRoot { + public abstract static class SqDelItemNode extends WrapperDescriptor { static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "key"), true, false); @Child private ReadIndexedArgumentNode readKeyNode; @Child private GetIndexNode getIndexNode; - SqDelItemRootNode(TruffleString name, PExternalFunctionWrapper provider) { + SqDelItemNode(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); this.readKeyNode = ReadIndexedArgumentNode.create(1); this.getIndexNode = GetIndexNode.create(); @@ -1716,12 +1716,12 @@ public Signature getSignature() { * Implements semantics of {@code typeobject.c:wrap_descr_get} */ @CApiWrapperDescriptor(value = DESCR_GET) - public abstract static class DescrGetRootNode extends ObjectWrapperDescriptorRoot { + public abstract static class DescrGetNode extends ObjectWrapperDescriptor { static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "obj", "type"), true, false); @Child private ReadIndexedArgumentNode readObj; @Child private ReadIndexedArgumentNode readType; - public DescrGetRootNode(TruffleString name, PExternalFunctionWrapper provider) { + public DescrGetNode(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); this.readObj = ReadIndexedArgumentNode.create(1); this.readType = ReadIndexedArgumentNode.create(2); @@ -1749,11 +1749,11 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_descr_delete} */ @CApiWrapperDescriptor(value = DESCR_DELETE) - public abstract static class DescrDeleteRootNode extends WrapperDescriptorRoot { + public abstract static class DescrDeleteNode extends WrapperDescriptor { static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "obj"), true, false); @Child private ReadIndexedArgumentNode readObj; - public DescrDeleteRootNode(TruffleString name, PExternalFunctionWrapper provider) { + public DescrDeleteNode(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); this.readObj = ReadIndexedArgumentNode.create(1); } @@ -1780,11 +1780,11 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_delattr}. */ @CApiWrapperDescriptor(value = DELATTRO) - public abstract static class DelAttrRootNode extends WrapperDescriptorRoot { + public abstract static class DelAttrNode extends WrapperDescriptor { static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "obj"), true, false); @Child private ReadIndexedArgumentNode readObj; - public DelAttrRootNode(TruffleString name, PExternalFunctionWrapper provider) { + public DelAttrNode(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); this.readObj = ReadIndexedArgumentNode.create(1); } @@ -1812,11 +1812,11 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_delitem}. */ @CApiWrapperDescriptor(value = MP_DELITEM) - public abstract static class MpDelItemRootNode extends WrapperDescriptorRoot { + public abstract static class MpDelItemNode extends WrapperDescriptor { static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "key"), true, false); @Child private ReadIndexedArgumentNode readKeyNode; - MpDelItemRootNode(TruffleString name, PExternalFunctionWrapper provider) { + MpDelItemNode(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); this.readKeyNode = ReadIndexedArgumentNode.create(1); } @@ -1846,7 +1846,7 @@ public Signature getSignature() { * {@code typeobject.c: wrap_ternaryfunc_r}. */ @CApiWrapperDescriptor(value = {TERNARYFUNC, TERNARYFUNC_R}) - public abstract static class MethTernaryFuncRoot extends ObjectWrapperDescriptorRoot { + public abstract static class MethTernaryFunc extends ObjectWrapperDescriptor { static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "other", "third"), false, false); @Child private ReadIndexedArgumentNode readArg1Node; @@ -1854,7 +1854,7 @@ public abstract static class MethTernaryFuncRoot extends ObjectWrapperDescriptor private final boolean reverse; - MethTernaryFuncRoot(TruffleString name, PExternalFunctionWrapper provider) { + MethTernaryFunc(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); this.readArg1Node = ReadIndexedArgumentNode.create(1); this.readArg2Node = ReadIndexedArgumentNode.create(2); @@ -1896,14 +1896,14 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_richcmpfunc} */ @CApiWrapperDescriptor(value = {GT, GE, LE, LT, EQ, NE}) - public abstract static class MethRichcmpOpRootNode extends ObjectWrapperDescriptorRoot { + public abstract static class MethRichcmpOpNode extends ObjectWrapperDescriptor { static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "other"), true, false); @Child private ReadIndexedArgumentNode readArgNode; private final int op; - MethRichcmpOpRootNode(TruffleString name, PExternalFunctionWrapper provider) { + MethRichcmpOpNode(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); this.readArgNode = ReadIndexedArgumentNode.create(1); this.op = getCompareOpCode(provider); @@ -1940,12 +1940,12 @@ private static int getCompareOpCode(PExternalFunctionWrapper sig) { /** Implements semantics of {@code typeobject.c: wrap_next}. */ @CApiWrapperDescriptor(value = ITERNEXT) - public abstract static class IterNextFuncRootNode extends ObjectWrapperDescriptorRoot { - static final Signature SIGNATURE = MethNoargsRoot.SIGNATURE; + public abstract static class IterNextFuncNode extends ObjectWrapperDescriptor { + static final Signature SIGNATURE = MethNoargs.SIGNATURE; @Child private CheckIterNextResultNode checkIterNextResultNode; - IterNextFuncRootNode(TruffleString name, PExternalFunctionWrapper provider) { + IterNextFuncNode(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); this.checkIterNextResultNode = CheckIterNextResultNodeGen.create(); } @@ -1964,7 +1964,7 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati @Override public Signature getSignature() { // same signature as a method without arguments (just the self) - return MethNoargsRoot.SIGNATURE; + return MethNoargs.SIGNATURE; } } @@ -1972,12 +1972,12 @@ public Signature getSignature() { * Wrapper root node for C function type {@code getter}. */ @CApiWrapperDescriptor(value = GETTER) - public abstract static class GetterRoot extends ObjectWrapperDescriptorRoot { + public abstract static class Getter extends ObjectWrapperDescriptor { static final Signature SIGNATURE = createSignatureWithClosure(false, -1, tsArray("self"), true, false); @Child private ReadIndexedArgumentNode readClosureNode; - public GetterRoot(TruffleString name, PExternalFunctionWrapper provider) { + public Getter(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); } @@ -2011,13 +2011,13 @@ public Signature getSignature() { * Wrapper root node for C function type {@code setter}. */ @CApiWrapperDescriptor(value = SETTER) - public abstract static class SetterRoot extends WrapperDescriptorRoot { + public abstract static class Setter extends WrapperDescriptor { static final Signature SIGNATURE = createSignatureWithClosure(false, -1, tsArray("self", "value"), true, false); @Child private ReadIndexedArgumentNode readClosureNode; @Child private ReadIndexedArgumentNode readArgNode; - public SetterRoot(TruffleString name, PExternalFunctionWrapper provider) { + public Setter(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); } @@ -2030,7 +2030,7 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati Object arg = ensurePythonObject(ensureReadArgNode().execute(frame)); if (readClosureNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - readClosureNode = insert(GetterRoot.createReadClosureNode(SIGNATURE)); + readClosureNode = insert(Getter.createReadClosureNode(SIGNATURE)); } long closure = (long) readClosureNode.execute(frame); if (invokeExternalFunction(frame, boundFunction, self, arg, closure) < 0) { @@ -2055,10 +2055,10 @@ private ReadIndexedArgumentNode ensureReadArgNode() { /** Implements semantics of {@code typeobject.c: wrap_lenfunc} */ @CApiWrapperDescriptor(value = {LENFUNC, HASHFUNC}) - public abstract static class MethLenfuncRoot extends WrapperDescriptorRoot { + public abstract static class MethLenfunc extends WrapperDescriptor { static final Signature SIGNATURE = createSignature(false, -1, tsArray("self"), true, false); - public MethLenfuncRoot(TruffleString name, PExternalFunctionWrapper provider) { + public MethLenfunc(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); } @@ -2083,12 +2083,12 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_objobjproc}. */ @CApiWrapperDescriptor(value = OBJOBJPROC) - public abstract static class MethObjObjProcRoot extends WrapperDescriptorRoot { + public abstract static class MethObjObjProc extends WrapperDescriptor { static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "value"), true, false); @Child private ReadIndexedArgumentNode readValueNode; - MethObjObjProcRoot(TruffleString name, PExternalFunctionWrapper provider) { + MethObjObjProc(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); this.readValueNode = ReadIndexedArgumentNode.create(1); } @@ -2116,13 +2116,13 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_objobjargproc}. */ @CApiWrapperDescriptor(value = OBJOBJARGPROC) - public abstract static class MethObjObjArgProcRoot extends WrapperDescriptorRoot { + public abstract static class MethObjObjArgProc extends WrapperDescriptor { static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "key", "value"), true, false); @Child private ReadIndexedArgumentNode readKeyNode; @Child private ReadIndexedArgumentNode readValueNode; - MethObjObjArgProcRoot(TruffleString name, PExternalFunctionWrapper provider) { + MethObjObjArgProc(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); this.readKeyNode = ReadIndexedArgumentNode.create(1); this.readValueNode = ReadIndexedArgumentNode.create(2); @@ -2155,14 +2155,14 @@ public Signature getSignature() { * {@code typeobject.c: wrap_binaryfunc_r}. */ @CApiWrapperDescriptor(value = {BINARYFUNC, BINARYFUNC_L, BINARYFUNC_R}) - public abstract static class MethBinaryRoot extends ObjectWrapperDescriptorRoot { + public abstract static class MethBinary extends ObjectWrapperDescriptor { static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "other"), true, false); @Child private ReadIndexedArgumentNode readOtherNode; private final boolean reverse; - MethBinaryRoot(TruffleString name, PExternalFunctionWrapper provider) { + MethBinary(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); this.readOtherNode = ReadIndexedArgumentNode.create(1); this.reverse = provider == BINARYFUNC_R; @@ -2197,12 +2197,12 @@ public Signature getSignature() { /** Implements semantics of {@code typeobject.c: wrap_descr_set} */ @CApiWrapperDescriptor(value = DESCR_SET) - public abstract static class MethDescrSetRoot extends WrapperDescriptorRoot { + public abstract static class MethDescrSet extends WrapperDescriptor { static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "instance", "value"), true, false); @Child private ReadIndexedArgumentNode readInstanceNode; @Child private ReadIndexedArgumentNode readValueNode; - MethDescrSetRoot(TruffleString name, PExternalFunctionWrapper provider) { + MethDescrSet(TruffleString name, PExternalFunctionWrapper provider) { super(name, provider); this.readInstanceNode = ReadIndexedArgumentNode.create(1); this.readValueNode = ReadIndexedArgumentNode.create(2); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionWrapperFactory.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionWrapperFactory.java index 49d1afeb7d..a3760836f4 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionWrapperFactory.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionWrapperFactory.java @@ -47,7 +47,7 @@ import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.annotations.Builtin; import com.oracle.graal.python.annotations.PythonOS; -import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.WrapperBaseRoot; +import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.WrapperBase; import com.oracle.graal.python.builtins.objects.function.Signature; import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode; import com.oracle.truffle.api.dsl.NodeFactory; @@ -55,17 +55,17 @@ import com.oracle.truffle.api.strings.TruffleString; /** Creates configured native wrapper bodies that read their own frame arguments. */ -final class ExternalFunctionWrapperFactory implements NodeFactory { - private final Class nodeClass; +final class ExternalFunctionWrapperFactory implements NodeFactory { + private final Class nodeClass; private final Signature signature; private final Builtin builtin; - private final Supplier constructor; + private final Supplier constructor; - ExternalFunctionWrapperFactory(Class nodeClass, Signature signature, TruffleString name, - Supplier constructor) { + ExternalFunctionWrapperFactory(Class nodeClass, Signature signature, TruffleString name, + Supplier constructor) { this.nodeClass = nodeClass; this.signature = signature; - this.builtin = new NamedBuiltin(name.toJavaStringUncached(), WrapperBaseRoot.class.getAnnotation(Builtin.class)); + this.builtin = new NamedBuiltin(name.toJavaStringUncached(), WrapperBase.class.getAnnotation(Builtin.class)); this.constructor = constructor; } @@ -74,17 +74,17 @@ BuiltinFunctionRootNode createRoot(PythonLanguage language) { } @Override - public WrapperBaseRoot createNode(Object... arguments) { + public WrapperBase createNode(Object... arguments) { assert arguments.length == 0; - WrapperBaseRoot body = constructor.get(); + WrapperBase body = constructor.get(); assert nodeClass.isInstance(body); return body; } @Override @SuppressWarnings("unchecked") - public Class getNodeClass() { - return (Class) nodeClass; + public Class getNodeClass() { + return (Class) nodeClass; } @Override diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/MethodDescriptorWrapper.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/MethodDescriptorWrapper.java index fdfbd8df3b..28e3c0b81f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/MethodDescriptorWrapper.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/MethodDescriptorWrapper.java @@ -48,13 +48,13 @@ import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.annotations.ArgDescriptor; import com.oracle.graal.python.builtins.objects.PNone; -import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.MethFastcallRoot; -import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.MethFastcallWithKeywordsRoot; -import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.MethKeywordsRoot; -import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.MethMethodRoot; -import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.MethNoargsRoot; -import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.MethORoot; -import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.MethVarargsRoot; +import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.MethFastcall; +import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.MethFastcallWithKeywords; +import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.MethKeywords; +import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.MethMethod; +import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.MethNoargs; +import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.MethO; +import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.MethVarargs; import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodes; import com.oracle.graal.python.builtins.objects.cext.common.NativeCExtSymbol; import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction; @@ -123,20 +123,20 @@ static BuiltinFunctionRootNode getOrCreateRootNode(PythonLanguage language, Meth static ExternalFunctionWrapperFactory createFactory(MethodDescriptorWrapper sig, TruffleString name, boolean isStatic) { return switch (sig) { - case KEYWORDS -> new ExternalFunctionWrapperFactory(MethKeywordsRoot.class, MethKeywordsRoot.SIGNATURE, name, - () -> new MethKeywordsRoot(name, isStatic, sig)); - case VARARGS -> new ExternalFunctionWrapperFactory(MethVarargsRoot.class, MethVarargsRoot.SIGNATURE, name, - () -> new MethVarargsRoot(name, isStatic, sig)); - case NOARGS -> new ExternalFunctionWrapperFactory(MethNoargsRoot.class, MethNoargsRoot.SIGNATURE, name, - () -> new MethNoargsRoot(name, isStatic, sig)); - case O -> new ExternalFunctionWrapperFactory(MethORoot.class, MethORoot.SIGNATURE, name, - () -> new MethORoot(name, isStatic, sig)); - case FASTCALL -> new ExternalFunctionWrapperFactory(MethFastcallRoot.class, MethFastcallRoot.SIGNATURE, name, - () -> new MethFastcallRoot(name, isStatic, sig)); - case FASTCALL_WITH_KEYWORDS -> new ExternalFunctionWrapperFactory(MethFastcallWithKeywordsRoot.class, MethFastcallWithKeywordsRoot.SIGNATURE, name, - () -> new MethFastcallWithKeywordsRoot(name, isStatic, sig)); - case METHOD -> new ExternalFunctionWrapperFactory(MethMethodRoot.class, MethMethodRoot.SIGNATURE, name, - () -> new MethMethodRoot(name, isStatic, sig)); + case KEYWORDS -> new ExternalFunctionWrapperFactory(MethKeywords.class, MethKeywords.SIGNATURE, name, + () -> new MethKeywords(name, isStatic, sig)); + case VARARGS -> new ExternalFunctionWrapperFactory(MethVarargs.class, MethVarargs.SIGNATURE, name, + () -> new MethVarargs(name, isStatic, sig)); + case NOARGS -> new ExternalFunctionWrapperFactory(MethNoargs.class, MethNoargs.SIGNATURE, name, + () -> new MethNoargs(name, isStatic, sig)); + case O -> new ExternalFunctionWrapperFactory(MethO.class, MethO.SIGNATURE, name, + () -> new MethO(name, isStatic, sig)); + case FASTCALL -> new ExternalFunctionWrapperFactory(MethFastcall.class, MethFastcall.SIGNATURE, name, + () -> new MethFastcall(name, isStatic, sig)); + case FASTCALL_WITH_KEYWORDS -> new ExternalFunctionWrapperFactory(MethFastcallWithKeywords.class, MethFastcallWithKeywords.SIGNATURE, name, + () -> new MethFastcallWithKeywords(name, isStatic, sig)); + case METHOD -> new ExternalFunctionWrapperFactory(MethMethod.class, MethMethod.SIGNATURE, name, + () -> new MethMethod(name, isStatic, sig)); }; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PRootNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PRootNode.java index 13f910083c..6eda0ff777 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PRootNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PRootNode.java @@ -41,7 +41,7 @@ package com.oracle.graal.python.nodes; import com.oracle.graal.python.PythonLanguage; -import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.WrapperBaseRoot; +import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.WrapperBase; import com.oracle.graal.python.builtins.objects.frame.FrameBuiltinsFactory; import com.oracle.graal.python.builtins.objects.function.Signature; import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode; @@ -111,7 +111,7 @@ public int getCallerFlags() { public void updateCallerFlags(int flags) { if (this instanceof BuiltinFunctionRootNode functionRootNode && !(functionRootNode.getFactory() instanceof FrameBuiltinsFactory.GetLocalsNodeFactory) && - !WrapperBaseRoot.class.isAssignableFrom(functionRootNode.getFactory().getNodeClass())) { + !WrapperBase.class.isAssignableFrom(functionRootNode.getFactory().getNodeClass())) { /* * Our callee-side tracking of the caller flags is too broad and causes "poisoning" of common builtins that * are calling many other things, like object.__getattribute__ or type.__new__. For materialized frames this diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/AbstractCallMethodNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/AbstractCallMethodNode.java index bb25049c36..49606ee87e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/AbstractCallMethodNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/AbstractCallMethodNode.java @@ -76,7 +76,7 @@ public static PythonBuiltinBaseNode getBuiltin(VirtualFrame frame, PBuiltinFunct CompilerAsserts.neverPartOfCompilation(); NodeFactory builtinNodeFactory = func.getBuiltinNodeFactory(); if (builtinNodeFactory == null) { - return null; // see for example MethodDescriptorRoot and subclasses + return null; // see for example MethodDescriptor and subclasses } if (TpSlotBuiltin.isSlotFactory(builtinNodeFactory)) { // slot wrapper must perform validation implemented in WrapperDescrCall inside the diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/BuiltinFunctionRootNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/BuiltinFunctionRootNode.java index b2a78cd987..44bd145888 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/BuiltinFunctionRootNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/BuiltinFunctionRootNode.java @@ -36,7 +36,7 @@ import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.annotations.Builtin; import com.oracle.graal.python.builtins.PythonBuiltinClassType; -import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.WrapperBaseRoot; +import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.WrapperBase; import com.oracle.graal.python.builtins.objects.function.Signature; import com.oracle.graal.python.nodes.PRootNode; import com.oracle.graal.python.nodes.argument.ReadArgumentNode; @@ -102,7 +102,7 @@ public BuiltinFunctionRootNode(PythonLanguage language, Signature signature, Bui this.factory = factory; this.declaresExplicitSelf = declaresExplicitSelf; this.wrapsSlotForClass = wrapsSlotForClass; - this.isCaptureForTraces = WrapperBaseRoot.class.isAssignableFrom(factory.getNodeClass()); + this.isCaptureForTraces = WrapperBase.class.isAssignableFrom(factory.getNodeClass()); if (builtin.callerFlags() != 0) { updateCallerFlags(builtin.callerFlags()); } From fa0094584e60f798cf2d716e6fbc2eda442841fb Mon Sep 17 00:00:00 2001 From: stepan Date: Tue, 3 Nov 2026 12:32:18 +0100 Subject: [PATCH 5/6] Define native wrapper builtin metadata explicitly --- .../cext/capi/ExternalFunctionNodes.java | 2 - .../capi/ExternalFunctionWrapperFactory.java | 50 +++++++++---------- 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java index c1324cce83..1dc2d0ccff 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java @@ -97,7 +97,6 @@ import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.annotations.ArgDescriptor; -import com.oracle.graal.python.annotations.Builtin; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject; @@ -503,7 +502,6 @@ private static Signature createSignatureWithClosure(boolean takesVarKeywordArgs, return new Signature(-1, takesVarKeywordArgs, varArgIndex, parameters, KEYWORDS_HIDDEN_CALLABLE_AND_CLOSURE, checkEnclosingType, T_EMPTY_STRING, hidden); } - @Builtin(needsFrame = true, declaresExplicitSelf = true, autoRegister = false) public abstract static class WrapperBase extends PythonBuiltinFrameArgsNode { @Child private ReadIndexedArgumentNode readSelfNode; @Child private ReadIndexedArgumentNode readCallableNode; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionWrapperFactory.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionWrapperFactory.java index a3760836f4..0e3ffbc3e4 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionWrapperFactory.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionWrapperFactory.java @@ -65,7 +65,7 @@ final class ExternalFunctionWrapperFactory implements NodeFactory { Supplier constructor) { this.nodeClass = nodeClass; this.signature = signature; - this.builtin = new NamedBuiltin(name.toJavaStringUncached(), WrapperBase.class.getAnnotation(Builtin.class)); + this.builtin = new WrapperBuiltin(name.toJavaStringUncached()); this.constructor = constructor; } @@ -97,12 +97,8 @@ public List> getExecutionSignature() { return List.of(); } - /** Give the common wrapper metadata the enclosing root's runtime name. */ - private record NamedBuiltin(String name, Builtin annotation) implements Builtin { - NamedBuiltin { - assert annotation != null; - } - + /** Builtin metadata for native wrappers, whose argument layout is defined by the signature. */ + private record WrapperBuiltin(String name) implements Builtin { @Override public Class annotationType() { return Builtin.class; @@ -110,102 +106,102 @@ public Class annotationType() { @Override public String doc() { - return annotation.doc(); + return ""; } @Override public PythonOS os() { - return annotation.os(); + return PythonOS.PLATFORM_ANY; } @Override public int minNumOfPositionalArgs() { - return annotation.minNumOfPositionalArgs(); + return 0; } @Override public int maxNumOfPositionalArgs() { - return annotation.maxNumOfPositionalArgs(); + return -1; } @Override public int numOfPositionalOnlyArgs() { - return annotation.numOfPositionalOnlyArgs(); + return -1; } @Override public boolean isGetter() { - return annotation.isGetter(); + return false; } @Override public boolean isSetter() { - return annotation.isSetter(); + return false; } @Override public boolean allowsDelete() { - return annotation.allowsDelete(); + return false; } @Override public boolean takesVarArgs() { - return annotation.takesVarArgs(); + return false; } @Override public boolean takesVarKeywordArgs() { - return annotation.takesVarKeywordArgs(); + return false; } @Override public String[] parameterNames() { - return annotation.parameterNames(); + return new String[0]; } @Override public String[] keywordOnlyNames() { - return annotation.keywordOnlyNames(); + return new String[0]; } @Override public boolean isClassmethod() { - return annotation.isClassmethod(); + return false; } @Override public boolean isStaticmethod() { - return annotation.isStaticmethod(); + return false; } @Override public boolean needsFrame() { - return annotation.needsFrame(); + return true; } @Override public int callerFlags() { - return annotation.callerFlags(); + return 0; } @Override public boolean declaresExplicitSelf() { - return annotation.declaresExplicitSelf(); + return true; } @Override public String raiseErrorName() { - return annotation.raiseErrorName(); + return ""; } @Override public boolean forceSplitDirectCalls() { - return annotation.forceSplitDirectCalls(); + return false; } @Override public boolean autoRegister() { - return annotation.autoRegister(); + return false; } } } From 55d06ced9a1a66e94869d36121a89db71db7d4c4 Mon Sep 17 00:00:00 2001 From: stepan Date: Tue, 3 Nov 2026 22:07:46 +0100 Subject: [PATCH 6/6] Exclude recursive exception normalization test due to unreliable native stack-overflow recovery --- .../src/tests/unittest_tags/test_exceptions.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_exceptions.txt b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_exceptions.txt index 6b97ffc097..305a61ea3e 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_exceptions.txt +++ b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_exceptions.txt @@ -43,7 +43,8 @@ test.test_exceptions.ExceptionTests.test_no_hang_on_context_chain_cycle2 @ darwi test.test_exceptions.ExceptionTests.test_notes @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_exceptions.ExceptionTests.test_raise_does_not_create_context_chain_cycle @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_exceptions.ExceptionTests.test_raise_in_generator @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github -test.test_exceptions.ExceptionTests.test_recursion_normalizing_infinite_exception @ darwin-arm64,win32-AMD64 +# Recursive native exception normalization can terminate the process during stack-overflow recovery. +!test.test_exceptions.ExceptionTests.test_recursion_normalizing_infinite_exception test.test_exceptions.ExceptionTests.test_setstate @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_exceptions.ExceptionTests.test_str @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_exceptions.ExceptionTests.test_unhandled @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github