Skip to content

Commit c492486

Browse files
committed
Avoid syncing class freevars to frame locals
1 parent d422933 commit c492486

File tree

3 files changed

+44
-27
lines changed

3 files changed

+44
-27
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_frame_tests.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ def test_lineno():
5151
def test_nested_lineno():
5252
def test_nested():
5353
return sys._getframe(0)
54+
5455
f = test_nested()
5556
assert f.f_lineno == 53
5657

@@ -67,9 +68,11 @@ def test_read_and_write_locals():
6768

6869
def test_backref():
6970
a = 'test_backref'
71+
7072
def foo():
7173
a = 'foo'
7274
return sys._getframe(0).f_back
75+
7376
assert foo().f_locals['a'] == 'test_backref'
7477

7578
def get_frame():
@@ -106,7 +109,7 @@ def foo(i):
106109
return stack
107110
else:
108111
# This recursive call will cause
109-
return foo(i+1)
112+
return foo(i + 1)
110113

111114
def bar():
112115
return foo(0)
@@ -151,6 +154,15 @@ def foo():
151154

152155
assert type(locals()['cell']).__name__ == 'cell'
153156

157+
158+
def test_locals_freevar_in_class():
159+
x = 1
160+
161+
class Foo:
162+
c = x
163+
assert 'c' in locals()
164+
assert 'x' not in locals()
165+
154166
# GR-22089
155167
# def test_backref_from_traceback():
156168
# def bar():

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/PBytecodeRootNode.java

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2971,7 +2971,7 @@ private void invokeTraceFunction(VirtualFrame virtualFrame, Object arg, PythonCo
29712971
// Force locals dict sync, so that we can sync them back later
29722972
GetFrameLocalsNode.getUncached().execute(pyFrame);
29732973
Object result = CallTernaryMethodNode.getUncached().execute(null, traceFn, pyFrame, event.pythonName, nonNullArg);
2974-
syncLocalsBack(virtualFrame, pyFrame);
2974+
syncLocalsBackToFrame(virtualFrame, pyFrame);
29752975
Object realResult = result == PNone.NONE ? null : result;
29762976
pyFrame.setLocalTraceFun(realResult);
29772977
} catch (Throwable e) {
@@ -2985,34 +2985,12 @@ private void invokeTraceFunction(VirtualFrame virtualFrame, Object arg, PythonCo
29852985
}
29862986
}
29872987

2988-
// PyFrame_LocalsToFast
2989-
private void syncLocalsBack(VirtualFrame virtualFrame, PFrame pyFrame) {
2988+
private void syncLocalsBackToFrame(VirtualFrame virtualFrame, PFrame pyFrame) {
29902989
Frame localFrame = virtualFrame;
29912990
if (co.isGeneratorOrCoroutine()) {
29922991
localFrame = PArguments.getGeneratorFrame(virtualFrame);
29932992
}
2994-
Object localsDict = pyFrame.getLocalsDict();
2995-
copyLocalsArray(localFrame, localsDict, varnames, 0, false);
2996-
copyLocalsArray(localFrame, localsDict, cellvars, celloffset, true);
2997-
copyLocalsArray(localFrame, localsDict, freevars, freeoffset, true);
2998-
}
2999-
3000-
private static void copyLocalsArray(Frame localFrame, Object localsDict, TruffleString[] namesArray, int offset, boolean deref) {
3001-
for (int i = 0; i < namesArray.length; i++) {
3002-
TruffleString varname = namesArray[i];
3003-
Object value = null;
3004-
try {
3005-
value = PyObjectGetItem.getUncached().execute(null, localsDict, varname);
3006-
} catch (AbstractTruffleException e) {
3007-
// CPython ignores all exceptions
3008-
}
3009-
if (deref) {
3010-
PCell cell = (PCell) localFrame.getObject(offset + i);
3011-
cell.setRef(value);
3012-
} else {
3013-
localFrame.setObject(offset + i, value);
3014-
}
3015-
}
2993+
GetFrameLocalsNode.syncLocalsBackToFrame(co, pyFrame, localFrame);
30162994
}
30172995

30182996
private void profileCEvent(VirtualFrame virtualFrame, Object callable, PythonContext.ProfileEvent event, MutableLoopData mutableData, boolean profilingEnabled) {
@@ -3054,7 +3032,7 @@ private void invokeProfileFunction(VirtualFrame virtualFrame, Object arg, Python
30543032
// Force locals dict sync, so that we can sync them back later
30553033
GetFrameLocalsNode.getUncached().execute(pyFrame);
30563034
Object result = CallTernaryMethodNode.getUncached().execute(null, profileFun, pyFrame, event.name, arg == null ? PNone.NONE : arg);
3057-
syncLocalsBack(virtualFrame, pyFrame);
3035+
syncLocalsBackToFrame(virtualFrame, pyFrame);
30583036
Object realResult = result == PNone.NONE ? null : result;
30593037
pyFrame.setLocalTraceFun(realResult);
30603038
} catch (Throwable e) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/GetFrameLocalsNode.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import com.oracle.graal.python.builtins.objects.frame.PFrame;
4646
import com.oracle.graal.python.compiler.CodeUnit;
4747
import com.oracle.graal.python.lib.PyDictDelItem;
48+
import com.oracle.graal.python.lib.PyDictGetItem;
4849
import com.oracle.graal.python.lib.PyDictSetItem;
4950
import com.oracle.graal.python.nodes.bytecode.FrameInfo;
5051
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
@@ -55,6 +56,7 @@
5556
import com.oracle.truffle.api.dsl.Idempotent;
5657
import com.oracle.truffle.api.dsl.NeverDefault;
5758
import com.oracle.truffle.api.dsl.Specialization;
59+
import com.oracle.truffle.api.frame.Frame;
5860
import com.oracle.truffle.api.frame.FrameDescriptor;
5961
import com.oracle.truffle.api.frame.MaterializedFrame;
6062
import com.oracle.truffle.api.nodes.ExplodeLoop;
@@ -143,6 +145,31 @@ protected static FrameInfo getInfo(FrameDescriptor fd) {
143145
}
144146
}
145147

148+
/**
149+
* Equivalent of CPython's {@code PyFrame_LocalsToFast}
150+
*/
151+
public static void syncLocalsBackToFrame(CodeUnit co, PFrame pyFrame, Frame localFrame) {
152+
if (!pyFrame.hasCustomLocals()) {
153+
PDict localsDict = (PDict) pyFrame.getLocalsDict();
154+
copyLocalsArray(localFrame, localsDict, co.varnames, 0, false);
155+
copyLocalsArray(localFrame, localsDict, co.cellvars, co.varnames.length, true);
156+
copyLocalsArray(localFrame, localsDict, co.freevars, co.varnames.length + co.cellvars.length, true);
157+
}
158+
}
159+
160+
private static void copyLocalsArray(Frame localFrame, PDict localsDict, TruffleString[] namesArray, int offset, boolean deref) {
161+
for (int i = 0; i < namesArray.length; i++) {
162+
TruffleString varname = namesArray[i];
163+
Object value = PyDictGetItem.getUncached().execute(null, localsDict, varname);
164+
if (deref) {
165+
PCell cell = (PCell) localFrame.getObject(offset + i);
166+
cell.setRef(value);
167+
} else {
168+
localFrame.setObject(offset + i, value);
169+
}
170+
}
171+
}
172+
146173
@NeverDefault
147174
public static GetFrameLocalsNode create() {
148175
return GetFrameLocalsNodeGen.create();

0 commit comments

Comments
 (0)