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..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"); @@ -2004,17 +2004,16 @@ 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(); 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.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 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(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(" default -> throw CompilerDirectives.shouldNotReachHere(\"no 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("}"); @@ -2327,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 new file mode 100644 index 0000000000..cb1c9aeca2 --- /dev/null +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/ExternalFunctionWrapperTest.java @@ -0,0 +1,654 @@ +/* + * 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 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; +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 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.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.WrapperBase; +import com.oracle.graal.python.builtins.objects.cext.capi.MethodDescriptorWrapper; +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.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.runtime.CallerFlags; +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("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("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() { + 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(WrapperBase 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(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()) { + 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(Getter.class, null, "createReadClosureNode", new Class[]{Signature.class}, signature)); + } + } + } + + 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<>(); + 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(WrapperBase.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); + WrapperBase body = (WrapperBase) 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()); + 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())); + 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 = WrapperBase.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(), 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)); + 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/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.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.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 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..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 @@ -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; @@ -110,7 +107,7 @@ 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; import com.oracle.graal.python.nodes.object.GetDictIfExistsNode; @@ -121,7 +118,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; @@ -419,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); } @@ -427,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); } @@ -438,15 +434,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..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 @@ -99,7 +99,6 @@ import com.oracle.graal.python.annotations.ArgDescriptor; 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; @@ -146,6 +145,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; @@ -156,9 +156,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; @@ -284,126 +285,131 @@ 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; } @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(WrapperDescriptorNodesGen.getNodeClass(sig), WrapperDescriptorNodesGen.getSignature(sig), name, + () -> WrapperDescriptorNodesGen.create(name, sig)); } /** @@ -426,7 +432,7 @@ static PRootNode getOrCreateRootNode(PExternalFunctionWrapper sig, PythonLanguag @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); @@ -496,16 +502,14 @@ 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; + public abstract static class WrapperBase 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); + WrapperBase(TruffleString name, boolean isStatic) { CompilerAsserts.neverPartOfCompilation(); this.name = name; if (!isStatic) { @@ -513,29 +517,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 +544,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); @@ -583,15 +556,15 @@ 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(PythonLanguage language, TruffleString name, boolean isStatic, MethodDescriptorWrapper wrapper) { - super(language, name, isStatic); + MethodDescriptor(TruffleString name, boolean isStatic, MethodDescriptorWrapper wrapper) { + super(name, isStatic); assert wrapper.returnValue == PyObject; this.timing = CApiTiming.create(true, name); } @@ -619,12 +592,12 @@ 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(PythonLanguage language, TruffleString name, @SuppressWarnings("unused") PExternalFunctionWrapper wrapper) { - super(language, name, false); + WrapperDescriptor(TruffleString name, @SuppressWarnings("unused") PExternalFunctionWrapper wrapper) { + super(name, false); } protected final void transformExceptionFromNative() { @@ -649,13 +622,14 @@ 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(PythonLanguage language, TruffleString name, PExternalFunctionWrapper wrapper) { - super(language, name, wrapper); - assert wrapper.signature.returnValue == PyObject; + 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; } final NativeToPythonReturnNode ensureNativeToPythonReturnNode() { @@ -675,8 +649,8 @@ final Object returnNativeObjectToPython(long lresult) { } } - public static final class MethVarargsRoot extends PyCFunctionRootNode { - private static final Signature SIGNATURE = createSignature(false, 1, tsArray("self"), true, true); + 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; @Child private CreateNativeArgsTupleNode createNativeArgsTupleNode; @@ -684,8 +658,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 MethVarargs(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { + super(name, isStatic, provider); this.readVarargsNode = ReadVarArgsNode.create(SIGNATURE.varArgsPArgumentsIndex()); this.argsTupleToNativeNode = PythonToNativeNode.create(); this.createNativeArgsTupleNode = CreateNativeArgsTupleNodeGen.create(); @@ -742,14 +716,13 @@ public Signature getSignature() { } } - static final class MethKeywordsRoot extends MethodDescriptorRoot { - private static final Signature SIGNATURE = createSignature(true, 1, tsArray("self"), true, true); + static final class MethKeywords extends MethodDescriptor { + 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 +731,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 MethKeywords(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(); } @@ -795,7 +768,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; @@ -811,7 +784,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()); @@ -826,11 +798,11 @@ 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); + abstract static class MethUnaryFunc extends ObjectWrapperDescriptor { + 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}) @@ -848,8 +820,8 @@ public Signature getSignature() { } } - public abstract static class MethNewOrCallRoot extends ObjectWrapperDescriptorRoot { - private 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; @@ -858,8 +830,8 @@ public abstract static class MethNewOrCallRoot extends ObjectWrapperDescriptorRo @CompilationFinal boolean seenNativeArgsTupleStorage; - public MethNewOrCallRoot(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + public MethNewOrCall(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readVarargsNode = ReadVarArgsNode.create(SIGNATURE.varArgsPArgumentsIndex()); this.readKwargsNode = ReadVarKeywordsNode.create(SIGNATURE.varKeywordsPArgumentsIndex()); this.argsTupleToNativeNode = PythonToNativeNode.create(); @@ -921,13 +893,13 @@ 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(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + public MethNew(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); } @InvokeExternalFunction(value = ExternalFunctionSignature.NEWFUNC, argConversions = {PythonToNativeNode.class, long.class, PythonToNativeNode.class}) @@ -965,13 +937,13 @@ 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 { 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; @@ -982,10 +954,10 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati } @CApiWrapperDescriptor(value = CALL) - abstract static class MethCallRoot extends MethNewOrCallRoot { + abstract static class MethCall extends MethNewOrCall { - public MethCallRoot(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + public MethCall(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); } @InvokeExternalFunction(value = ExternalFunctionSignature.TERNARYFUNC, argConversions = {PythonToNativeNode.class, long.class, PythonToNativeNode.class}) @@ -1015,7 +987,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; @@ -1026,8 +998,8 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati } @CApiWrapperDescriptor(value = INIT) - abstract static class MethInitRoot extends WrapperDescriptorRoot { - private 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; @@ -1037,8 +1009,8 @@ abstract static class MethInitRoot extends WrapperDescriptorRoot { @CompilationFinal boolean seenNativeArgsTupleStorage; - public MethInitRoot(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + public MethInit(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readVarargsNode = ReadVarArgsNode.create(SIGNATURE.varArgsPArgumentsIndex()); this.readKwargsNode = ReadVarKeywordsNode.create(SIGNATURE.varKeywordsPArgumentsIndex()); this.argsTupleToNativeNode = PythonToNativeNode.create(); @@ -1076,7 +1048,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; @@ -1093,11 +1065,11 @@ 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); + public abstract static class MethInquiry extends WrapperDescriptor { + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self"), true, false); - public MethInquiryRoot(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + public MethInquiry(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); } @InvokeExternalFunction(value = ExternalFunctionSignature.INQUIRY, retConversion = int.class, argConversions = {PythonToNativeNode.class}) @@ -1119,11 +1091,11 @@ public Signature getSignature() { } } - static final class MethNoargsRoot extends PyCFunctionRootNode { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self"), true, true); + static final class MethNoargs extends PyCFunctionNode { + 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 MethNoargs(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { + super(name, isStatic, provider); } @Override @@ -1139,19 +1111,18 @@ public Signature getSignature() { } } - abstract static class PyCFunctionRootNode extends MethodDescriptorRoot { - @Child private CalleeContext calleeContext; + abstract static class PyCFunctionNode extends MethodDescriptor { @Child private BoundaryCallData boundaryCallData; @Child private PythonToNativeNode selfToNativeNode; - public PyCFunctionRootNode(PythonLanguage language, TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { - super(language, name, isStatic, provider); + public PyCFunctionNode(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 +1138,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); + 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(PythonLanguage language, TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { - super(language, name, isStatic, provider); + public MethO(TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { + super(name, isStatic, provider); this.readArgNode = ReadIndexedArgumentNode.create(1); this.argToNativeNode = PythonToNativeNode.create(); } @@ -1201,12 +1171,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. */ - private static final Signature SIGNATURE = MethKeywordsRoot.SIGNATURE; + static final Signature SIGNATURE = MethKeywords.SIGNATURE; @Child private ReadVarArgsNode readVarargsNode; @Child private ReadVarKeywordsNode readKwargsNode; @@ -1217,13 +1187,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 MethFastcallWithKeywords(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; @@ -1256,16 +1226,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); @@ -1290,8 +1260,8 @@ public Signature getSignature() { } } - static final class MethMethodRoot extends MethodDescriptorRoot { - private static final Signature SIGNATURE = createSignature(true, 1, tsArray("self", "cls"), true, true); + static final class MethMethod extends MethodDescriptor { + static final Signature SIGNATURE = createSignature(true, 1, tsArray("self", "cls"), true, true); @Child private ReadIndexedArgumentNode readClsNode; @Child private ReadVarArgsNode readVarargsNode; @@ -1301,13 +1271,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 MethMethod(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; @@ -1339,14 +1309,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); @@ -1369,25 +1339,25 @@ 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. */ - private 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(PythonLanguage language, TruffleString name, boolean isStatic, MethodDescriptorWrapper provider) { - super(language, name, isStatic, provider); + public MethFastcall(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; @@ -1461,13 +1431,13 @@ 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); + 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(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + IndexArgFuncNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readINode = ReadIndexedArgumentNode.create(1); this.asSizeNode = PyNumberAsSizeNode.create(); } @@ -1492,14 +1462,14 @@ 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); - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "key"), true, false); + 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(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + GetAttrFuncNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readArgNode = ReadIndexedArgumentNode.create(1); this.asCharPointerNode = AsCharPointerNodeGen.create(); } @@ -1531,15 +1501,15 @@ 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); - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "key", "value"), true, false); + 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(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + SetAttrFuncNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readArg1Node = ReadIndexedArgumentNode.create(1); this.readArg2Node = ReadIndexedArgumentNode.create(2); this.asCharPointerNode = AsCharPointerNodeGen.create(); @@ -1572,13 +1542,13 @@ 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); + 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(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + SetAttrOFuncNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readNameNode = ReadIndexedArgumentNode.create(1); this.readValueNode = ReadIndexedArgumentNode.create(2); } @@ -1612,13 +1582,13 @@ public Signature getSignature() { * {@code tp_richcompare}. */ @CApiWrapperDescriptor(value = RICHCMP) - public abstract static class RichCmpFuncRootNode extends ObjectWrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignature(false, -1, tsArray("self", "other", "op"), true, false); + 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(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + RichCmpFuncNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readOtherNode = ReadIndexedArgumentNode.create(1); this.readOpNode = ReadIndexedArgumentNode.create(2); } @@ -1643,13 +1613,13 @@ 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); + 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(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + GetItemNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readArg1Node = ReadIndexedArgumentNode.create(1); this.getIndexNode = GetIndexNode.create(); } @@ -1673,14 +1643,14 @@ 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); + 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(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + SetItemNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readArg1Node = ReadIndexedArgumentNode.create(1); this.readArg2Node = ReadIndexedArgumentNode.create(2); this.getIndexNode = GetIndexNode.create(); @@ -1709,13 +1679,13 @@ 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); + 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(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + SqDelItemNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readKeyNode = ReadIndexedArgumentNode.create(1); this.getIndexNode = GetIndexNode.create(); } @@ -1744,13 +1714,13 @@ public Signature getSignature() { * Implements semantics of {@code typeobject.c:wrap_descr_get} */ @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); + 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(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + public DescrGetNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readObj = ReadIndexedArgumentNode.create(1); this.readType = ReadIndexedArgumentNode.create(2); } @@ -1777,12 +1747,12 @@ 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); + 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(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + public DescrDeleteNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readObj = ReadIndexedArgumentNode.create(1); } @@ -1808,12 +1778,12 @@ 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); + 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(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + public DelAttrNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readObj = ReadIndexedArgumentNode.create(1); } @@ -1840,12 +1810,12 @@ 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); + public abstract static class MpDelItemNode extends WrapperDescriptor { + 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); + MpDelItemNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readKeyNode = ReadIndexedArgumentNode.create(1); } @@ -1874,16 +1844,16 @@ public Signature getSignature() { * {@code typeobject.c: wrap_ternaryfunc_r}. */ @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); + public abstract static class MethTernaryFunc extends ObjectWrapperDescriptor { + 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); + MethTernaryFunc(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readArg1Node = ReadIndexedArgumentNode.create(1); this.readArg2Node = ReadIndexedArgumentNode.create(2); this.reverse = provider == TERNARYFUNC_R; @@ -1924,15 +1894,15 @@ 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); + 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(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + MethRichcmpOpNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readArgNode = ReadIndexedArgumentNode.create(1); this.op = getCompareOpCode(provider); } @@ -1968,12 +1938,13 @@ private static int getCompareOpCode(PExternalFunctionWrapper sig) { /** Implements semantics of {@code typeobject.c: wrap_next}. */ @CApiWrapperDescriptor(value = ITERNEXT) - public abstract static class IterNextFuncRootNode extends ObjectWrapperDescriptorRoot { + public abstract static class IterNextFuncNode extends ObjectWrapperDescriptor { + static final Signature SIGNATURE = MethNoargs.SIGNATURE; @Child private CheckIterNextResultNode checkIterNextResultNode; - IterNextFuncRootNode(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + IterNextFuncNode(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.checkIterNextResultNode = CheckIterNextResultNodeGen.create(); } @@ -1991,7 +1962,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; } } @@ -1999,13 +1970,13 @@ public Signature getSignature() { * Wrapper root node for C function type {@code getter}. */ @CApiWrapperDescriptor(value = GETTER) - public abstract static class GetterRoot extends ObjectWrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignatureWithClosure(false, -1, tsArray("self"), true, false); + public abstract static class Getter extends ObjectWrapperDescriptor { + 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 Getter(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); } @InvokeExternalFunction(value = ExternalFunctionSignature.GETTER, argConversions = {PythonToNativeNode.class, long.class}) @@ -2038,14 +2009,14 @@ public Signature getSignature() { * Wrapper root node for C function type {@code setter}. */ @CApiWrapperDescriptor(value = SETTER) - public abstract static class SetterRoot extends WrapperDescriptorRoot { - private static final Signature SIGNATURE = createSignatureWithClosure(false, -1, tsArray("self", "value"), true, false); + 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(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + public Setter(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); } @InvokeExternalFunction(value = ExternalFunctionSignature.SETTER, retConversion = int.class, argConversions = {PythonToNativeNode.class, PythonToNativeNode.class, long.class}) @@ -2057,7 +2028,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) { @@ -2082,11 +2053,11 @@ 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); + public abstract static class MethLenfunc extends WrapperDescriptor { + static final Signature SIGNATURE = createSignature(false, -1, tsArray("self"), true, false); - public MethLenfuncRoot(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, provider); + public MethLenfunc(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); } @InvokeExternalFunction(value = ExternalFunctionSignature.LENFUNC, argConversions = {PythonToNativeNode.class}) @@ -2110,13 +2081,13 @@ 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); + public abstract static class MethObjObjProc extends WrapperDescriptor { + 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); + MethObjObjProc(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readValueNode = ReadIndexedArgumentNode.create(1); } @@ -2143,14 +2114,14 @@ 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); + 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(PythonLanguage lang, TruffleString name, PExternalFunctionWrapper provider) { - super(lang, name, provider); + MethObjObjArgProc(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readKeyNode = ReadIndexedArgumentNode.create(1); this.readValueNode = ReadIndexedArgumentNode.create(2); } @@ -2182,15 +2153,15 @@ public Signature getSignature() { * {@code typeobject.c: wrap_binaryfunc_r}. */ @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); + 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(PythonLanguage lang, TruffleString name, PExternalFunctionWrapper provider) { - super(lang, name, provider); + MethBinary(TruffleString name, PExternalFunctionWrapper provider) { + super(name, provider); this.readOtherNode = ReadIndexedArgumentNode.create(1); this.reverse = provider == BINARYFUNC_R; } @@ -2224,13 +2195,13 @@ 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); + 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(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { - super(language, name, 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 new file mode 100644 index 0000000000..0e3ffbc3e4 --- /dev/null +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionWrapperFactory.java @@ -0,0 +1,207 @@ +/* + * 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.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; +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 WrapperBuiltin(name.toJavaStringUncached()); + this.constructor = constructor; + } + + BuiltinFunctionRootNode createRoot(PythonLanguage language) { + return new BuiltinFunctionRootNode(language, signature, builtin, this, true, null); + } + + @Override + public WrapperBase createNode(Object... arguments) { + assert arguments.length == 0; + WrapperBase 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(); + } + + /** 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; + } + + @Override + public String doc() { + return ""; + } + + @Override + public PythonOS os() { + return PythonOS.PLATFORM_ANY; + } + + @Override + public int minNumOfPositionalArgs() { + return 0; + } + + @Override + public int maxNumOfPositionalArgs() { + return -1; + } + + @Override + public int numOfPositionalOnlyArgs() { + return -1; + } + + @Override + public boolean isGetter() { + return false; + } + + @Override + public boolean isSetter() { + return false; + } + + @Override + public boolean allowsDelete() { + return false; + } + + @Override + public boolean takesVarArgs() { + return false; + } + + @Override + public boolean takesVarKeywordArgs() { + return false; + } + + @Override + public String[] parameterNames() { + return new String[0]; + } + + @Override + public String[] keywordOnlyNames() { + return new String[0]; + } + + @Override + public boolean isClassmethod() { + return false; + } + + @Override + public boolean isStaticmethod() { + return false; + } + + @Override + public boolean needsFrame() { + return true; + } + + @Override + public int callerFlags() { + return 0; + } + + @Override + public boolean declaresExplicitSelf() { + return true; + } + + @Override + public String raiseErrorName() { + return ""; + } + + @Override + public boolean forceSplitDirectCalls() { + return false; + } + + @Override + public boolean autoRegister() { + return false; + } + } +} 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..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,20 +48,20 @@ 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; 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(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)); }; - return language.createCachedExternalFunWrapperRootNode(rootNodeFunction, nodeKlass, sig, name, true, isStatic); } /** @@ -171,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/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/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/PRootNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PRootNode.java index 423ac950ed..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,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.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; @@ -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) && + !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/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 796808c5e5..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,7 +50,9 @@ 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; import com.oracle.graal.python.runtime.ExecutionContext.IndirectCalleeContext; import com.oracle.graal.python.runtime.PythonContext; @@ -75,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 { @@ -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) { @@ -396,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); @@ -437,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/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/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/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/nodes/function/BuiltinFunctionRootNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/BuiltinFunctionRootNode.java index 3a0549f5c7..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 @@ -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.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; @@ -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 = WrapperBase.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; 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..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,9 +239,9 @@ 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; import com.oracle.graal.python.runtime.NativeZlibSupport; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.sequence.storage.ByteSequenceStorage; @@ -264,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; @@ -566,29 +565,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); @@ -1137,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,