Skip to content

Commit a6f0a88

Browse files
DSouzaMsteve-s
authored andcommitted
Bytecode DSL interpreter migration
1 parent 3567276 commit a6f0a88

File tree

169 files changed

+13898
-1761
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

169 files changed

+13898
-1761
lines changed

graalpython/com.oracle.graal.python.benchmarks/python/harness.py

+3
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,9 @@ def run_benchmark(args):
501501
else:
502502
print("### no extra module search paths specified")
503503

504+
if GRAALPYTHON:
505+
print(f"### using bytecode DSL interpreter: {__graalpython__.is_bytecode_dsl_interpreter}")
506+
504507
BenchRunner(bench_file, bench_args=bench_args, iterations=iterations, warmup=warmup, warmup_runs=warmup_runs, startup=startup, live_results=live_results).run()
505508

506509

graalpython/com.oracle.graal.python.frozen/freeze_modules.py

+15-9
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ def relpath_for_posix_display(path, base):
155155
#######################################
156156
# specs
157157

158-
def parse_frozen_specs():
158+
def parse_frozen_specs(suffix):
159159
seen = {}
160160
for section, specs in FROZEN:
161161
parsed = _parse_specs(specs, section, seen)
@@ -164,7 +164,7 @@ def parse_frozen_specs():
164164
try:
165165
source = seen[frozenid]
166166
except KeyError:
167-
source = FrozenSource.from_id(frozenid, pyfile)
167+
source = FrozenSource.from_id(frozenid, suffix, pyfile)
168168
seen[frozenid] = source
169169
else:
170170
assert not pyfile or pyfile == source.pyfile, item
@@ -272,11 +272,11 @@ def iter_subs():
272272
class FrozenSource(namedtuple('FrozenSource', 'id pyfile frozenfile deepfreezefile')):
273273

274274
@classmethod
275-
def from_id(cls, frozenid, pyfile=None):
275+
def from_id(cls, frozenid, suffix, pyfile=None):
276276
if not pyfile:
277277
pyfile = os.path.join(STDLIB_DIR, *frozenid.split('.')) + '.py'
278278
#assert os.path.exists(pyfile), (frozenid, pyfile)
279-
frozenfile = resolve_frozen_file(frozenid, FROZEN_MODULES_DIR)
279+
frozenfile = resolve_frozen_file(frozenid, FROZEN_MODULES_DIR, suffix)
280280
return cls(frozenid, pyfile, frozenfile, STDLIB_DIR)
281281

282282
@classmethod
@@ -312,7 +312,7 @@ def isbootstrap(self):
312312
return self.id in BOOTSTRAP
313313

314314

