diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/GraalPythonModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/GraalPythonModuleBuiltins.java index 25858c5e9d..9dbeec9804 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/GraalPythonModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/GraalPythonModuleBuiltins.java @@ -401,7 +401,7 @@ private void runFile(PythonContext context, TruffleString inputFilePath) { Object[] arguments = PArguments.create(); PythonModule mainModule = context.getMainModule(); PDict mainDict = GetOrCreateDictNode.executeUncached(mainModule); - PArguments.setGlobals(arguments, mainModule); + PArguments.setGlobals(arguments, mainDict); PArguments.setSpecialArgument(arguments, mainDict); PArguments.setException(arguments, PException.NO_EXCEPTION); context.initializeMainModule(inputFilePath); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/function/PArguments.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/function/PArguments.java index f40824f156..2790c91638 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/function/PArguments.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/function/PArguments.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. @@ -26,9 +26,11 @@ package com.oracle.graal.python.builtins.objects.function; import com.oracle.graal.python.builtins.objects.frame.PFrame; +import com.oracle.graal.python.builtins.objects.module.PythonModule; import com.oracle.graal.python.builtins.objects.object.PythonObject; import com.oracle.graal.python.nodes.argument.CreateArgumentsNode; import com.oracle.graal.python.runtime.exception.PException; +import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.exception.AbstractTruffleException; import com.oracle.truffle.api.frame.Frame; @@ -70,9 +72,10 @@ public static boolean isPythonFrame(Object[] frameArgs) { return frameArgs.length >= USER_ARGUMENTS_OFFSET && frameArgs[INDEX_CURRENT_FRAME_INFO] instanceof PFrame.Reference; } - public static Object[] withGlobals(PythonObject globals) { + public static Object[] withGlobals(PythonModule globals) { + CompilerAsserts.neverPartOfCompilation(); Object[] arguments = create(); - setGlobals(arguments, globals); + setGlobals(arguments, globals.getDict()); return arguments; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/module/PythonModule.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/module/PythonModule.java index 10f69de0b2..92edd0cf17 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/module/PythonModule.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/module/PythonModule.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. @@ -37,9 +37,12 @@ import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.PythonBuiltins; import com.oracle.graal.python.builtins.objects.PNone; +import com.oracle.graal.python.builtins.objects.dict.PDict; import com.oracle.graal.python.builtins.objects.object.PythonObject; import com.oracle.graal.python.nodes.PGuards; +import com.oracle.graal.python.nodes.object.GetDictIfExistsNode; import com.oracle.graal.python.nodes.object.GetOrCreateDictNode; +import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.strings.TruffleString; @@ -61,7 +64,7 @@ public final class PythonModule extends PythonObject { * table reference weak in order to break possible reference cycles. This field will ever only * be set if the module's native definition provides a traverse function (see * {@code moduleobject.c: module_traverse}). The condition for this is: - * + * *
* {@code
* if (m -> md_def && m -> md_def -> m_traverse && (m -> md_def -> m_size <= 0 || m -> md_state != NULL)) {
@@ -162,4 +165,10 @@ public void setReplicatedNativeReferences(Object[] replicatedNativeReferences) {
public Object[] getReplicatedNativeReferences() {
return this.replicatedNativeReferences;
}
+
+ public PDict getDict() {
+ // PythonModule always have a dict
+ CompilerAsserts.neverPartOfCompilation();
+ return GetDictIfExistsNode.getDictUncached(this);
+ }
}
diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/PythonObject.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/PythonObject.java
index 86718564dc..a7731d67cf 100644
--- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/PythonObject.java
+++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/PythonObject.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.
@@ -83,11 +83,11 @@ public void setDict(Node inliningTarget, HiddenAttr.WriteNode writeNode, PDict d
}
@NeverDefault
- public Object getPythonClass() {
+ public final Object getPythonClass() {
return pythonClass;
}
- public void setPythonClass(Object pythonClass) {
+ public final void setPythonClass(Object pythonClass) {
assert getShape().getDynamicType() == PNone.NO_VALUE;
this.pythonClass = pythonClass;
}
diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectGetItem.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectGetItem.java
index f20435b8b3..2a78ecb393 100644
--- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectGetItem.java
+++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectGetItem.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 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
@@ -42,10 +42,12 @@
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___CLASS_GETITEM__;
+import static com.oracle.graal.python.runtime.exception.PythonErrorType.KeyError;
import com.oracle.graal.python.PythonLanguage;
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
import com.oracle.graal.python.builtins.objects.PNone;
+import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageGetItem;
import com.oracle.graal.python.builtins.objects.dict.DictBuiltins;
import com.oracle.graal.python.builtins.objects.dict.PDict;
import com.oracle.graal.python.builtins.objects.list.ListBuiltins;
@@ -63,6 +65,8 @@
import com.oracle.graal.python.nodes.PRaiseNode;
import com.oracle.graal.python.nodes.call.CallNode;
import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinClassExactProfile;
+import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile;
+import com.oracle.graal.python.runtime.exception.PException;
import com.oracle.graal.python.runtime.object.PFactory;
import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff;
import com.oracle.truffle.api.dsl.Cached;
@@ -76,6 +80,7 @@
import com.oracle.truffle.api.frame.Frame;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.strings.TruffleString;
/**
* Equivalent of CPython's {@code PyObject_GetItem}.
@@ -121,6 +126,38 @@ static Object doGeneric(VirtualFrame frame, Node inliningTarget, Object object,
return genericNode.execute(frame, inliningTarget, object, slots, key);
}
+ /**
+ * A version of {@link PyObjectGetItem} optimized for builtin dictionaries and
+ * {@link TruffleString} keys that suppresses the {@code KeyError} and returns {@code null} if
+ * key was not found.
+ */
+ @GenerateUncached
+ @GenerateInline
+ @GenerateCached(false)
+ public abstract static class PyObjectGetItemOrNull extends PNodeWithContext {
+ public abstract Object execute(VirtualFrame frame, Node inliningTarget, Object dict, TruffleString key);
+
+ @Specialization(guards = "isBuiltinDict(dict)")
+ static Object doPDict(VirtualFrame frame, Node inliningTarget, PDict dict, TruffleString key,
+ @Cached HashingStorageGetItem getItem) {
+ return getItem.execute(frame, inliningTarget, dict.getDictStorage(), key);
+ }
+
+ @Fallback
+ @InliningCutoff
+ static Object doPDictGeneric(VirtualFrame frame, Node inliningTarget, Object object, TruffleString key,
+ @Cached GetObjectSlotsNode getSlotsNode,
+ @Cached PyObjectGetItemGeneric genericNode,
+ @Cached IsBuiltinObjectProfile errorProfile) {
+ try {
+ return doGeneric(frame, inliningTarget, object, key, getSlotsNode, genericNode);
+ } catch (PException e) {
+ e.expect(inliningTarget, KeyError, errorProfile);
+ return null;
+ }
+ }
+ }
+
@GenerateUncached
@GenerateInline
@GenerateCached(false)
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 63d7526ad8..b6634096cb 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
@@ -72,6 +72,7 @@
import com.oracle.graal.python.builtins.objects.asyncio.PAsyncGenWrappedValue;
import com.oracle.graal.python.builtins.objects.cell.PCell;
import com.oracle.graal.python.builtins.objects.code.PCode;
+import com.oracle.graal.python.builtins.objects.common.DynamicObjectStorage;
import com.oracle.graal.python.builtins.objects.common.EconomicMapStorage;
import com.oracle.graal.python.builtins.objects.common.HashingStorage;
import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageSetItem;
@@ -151,6 +152,7 @@
import com.oracle.graal.python.lib.PyObjectFunctionStr;
import com.oracle.graal.python.lib.PyObjectGetAttr;
import com.oracle.graal.python.lib.PyObjectGetItem;
+import com.oracle.graal.python.lib.PyObjectGetItem.PyObjectGetItemOrNull;
import com.oracle.graal.python.lib.PyObjectGetIter;
import com.oracle.graal.python.lib.PyObjectGetMethod;
import com.oracle.graal.python.lib.PyObjectHashNode;
@@ -178,6 +180,7 @@
import com.oracle.graal.python.nodes.argument.keywords.NonMappingException;
import com.oracle.graal.python.nodes.argument.keywords.SameDictKeyException;
import com.oracle.graal.python.nodes.attributes.GetFixedAttributeNode;
+import com.oracle.graal.python.nodes.attributes.ReadAttributeFromPythonObjectNode;
import com.oracle.graal.python.nodes.builtins.ListNodes;
import com.oracle.graal.python.nodes.bytecode.CopyDictWithoutKeysNode;
import com.oracle.graal.python.nodes.bytecode.GetAIterNode;
@@ -211,7 +214,6 @@
import com.oracle.graal.python.nodes.frame.ReadBuiltinNode;
import com.oracle.graal.python.nodes.frame.ReadFromLocalsNode;
import com.oracle.graal.python.nodes.frame.ReadGlobalOrBuiltinNode;
-import com.oracle.graal.python.nodes.frame.ReadNameNode;
import com.oracle.graal.python.nodes.frame.WriteGlobalNode;
import com.oracle.graal.python.nodes.frame.WriteNameNode;
import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile;
@@ -258,6 +260,7 @@
import com.oracle.truffle.api.bytecode.ContinuationRootNode;
import com.oracle.truffle.api.bytecode.EpilogExceptional;
import com.oracle.truffle.api.bytecode.EpilogReturn;
+import com.oracle.truffle.api.bytecode.ForceQuickening;
import com.oracle.truffle.api.bytecode.GenerateBytecode;
import com.oracle.truffle.api.bytecode.Instruction;
import com.oracle.truffle.api.bytecode.Instrumentation;
@@ -348,6 +351,7 @@
@OperationProxy(SetupAnnotationsNode.class)
@OperationProxy(GetAIterNode.class)
@OperationProxy(GetANextNode.class)
+@OperationProxy(value = ReadGlobalOrBuiltinNode.class, name = "ReadGlobal")
@OperationProxy(value = CopyDictWithoutKeysNode.class, name = "CopyDictWithoutKeys")
@OperationProxy(value = PyObjectIsTrueNode.class, name = "Yes")
@OperationProxy(value = PyObjectIsNotTrueNode.class, name = "Not")
@@ -1204,13 +1208,42 @@ public static void perform(VirtualFrame frame, TruffleString name, Object value,
}
}
- @Operation(storeBytecodeIndex = true)
+ @Operation(storeBytecodeIndex = false)
@ConstantOperand(type = TruffleString.class)
+ @ImportStatic(PGuards.class)
public static final class ReadName {
- @Specialization
- public static Object perform(VirtualFrame frame, TruffleString name,
- @Cached ReadNameNode readNode) {
- return readNode.execute(frame, name);
+ static Object readFromLocalsFastPath(VirtualFrame frame, TruffleString attributeId, ReadAttributeFromPythonObjectNode readNode) {
+ Object specialArgument = PArguments.getSpecialArgument(frame);
+ if (specialArgument instanceof PDict dict && dict.getDictStorage() instanceof DynamicObjectStorage s) {
+ return readNode.execute(s.getStore(), attributeId, PNone.NO_VALUE);
+ }
+ return PNone.NO_VALUE;
+ }
+
+ @ForceQuickening
+ @Specialization(guards = "!isNoValue(result)", limit = "1")
+ public static Object doLocalFastPath(VirtualFrame frame, TruffleString name,
+ @Cached ReadAttributeFromPythonObjectNode readAttrNode,
+ @Bind("readFromLocalsFastPath(frame, name, readAttrNode)") Object result) {
+ return result;
+ }
+
+ @StoreBytecodeIndex
+ @Specialization(replaces = "doLocalFastPath")
+ public static Object doFull(VirtualFrame frame, TruffleString name,
+ @Bind Node inliningTarget,
+ @Cached PyObjectGetItemOrNull getLocal,
+ @Cached ReadGlobalOrBuiltinNode readGlobalOrBuiltinNode,
+ @Cached InlinedConditionProfile hasLocalsProfile) {
+ Object locals = PArguments.getSpecialArgument(frame);
+ Object result = null;
+ if (hasLocalsProfile.profile(inliningTarget, locals != null)) {
+ result = getLocal.execute(frame, inliningTarget, locals, name);
+ }
+ if (result == null) {
+ return readGlobalOrBuiltinNode.execute(frame, name);
+ }
+ return result;
}
}
@@ -1621,16 +1654,6 @@ public static void doWithFrame(VirtualFrame frame, Object primary, Object index,
}
}
- @Operation(storeBytecodeIndex = true)
- @ConstantOperand(type = TruffleString.class)
- public static final class ReadGlobal {
- @Specialization
- public static Object perform(VirtualFrame frame, TruffleString name,
- @Cached ReadGlobalOrBuiltinNode readNode) {
- return readNode.execute(frame, name);
- }
- }
-
@Operation(storeBytecodeIndex = true)
@ConstantOperand(type = TruffleString.class)
public static final class WriteGlobal {
@@ -2657,7 +2680,7 @@ public static Object doLoadCell(VirtualFrame frame, TruffleString name, Object d
value = getItemNode.execute(frame, inliningTarget, dict, name);
} catch (PException e) {
e.expect(inliningTarget, KeyError, errorProfile);
- value = readGlobal.read(frame, PArguments.getGlobals(frame), name);
+ value = readGlobal.execute(frame, name);
}
return value;
}
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 5f4d7cc659..216a0c2602 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
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 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
@@ -323,7 +323,7 @@ private Object run(VirtualFrame frame) {
} else {
mainModule = pythonContext.getMainModule();
PDict mainDict = GetOrCreateDictNode.executeUncached(mainModule);
- PArguments.setGlobals(arguments, mainModule);
+ PArguments.setGlobals(arguments, mainDict);
PArguments.setSpecialArgument(arguments, mainDict);
PArguments.setException(arguments, PException.NO_EXCEPTION);
}
diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/ReadGlobalOrBuiltinNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/ReadGlobalOrBuiltinNode.java
index bbfbbba72b..56bb66ba48 100644
--- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/ReadGlobalOrBuiltinNode.java
+++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/ReadGlobalOrBuiltinNode.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.
@@ -26,52 +26,56 @@
package com.oracle.graal.python.nodes.frame;
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.SystemError;
-import static com.oracle.graal.python.runtime.exception.PythonErrorType.KeyError;
import com.oracle.graal.python.builtins.objects.PNone;
-import com.oracle.graal.python.builtins.objects.common.HashingStorage;
-import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageGetItem;
+import com.oracle.graal.python.builtins.objects.common.DynamicObjectStorage;
import com.oracle.graal.python.builtins.objects.dict.PDict;
import com.oracle.graal.python.builtins.objects.function.PArguments;
-import com.oracle.graal.python.builtins.objects.module.PythonModule;
-import com.oracle.graal.python.lib.PyObjectGetItem;
+import com.oracle.graal.python.builtins.objects.object.PythonObject;
+import com.oracle.graal.python.lib.PyObjectGetItem.PyObjectGetItemOrNull;
import com.oracle.graal.python.nodes.ErrorMessages;
-import com.oracle.graal.python.nodes.PNodeWithContext;
+import com.oracle.graal.python.nodes.PGuards;
import com.oracle.graal.python.nodes.PRaiseNode;
-import com.oracle.graal.python.nodes.attributes.ReadAttributeFromModuleNode;
-import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile;
+import com.oracle.graal.python.nodes.attributes.ReadAttributeFromPythonObjectNode;
import com.oracle.graal.python.runtime.exception.PException;
import com.oracle.truffle.api.CompilerAsserts;
+import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff;
+import com.oracle.truffle.api.bytecode.ConstantOperand;
+import com.oracle.truffle.api.bytecode.ForceQuickening;
+import com.oracle.truffle.api.bytecode.OperationProxy.Proxyable;
+import com.oracle.truffle.api.bytecode.StoreBytecodeIndex;
import com.oracle.truffle.api.dsl.Bind;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Cached.Exclusive;
import com.oracle.truffle.api.dsl.Cached.Shared;
-import com.oracle.truffle.api.dsl.Fallback;
-import com.oracle.truffle.api.dsl.GenerateCached;
import com.oracle.truffle.api.dsl.GenerateInline;
import com.oracle.truffle.api.dsl.GenerateUncached;
+import com.oracle.truffle.api.dsl.ImportStatic;
import com.oracle.truffle.api.dsl.NeverDefault;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.Frame;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.object.Shape;
import com.oracle.truffle.api.profiles.InlinedBranchProfile;
import com.oracle.truffle.api.strings.TruffleString;
@GenerateUncached
@GenerateInline(false) // footprint reduction 48 -> 30
-public abstract class ReadGlobalOrBuiltinNode extends PNodeWithContext {
- public final Object execute(VirtualFrame frame, TruffleString name) {
- CompilerAsserts.partialEvaluationConstant(name);
- return executeWithGlobals(frame, PArguments.getGlobals(frame), name);
- }
-
- protected abstract Object executeWithGlobals(VirtualFrame frame, Object globals, TruffleString name);
+@Proxyable(storeBytecodeIndex = false)
+@ConstantOperand(type = TruffleString.class)
+@ImportStatic(PGuards.class)
+public abstract class ReadGlobalOrBuiltinNode extends Node {
+ public abstract Object execute(VirtualFrame frame, TruffleString name);
public Object read(Frame frame, Object globals, TruffleString name) {
CompilerAsserts.partialEvaluationConstant(name);
- return executeWithGlobals((VirtualFrame) frame, globals, name);
+ // reloading globals is not efficient, but this entry point is here just because it is used
+ // from the manual interpreter and only for the time being until the manual interpreter is
+ // removed
+ assert PArguments.getGlobals(frame) == globals;
+ return execute((VirtualFrame) frame, name);
}
@NeverDefault
@@ -83,107 +87,63 @@ public static ReadGlobalOrBuiltinNode getUncached() {
return ReadGlobalOrBuiltinNodeGen.getUncached();
}
- @Specialization(guards = {"isSingleContext()", "globals == cachedGlobals"}, limit = "1")
- protected static Object readGlobalCached(@SuppressWarnings("unused") PythonModule globals, TruffleString attributeId,
- @Bind Node inliningTarget,
- @Shared("readFromBuiltinsNode") @Cached ReadBuiltinNode readFromBuiltinsNode,
- @Exclusive @Cached InlinedBranchProfile wasReadFromModule,
- @Shared("readFromModule") @Cached ReadAttributeFromModuleNode readFromModuleNode,
- @Cached(value = "globals", weak = true) PythonModule cachedGlobals) {
- Object result = readFromModuleNode.execute(cachedGlobals, attributeId);
- return returnGlobalOrBuiltin(result, attributeId, readFromBuiltinsNode, inliningTarget, wasReadFromModule);
- }
-
- @InliningCutoff
- @Specialization(replaces = "readGlobalCached")
- protected static Object readGlobal(PythonModule globals, TruffleString attributeId,
- @Bind Node inliningTarget,
- @Shared("readFromBuiltinsNode") @Cached ReadBuiltinNode readFromBuiltinsNode,
- @Exclusive @Cached InlinedBranchProfile wasReadFromModule,
- @Shared("readFromModule") @Cached ReadAttributeFromModuleNode readFromModuleNode) {
- Object result = readFromModuleNode.execute(globals, attributeId);
- return returnGlobalOrBuiltin(result, attributeId, readFromBuiltinsNode, inliningTarget, wasReadFromModule);
- }
-
- static final class GlobalsDictStorageChanged extends RuntimeException {
- private static final GlobalsDictStorageChanged INSTANCE = new GlobalsDictStorageChanged();
- private static final long serialVersionUID = 2982918866373996561L;
-
- GlobalsDictStorageChanged() {
- super(null, null);
+ public static Shape getGlobalsStorageShape(VirtualFrame frame) {
+ Object obj = PArguments.getGlobals(frame);
+ if (obj instanceof PDict dict && dict.getDictStorage() instanceof DynamicObjectStorage dom) {
+ return dom.getStore().getShape();
}
+ return null;
+ }
- @SuppressWarnings("sync-override")
- @Override
- public Throwable fillInStackTrace() {
- return this;
+ public static Shape getGlobalsStorageShapeIfPropMissing(VirtualFrame frame, TruffleString name) {
+ Object obj = PArguments.getGlobals(frame);
+ if (obj instanceof PDict dict && dict.getDictStorage() instanceof DynamicObjectStorage dom) {
+ Shape shape = dom.getStore().getShape();
+ if (!shape.hasProperty(name)) {
+ return shape;
+ }
}
+ return null;
}
- @Specialization(guards = {"isSingleContext()", "globals == cachedGlobals", "isBuiltinDict(cachedGlobals)"}, limit = "1", rewriteOn = GlobalsDictStorageChanged.class)
- protected static Object readGlobalBuiltinDictCachedUnchangedStorage(@SuppressWarnings("unused") PDict globals, TruffleString attributeId,
- @Bind Node inliningTarget,
- @Shared("readFromBuiltinsNode") @Cached ReadBuiltinNode readFromBuiltinsNode,
- @Exclusive @Cached InlinedBranchProfile wasReadFromModule,
- @SuppressWarnings("unused") @Cached(value = "globals", weak = true) PDict cachedGlobals,
- @Cached(value = "globals.getDictStorage()", weak = true) HashingStorage cachedStorage,
- @Exclusive @Cached HashingStorageGetItem getItem) {
- if (cachedGlobals.getDictStorage() != cachedStorage) {
- throw GlobalsDictStorageChanged.INSTANCE;
- }
- Object result = getItem.execute(inliningTarget, cachedStorage, attributeId);
- return returnGlobalOrBuiltin(result == null ? PNone.NO_VALUE : result, attributeId, readFromBuiltinsNode, inliningTarget, wasReadFromModule);
+ @ForceQuickening
+ @Specialization(guards = {"cachedGlobalsShape != null", "cachedGlobalsShape == getGlobalsStorageShape(frame)"}, //
+ excludeForUncached = true, limit = "1")
+ public static Object readBuiltinFastPath(VirtualFrame frame, TruffleString attributeId,
+ @Cached("getGlobalsStorageShapeIfPropMissing(frame, attributeId)") Shape cachedGlobalsShape,
+ @Shared("readFromBuiltinsNode") @Cached ReadBuiltinNode readFromBuiltinsNode) {
+ return readFromBuiltinsNode.execute(attributeId);
}
- @InliningCutoff
- @Specialization(guards = {"isSingleContext()", "globals == cachedGlobals",
- "isBuiltinDict(cachedGlobals)"}, replaces = "readGlobalBuiltinDictCachedUnchangedStorage", limit = "1")
- protected static Object readGlobalBuiltinDictCached(@SuppressWarnings("unused") PDict globals, TruffleString attributeId,
- @Bind Node inliningTarget,
- @Shared("readFromBuiltinsNode") @Cached ReadBuiltinNode readFromBuiltinsNode,
- @Exclusive @Cached InlinedBranchProfile wasReadFromModule,
- @Cached(value = "globals", weak = true) PDict cachedGlobals,
- @Exclusive @Cached HashingStorageGetItem getItem) {
- Object result = getItem.execute(inliningTarget, cachedGlobals.getDictStorage(), attributeId);
- return returnGlobalOrBuiltin(result == null ? PNone.NO_VALUE : result, attributeId, readFromBuiltinsNode, inliningTarget, wasReadFromModule);
+ public static Object readFastFromGlobalStore(VirtualFrame frame, TruffleString name, ReadAttributeFromPythonObjectNode readNode) {
+ Object obj = PArguments.getGlobals(frame);
+ if (obj instanceof PDict dict && dict.getDictStorage() instanceof DynamicObjectStorage dom) {
+ return readNode.execute(dom.getStore(), name, PNone.NO_VALUE);
+ }
+ return PNone.NO_VALUE;
}
- @InliningCutoff
- @Specialization(guards = "isBuiltinDict(globals)", replaces = {"readGlobalBuiltinDictCached", "readGlobalBuiltinDictCachedUnchangedStorage"})
- protected static Object readGlobalBuiltinDict(@SuppressWarnings("unused") PDict globals, TruffleString attributeId,
- @Bind Node inliningTarget,
- @Shared("readFromBuiltinsNode") @Cached ReadBuiltinNode readFromBuiltinsNode,
- @Exclusive @Cached InlinedBranchProfile wasReadFromModule,
- @Bind("globals.getDictStorage()") HashingStorage storage,
- @Exclusive @Cached HashingStorageGetItem getItem) {
- Object result = getItem.execute(inliningTarget, storage, attributeId);
- return returnGlobalOrBuiltin(result == null ? PNone.NO_VALUE : result, attributeId, readFromBuiltinsNode, inliningTarget, wasReadFromModule);
+ @ForceQuickening
+ @Specialization(guards = "!isNoValue(result)", replaces = "readBuiltinFastPath", excludeForUncached = true, limit = "1")
+ public static Object readGlobalFastPath(VirtualFrame frame, TruffleString attributeId,
+ @Cached ReadAttributeFromPythonObjectNode readNode,
+ @Bind("readFastFromGlobalStore(frame, attributeId, readNode)") Object result) {
+ return result;
}
- @InliningCutoff
- @Specialization
- protected static Object readGlobalDictGeneric(VirtualFrame frame, PDict globals, TruffleString attributeId,
+ @StoreBytecodeIndex
+ @Specialization(replaces = {"readBuiltinFastPath", "readGlobalFastPath"})
+ public static Object readGlobalOrBuiltinGeneric(VirtualFrame frame, TruffleString attributeId,
@Bind Node inliningTarget,
@Shared("readFromBuiltinsNode") @Cached ReadBuiltinNode readFromBuiltinsNode,
@Exclusive @Cached InlinedBranchProfile wasReadFromModule,
- @Cached PyObjectGetItem getItemNode,
- @Cached IsBuiltinObjectProfile errorProfile) {
- try {
- Object result = getItemNode.execute(frame, inliningTarget, globals, attributeId);
- return returnGlobalOrBuiltin(result, attributeId, readFromBuiltinsNode, inliningTarget, wasReadFromModule);
- } catch (PException e) {
- e.expect(inliningTarget, KeyError, errorProfile);
- return returnGlobalOrBuiltin(PNone.NO_VALUE, attributeId, readFromBuiltinsNode, inliningTarget, wasReadFromModule);
+ @Cached PyObjectGetItemOrNull getItemNode) {
+ PythonObject globalsObj = PArguments.getGlobals(frame);
+ if (!(globalsObj instanceof PDict globals)) {
+ throw raiseSystemError(inliningTarget);
}
- }
-
- @Fallback
- protected Object syserr(@SuppressWarnings("unused") VirtualFrame frame, @SuppressWarnings("unused") Object dict, @SuppressWarnings("unused") TruffleString attributeId) {
- throw PRaiseNode.raiseStatic(this, SystemError, ErrorMessages.BAD_ARG_TO_INTERNAL_FUNC);
- }
-
- private static Object returnGlobalOrBuiltin(Object result, TruffleString attributeId, ReadBuiltinNode readFromBuiltinsNode, Node inliningTarget, InlinedBranchProfile wasReadFromModule) {
- if (result != PNone.NO_VALUE) {
+ Object result = getItemNode.execute(frame, inliningTarget, globals, attributeId);
+ if (result != null) {
wasReadFromModule.enter(inliningTarget);
return result;
} else {
@@ -191,19 +151,9 @@ private static Object returnGlobalOrBuiltin(Object result, TruffleString attribu
}
}
- @GenerateUncached
- @GenerateInline
- @GenerateCached(false)
- public abstract static class Lazy extends Node {
- public final ReadGlobalOrBuiltinNode get(Node inliningTarget) {
- return execute(inliningTarget);
- }
-
- public abstract ReadGlobalOrBuiltinNode execute(Node inliningTarget);
-
- @Specialization
- static ReadGlobalOrBuiltinNode doIt(@Cached(inline = false) ReadGlobalOrBuiltinNode node) {
- return node;
- }
+ @InliningCutoff
+ private static PException raiseSystemError(Node inliningTarget) {
+ CompilerDirectives.transferToInterpreter();
+ throw PRaiseNode.raiseStatic(inliningTarget, SystemError, ErrorMessages.BAD_ARG_TO_INTERNAL_FUNC);
}
}
diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/ReadNameNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/ReadNameNode.java
index 033554ba22..f1d833b6d1 100644
--- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/ReadNameNode.java
+++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/ReadNameNode.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2025, 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
@@ -40,18 +40,13 @@
*/
package com.oracle.graal.python.nodes.frame;
-import com.oracle.graal.python.builtins.PythonBuiltinClassType;
import com.oracle.graal.python.builtins.objects.PNone;
-import com.oracle.graal.python.builtins.objects.common.HashingStorage;
-import com.oracle.graal.python.builtins.objects.dict.PDict;
import com.oracle.graal.python.builtins.objects.function.PArguments;
import com.oracle.graal.python.nodes.PNodeWithContext;
-import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile;
-import com.oracle.graal.python.runtime.exception.PException;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.dsl.Bind;
import com.oracle.truffle.api.dsl.Cached;
-import com.oracle.truffle.api.dsl.Cached.Exclusive;
+import com.oracle.truffle.api.dsl.Cached.Shared;
import com.oracle.truffle.api.dsl.GenerateInline;
import com.oracle.truffle.api.dsl.GenerateUncached;
import com.oracle.truffle.api.dsl.NeverDefault;
@@ -75,30 +70,20 @@ public static ReadNameNode create() {
return ReadNameNodeGen.create();
}
- private static Object readGlobalsIfKeyError(VirtualFrame frame, Node inliningTarget, TruffleString attributeId, ReadGlobalOrBuiltinNode readGlobalNode, PException e,
- IsBuiltinObjectProfile keyError) {
- e.expect(inliningTarget, PythonBuiltinClassType.KeyError, keyError);
- return readGlobalNode.execute(frame, attributeId);
- }
-
- protected static HashingStorage getStorage(VirtualFrame frame) {
- return ((PDict) PArguments.getSpecialArgument(frame)).getDictStorage();
- }
-
@Specialization(guards = "!hasLocals(frame)")
protected static Object readFromLocals(VirtualFrame frame, TruffleString attributeId,
- @Exclusive @Cached ReadGlobalOrBuiltinNode readGlobalNode) {
+ @Shared @Cached ReadGlobalOrBuiltinNode readGlobalNode) {
return readGlobalNode.execute(frame, attributeId);
}
@Specialization(guards = "hasLocals(frame)")
protected static Object readFromLocalsDict(VirtualFrame frame, TruffleString attributeId,
@Bind Node inliningTarget,
- @Cached ReadGlobalOrBuiltinNode.Lazy readGlobalOrBuiltinNode,
+ @Shared @Cached ReadGlobalOrBuiltinNode readGlobalNode,
@Cached ReadFromLocalsNode readFromLocals) {
Object result = readFromLocals.execute(frame, inliningTarget, PArguments.getSpecialArgument(frame), attributeId);
if (result == PNone.NO_VALUE) {
- return readGlobalOrBuiltinNode.get(inliningTarget).execute(frame, attributeId);
+ return readGlobalNode.execute(frame, attributeId);
} else {
return result;
}
diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/object/GetDictIfExistsNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/object/GetDictIfExistsNode.java
index 8350f0b75a..fc77df4d78 100644
--- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/object/GetDictIfExistsNode.java
+++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/object/GetDictIfExistsNode.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 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
@@ -68,6 +68,7 @@
import com.oracle.truffle.api.dsl.GenerateInline;
import com.oracle.truffle.api.dsl.GenerateUncached;
import com.oracle.truffle.api.dsl.Idempotent;
+import com.oracle.truffle.api.dsl.NeverDefault;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.library.CachedLibrary;
@@ -78,6 +79,11 @@
@GenerateUncached
@GenerateInline(false) // footprint reduction 36 -> 17
public abstract class GetDictIfExistsNode extends PNodeWithContext {
+ @NeverDefault
+ public static GetDictIfExistsNode create() {
+ return GetDictIfExistsNodeGen.create();
+ }
+
public abstract PDict execute(Object object);
public abstract PDict execute(PythonObject object);
@@ -111,7 +117,7 @@ protected boolean dictIsConstant(PythonObject object) {
return object instanceof PythonModule || object instanceof PythonManagedClass;
}
- protected static PDict getDictUncached(PythonObject object) {
+ public static PDict getDictUncached(PythonObject object) {
return (PDict) HiddenAttr.ReadNode.executeUncached(object, HiddenAttr.DICT, null);
}