Skip to content

Commit 1d1d305

Browse files
committed
[GR-69672] Optimize frozen module footprint
PullRequest: graalpython/4003
2 parents 5967cf6 + ab947cb commit 1d1d305

File tree

15 files changed

+475
-916
lines changed

15 files changed

+475
-916
lines changed

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,20 @@
4444
('stdlib - startup, without site (python -S)', [
4545
'abc',
4646
'codecs',
47-
'<encodings.*>',
47+
# GraalPy change: don't freeze all the encodings, we have our own intrinsified encodings
48+
'<encodings>',
49+
'encodings.aliases',
4850
'io',
4951
]),
5052
('stdlib - startup, with site', [
5153
'_py_abc',
5254
'_weakrefset',
5355
'types',
5456
'enum',
55-
'sre_constants',
56-
'sre_parse',
57-
'sre_compile',
57+
# GraalPy change: don't freeze these, they are deprecated, CPython probably just forgot to remove them from here
58+
# 'sre_constants',
59+
# 'sre_parse',
60+
# 'sre_compile',
5861
'operator',
5962
'keyword',
6063
'heapq',
@@ -553,7 +556,8 @@ def lower_camel_case(str):
553556
def freeze_module(src):
554557
with open(src.pyfile, "r", encoding="utf-8") as src_file, open(src.frozenfile, "wb") as binary_file:
555558
code_obj = compile(src_file.read(), f"<frozen {src.id}>", "exec")
556-
marshal.dump(code_obj, binary_file)
559+
# GraalPy note: we don't use marshal here, we just dump the co_code which implicitly marshals the code unit
560+
binary_file.write(code_obj.co_code)
557561

558562

559563
def write_frozen_modules_map(out_file, modules):

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -569,43 +569,7 @@ protected CallTarget parse(ParsingRequest request) {
569569
if (MIME_TYPE_BYTECODE.equals(source.getMimeType())) {
570570
byte[] bytes = source.getBytes().toByteArray();
571571
CodeUnit code = MarshalModuleBuiltins.deserializeCodeUnit(null, context, bytes);
572-
boolean internal = shouldMarkSourceInternal(context);
573-
// The original file path should be passed as the name
574-
String name = source.getName();
575-
if (name != null && !name.isEmpty()) {
576-
Source textSource = tryLoadSource(context, code, internal, name);
577-
if (textSource == null) {
578-
if (name.startsWith(FROZEN_FILENAME_PREFIX) && name.endsWith(FROZEN_FILENAME_SUFFIX)) {
579-
String id = name.substring(FROZEN_FILENAME_PREFIX.length(), name.length() - FROZEN_FILENAME_SUFFIX.length());
580-
String fs = context.getEnv().getFileNameSeparator();
581-
String path = context.getStdlibHome() + fs + id.replace(".", fs) + J_PY_EXTENSION;
582-
textSource = tryLoadSource(context, code, internal, path);
583-
if (textSource == null) {
584-
path = context.getStdlibHome() + fs + id.replace(".", fs) + fs + "__init__.py";
585-
textSource = tryLoadSource(context, code, internal, path);
586-
}
587-
}
588-
}
589-
if (textSource != null) {
590-
source = textSource;
591-
}
592-
}
593-
if (internal && !source.isInternal()) {
594-
source = Source.newBuilder(source).internal(true).build();
595-
}
596-
RootNode rootNode = null;
597-
598-
if (PythonOptions.ENABLE_BYTECODE_DSL_INTERPRETER) {
599-
if (source.hasBytes()) {
600-
// Force a character-based source so that source sections work as expected.
601-
source = Source.newBuilder(source).content(Source.CONTENT_NONE).build();
602-
}
603-
rootNode = ((BytecodeDSLCodeUnit) code).createRootNode(context, source);
604-
} else {
605-
rootNode = PBytecodeRootNode.create(this, (BytecodeCodeUnit) code, source);
606-
}
607-
608-
return PythonUtils.getOrCreateCallTarget(rootNode);
572+
return callTargetFromBytecode(context, source, code);
609573
}
610574

611575
String mime = source.getMimeType();
@@ -631,6 +595,46 @@ protected CallTarget parse(ParsingRequest request) {
631595
return parse(context, source, type, false, optimize, false, null, FutureFeature.fromFlags(flags));
632596
}
633597

598+
public RootCallTarget callTargetFromBytecode(PythonContext context, Source source, CodeUnit code) {
599+
boolean internal = shouldMarkSourceInternal(context);
600+
// The original file path should be passed as the name
601+
String name = source.getName();
602+
if (name != null && !name.isEmpty()) {
603+
Source textSource = tryLoadSource(context, code, internal, name);
604+
if (textSource == null) {
605+
if (name.startsWith(FROZEN_FILENAME_PREFIX) && name.endsWith(FROZEN_FILENAME_SUFFIX)) {
606+
String id = name.substring(FROZEN_FILENAME_PREFIX.length(), name.length() - FROZEN_FILENAME_SUFFIX.length());
607+
String fs = context.getEnv().getFileNameSeparator();
608+
String path = context.getStdlibHome() + fs + id.replace(".", fs) + J_PY_EXTENSION;
609+
textSource = tryLoadSource(context, code, internal, path);
610+
if (textSource == null) {
611+
path = context.getStdlibHome() + fs + id.replace(".", fs) + fs + "__init__.py";
612+
textSource = tryLoadSource(context, code, internal, path);
613+
}
614+
}
615+
}
616+
if (textSource != null) {
617+
source = textSource;
618+
}
619+
}
620+
if (internal && !source.isInternal()) {
621+
source = Source.newBuilder(source).internal(true).build();
622+
}
623+
RootNode rootNode;
624+
625+
if (PythonOptions.ENABLE_BYTECODE_DSL_INTERPRETER) {
626+
if (source.hasBytes()) {
627+
// Force a character-based source so that source sections work as expected.
628+
source = Source.newBuilder(source).content(Source.CONTENT_NONE).build();
629+
}
630+
rootNode = ((BytecodeDSLCodeUnit) code).createRootNode(context, source);
631+
} else {
632+
rootNode = PBytecodeRootNode.create(this, (BytecodeCodeUnit) code, source);
633+
}
634+
635+
return PythonUtils.getOrCreateCallTarget(rootNode);
636+
}
637+
634638
private static Source tryLoadSource(PythonContext context, CodeUnit code, boolean internal, String path) {
635639
try {
636640
return Source.newBuilder(PythonLanguage.ID, context.getEnv().getPublicTruffleFile(path)).name(code.name.toJavaStringUncached()).internal(internal).build();

0 commit comments

Comments
 (0)