315-
def resolve_frozen_file(frozenid, destdir):
315+
def resolve_frozen_file(frozenid, destdir, suffix):
316316
"""Return the filename corresponding to the given frozen ID.
317317
318318
For stdlib modules the ID will always be the full name
@@ -325,7 +325,7 @@ def resolve_frozen_file(frozenid, destdir):
325325
raise ValueError(f'unsupported frozenid {frozenid!r}')
326326
# We use a consistent naming convention for all frozen modules.
327327
frozen_symbol = FrozenSource.resolve_symbol(frozenid)
328-
frozenfile = f"Frozen{frozen_symbol}.bin"
328+
frozenfile = f"Frozen{frozen_symbol}.{suffix}"
329329

330330
if not destdir:
331331
return frozenfile
@@ -635,11 +635,17 @@ def main():
635635
STDLIB_DIR = os.path.abspath(parsed_args.python_lib)
636636
FROZEN_MODULES_DIR = os.path.abspath(parsed_args.binary_dir)
637637

638+
if __graalpython__.is_bytecode_dsl_interpreter:
639+
suffix = "bin_dsl"
640+
assert os.path.isdir(parsed_args.binary_dir), "Frozen modules for the DSL should be built after the manual bytecode interpreter."
641+
else:
642+
suffix = "bin"
643+
shutil.rmtree(parsed_args.binary_dir, ignore_errors=True)
644+
os.makedirs(parsed_args.binary_dir)
645+
638646
# create module specs
639-
modules = list(parse_frozen_specs())
647+
modules = list(parse_frozen_specs(suffix))
640648

641-
shutil.rmtree(parsed_args.binary_dir, ignore_errors=True)
642-
os.makedirs(parsed_args.binary_dir)
643649
# write frozen module binary files containing the byte code and class files
644650
# used for importing the binary files
645651
for src in _iter_sources(modules):

graalpython/com.oracle.graal.python.pegparser.test/src/com/oracle/graal/python/pegparser/test/LambdaInFunctionTests.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -41,8 +41,10 @@
4141

4242
package com.oracle.graal.python.pegparser.test;
4343

44+
import org.junit.Ignore;
4445
import org.junit.Test;
4546

47+
@Ignore // GR-62729
4648
public class LambdaInFunctionTests extends ParserTestBase {
4749

4850
@Test

graalpython/com.oracle.graal.python.pegparser.test/src/com/oracle/graal/python/pegparser/test/YieldStatementTests.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -41,6 +41,7 @@
4141

4242
package com.oracle.graal.python.pegparser.test;
4343

44+
import org.junit.Ignore;
4445
import org.junit.Test;
4546

4647
public class YieldStatementTests extends ParserTestBase {
@@ -148,6 +149,7 @@ public void customIter01() throws Exception {
148149
}
149150

150151
@Test
152+
@Ignore // GR-62729
151153
public void yield17() throws Exception {
152154
checkScopeAndTree("generator = type((lambda: (yield))())");
153155
}

graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/scope/Scope.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -229,11 +229,15 @@ public boolean isNested() {
229229
}
230230

231231
public HashMap<String, Integer> getSymbolsByType(EnumSet<DefUse> expectedFlags, int start) {
232+
return getSymbolsByType(expectedFlags, EnumSet.noneOf(DefUse.class), start);
233+
}
234+
235+
public HashMap<String, Integer> getSymbolsByType(EnumSet<DefUse> expectedFlags, EnumSet<DefUse> unexpectedFlags, int start) {
232236
int i = start;
233237
HashMap<String, Integer> mapping = new HashMap<>();
234238
for (String key : getSortedSymbols()) {
235239
EnumSet<DefUse> keyFlags = getUseOfName(key);
236-
if (!Collections.disjoint(expectedFlags, keyFlags)) {
240+
if (!Collections.disjoint(expectedFlags, keyFlags) && Collections.disjoint(unexpectedFlags, keyFlags)) {
237241
mapping.put(key, i++);
238242
}
239243
}

graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/scope/ScopeEnvironment.java

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -98,6 +98,7 @@ public class ScopeEnvironment {
9898
final HashMap<SSTNode, Scope> blocks = new HashMap<>();
9999
final ErrorCallback errorCallback;
100100
final EnumSet<FutureFeature> futureFeatures;
101+
final HashMap<Scope, Scope> parents = new HashMap<>();
101102

102103
public static ScopeEnvironment analyze(ModTy moduleNode, ErrorCallback errorCallback, EnumSet<FutureFeature> futureFeatures) {
103104
return new ScopeEnvironment(moduleNode, errorCallback, futureFeatures);
@@ -128,6 +129,14 @@ public Scope lookupScope(SSTNode node) {
128129
return blocks.get(node);
129130
}
130131

132+
public Scope lookupParent(Scope scope) {
133+
return parents.get(scope);
134+
}
135+
136+
public Scope getTopScope() {
137+
return topScope;
138+
}
139+
131140
private void analyzeBlock(Scope scope, HashSet<String> bound, HashSet<String> free, HashSet<String> global) {
132141
HashSet<String> local = new HashSet<>();
133142
HashMap<String, DefUse> scopes = new HashMap<>();
@@ -328,6 +337,7 @@ private void enterBlock(String name, Scope.ScopeType type, SSTNode ast) {
328337
if (type == Scope.ScopeType.Annotation) {
329338
return;
330339
}
340+
env.parents.put(scope, prev);
331341
if (prev != null) {
332342
prev.children.add(scope);
333343
}
@@ -635,7 +645,7 @@ public Void visit(ExprTy.Lambda node) {
635645
visitSequence(node.args.defaults);
636646
visitSequence(node.args.kwDefaults);
637647
}
638-
enterBlock("lambda", ScopeType.Function, node);
648+
enterBlock("<lambda>", ScopeType.Function, node);
639649
try {
640650
if (node.args != null) {
641651
node.args.accept(this);

graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonMain.java

+5
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,11 @@ protected List<String> preprocessArguments(List<String> givenArgs, Map<String, S
420420
}
421421
}
422422

423+
if (!ImageInfo.inImageCode() && Boolean.getBoolean("python.EnableBytecodeDSLInterpreter")) {
424+
// forward the property on JVM
425+
addRelaunchArg("--vm.Dpython.EnableBytecodeDSLInterpreter=true");
426+
}
427+
423428
// According to CPython if no arguments are given, they contain an empty string.
424429
if (programArgs.isEmpty()) {
425430
programArgs.add("");

graalpython/com.oracle.graal.python.test.integration/src/com/oracle/graal/python/test/integration/generator/GeneratorTests.java

+117-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2023, Oracle and/or its affiliates.
2+
* Copyright (c) 2017, 2025, Oracle and/or its affiliates.
33
* Copyright (c) 2013, Regents of the University of California
44
*
55
* All rights reserved.
@@ -72,7 +72,7 @@ public void desugared() {
7272
}
7373

7474
@Test
75-
public void testYieldFrom() {
75+
public void testYieldFromSimple() {
7676
String source = "def gen1():\n" +
7777
" yield 1\n" +
7878
" yield 2\n" +
@@ -83,4 +83,119 @@ public void testYieldFrom() {
8383
"print(list(gen2()))\n";
8484
assertPrints("[1, 2]\n", source);
8585
}
86+
87+
@Test
88+
public void testYieldFromIterable() {
89+
// yield from should extract an iterator from a non-generator argument
90+
String source = "class Foo:\n" +
91+
" def __init__(self, wrapped):\n" +
92+
" self.wrapped = wrapped\n" +
93+
" def __iter__(self):\n" +
94+
" return iter(self.wrapped)\n" +
95+
"def gen():\n" +
96+
" foo = Foo([1,2,3])\n" +
97+
" yield from foo\n" +
98+
"\n" +
99+
"print(list(gen()))\n";
100+
assertPrints("[1, 2, 3]\n", source);
101+
}
102+
103+
@Test
104+
public void testYieldFromReturn() {
105+
String source = "def gen1():\n" +
106+
" yield 1\n" +
107+
" yield 2\n" +
108+
" return 3\n" +
109+
"\n" +
110+
"def gen2():\n" +
111+
" final = yield from gen1()\n" +
112+
" yield final\n" +
113+
"\n" +
114+
"print(list(gen2()))\n";
115+
assertPrints("[1, 2, 3]\n", source);
116+
}
117+
118+
@Test
119+
public void testYieldFromSend() {
120+
String source = "def gen1(x):\n" +
121+
" yield (yield (yield x))\n" +
122+
"\n" +
123+
"def gen2():\n" +
124+
" yield from gen1(2)\n" +
125+
" yield 8\n" +
126+
"\n" +
127+
"gen = gen2()\n" +
128+
"print(gen.send(None))\n" +
129+
"print(gen.send(4))\n" +
130+
"print(gen.send(6))\n" +
131+
"print(gen.send(42))\n";
132+
assertPrints("2\n4\n6\n8\n", source);
133+
}
134+
135+
@Test
136+
public void testYieldFromThrowCaught() {
137+
String source = "def gen1():\n" +
138+
" try:\n" +
139+
" x = 1\n" +
140+
" while True:\n" +
141+
" x = yield x\n" +
142+
" except ValueError:\n" +
143+
" yield 42\n" +
144+
"\n" +
145+
"def gen2():\n" +
146+
" yield from gen1()\n" +
147+
"\n" +
148+
"gen = gen2()\n" +
149+
"print(gen.send(None))\n" +
150+
"print(gen.send(2))\n" +
151+
"print(gen.send(3))\n" +
152+
"print(gen.throw(ValueError))\n";
153+
assertPrints("1\n2\n3\n42\n", source);
154+
}
155+
156+
@Test
157+
public void testYieldFromThrowUncaught() {
158+
String source = "def gen1():\n" +
159+
" x = 1\n" +
160+
" while True:\n" +
161+
" x = yield x\n" +
162+
"\n" +
163+
"def gen2():\n" +
164+
" yield from gen1()\n" +
165+
"\n" +
166+
"gen = gen2()\n" +
167+
"print(gen.send(None))\n" +
168+
"print(gen.send(2))\n" +
169+
"print(gen.send(3))\n" +
170+
"try:\n" +
171+
" gen.throw(ValueError)\n" +
172+
" print('error')\n" +
173+
"except ValueError:\n" +
174+
" print('success')\n";
175+
assertPrints("1\n2\n3\nsuccess\n", source);
176+
}
177+
178+
@Test
179+
public void testYieldFromClose() {
180+
String source = "def gen1():\n" +
181+
" x = 1\n" +
182+
" try:\n" +
183+
" while True:\n" +
184+
" x = yield x\n" +
185+
" except GeneratorExit:\n" +
186+
" print('gen1 exit')\n" +
187+
"\n" +
188+
"def gen2():\n" +
189+
" try:\n" +
190+
" yield from gen1()\n" +
191+
" except GeneratorExit:\n" +
192+
" print('gen2 exit')\n" +
193+
"\n" +
194+
"gen = gen2()\n" +
195+
"print(gen.send(None))\n" +
196+
"print(gen.send(2))\n" +
197+
"print(gen.send(3))\n" +
198+
"gen.close()\n";
199+
assertPrints("1\n2\n3\ngen1 exit\ngen2 exit\n", source);
200+
}
86201
}

0 commit comments

Comments
 (0)