Skip to content

Commit 392ee71

Browse files
committed
force classloading when we import and we are emulating jython.
It seems to me this is the only way to reliably ensure that when a Java class is imported that is not yet loaded that it will be listed in java.lang.Package.getPackages() so we can reliably detect Java packages. This is unfortunate, but importing is already slow in Jython mode, so I guess it won't hurt us any more than it already does.
1 parent cb4843e commit 392ee71

File tree

1 file changed

+36
-0
lines changed

1 file changed

+36
-0
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/AbstractImportNode.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,18 +54,23 @@
5454
import com.oracle.graal.python.nodes.object.GetDictNode;
5555
import com.oracle.graal.python.nodes.util.ExceptionStateNodes.PassCaughtExceptionNode;
5656
import com.oracle.graal.python.runtime.PythonContext;
57+
import com.oracle.graal.python.runtime.PythonOptions;
5758
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
5859
import com.oracle.truffle.api.CompilerDirectives;
5960
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
61+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
6062
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
63+
import com.oracle.truffle.api.TruffleLanguage.Env;
6164
import com.oracle.truffle.api.frame.VirtualFrame;
6265
import com.oracle.truffle.api.instrumentation.StandardTags;
6366
import com.oracle.truffle.api.instrumentation.Tag;
67+
import com.oracle.truffle.api.profiles.BranchProfile;
6468

6569
public abstract class AbstractImportNode extends StatementNode {
6670
@CompilationFinal private ContextReference<PythonContext> contextRef;
6771
@Child PythonObjectFactory objectFactory;
6872

73+
private final BranchProfile emulatesJython = BranchProfile.create();
6974
@Child private CallNode callNode;
7075
@Child private GetDictNode getDictNode;
7176
@Child private PassCaughtExceptionNode passExceptionNode;
@@ -122,9 +127,40 @@ protected Object importModule(VirtualFrame frame, String name, Object globals, S
122127
return builtinModule;
123128
}
124129
}
130+
Env env = getContext().getEnv();
131+
if (env.isHostLookupAllowed() && PythonOptions.getOption(env, PythonOptions.EmulateJython)) {
132+
emulatesJython.enter();
133+
forceClassloadingOnImport(name, fromList);
134+
}
125135
return __import__(frame, name, globals, fromList, level);
126136
}
127137

138+
/**
139+
* Because of how Jython allows you to import classes that have not been
140+
* loaded, yet, we need attempt to load types here, while we have the full
141+
* string available. this will ensure that if there is such a Java class,
142+
* its package will have been initialized and the importer code in java.py
143+
* can find it.
144+
*/
145+
@TruffleBoundary
146+
private void forceClassloadingOnImport(String name, String[] fromList) {
147+
Env env = getContext().getEnv();
148+
try {
149+
env.lookupHostSymbol(name);
150+
} catch (RuntimeException e) {
151+
// ignore this, that's fine
152+
}
153+
for (String potentialClass : fromList) {
154+
try {
155+
env.lookupHostSymbol(name + "." + potentialClass);
156+
} catch (RuntimeException e) {
157+
continue;
158+
}
159+
// if we got here, we can stop. the package was loaded
160+
break;
161+
}
162+
}
163+
128164
Object __import__(VirtualFrame frame, String name, Object globals, String[] fromList, int level) {
129165
PMethod builtinImport = (PMethod) getContext().getCore().lookupBuiltinModule(BuiltinNames.BUILTINS).getAttribute(__IMPORT__);
130166
assert fromList != null;

0 commit comments

Comments
 (0)