|
54 | 54 | import com.oracle.graal.python.nodes.object.GetDictNode;
|
55 | 55 | import com.oracle.graal.python.nodes.util.ExceptionStateNodes.PassCaughtExceptionNode;
|
56 | 56 | import com.oracle.graal.python.runtime.PythonContext;
|
| 57 | +import com.oracle.graal.python.runtime.PythonOptions; |
57 | 58 | import com.oracle.graal.python.runtime.object.PythonObjectFactory;
|
58 | 59 | import com.oracle.truffle.api.CompilerDirectives;
|
59 | 60 | import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
|
| 61 | +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; |
60 | 62 | import com.oracle.truffle.api.TruffleLanguage.ContextReference;
|
| 63 | +import com.oracle.truffle.api.TruffleLanguage.Env; |
61 | 64 | import com.oracle.truffle.api.frame.VirtualFrame;
|
62 | 65 | import com.oracle.truffle.api.instrumentation.StandardTags;
|
63 | 66 | import com.oracle.truffle.api.instrumentation.Tag;
|
| 67 | +import com.oracle.truffle.api.profiles.BranchProfile; |
64 | 68 |
|
65 | 69 | public abstract class AbstractImportNode extends StatementNode {
|
66 | 70 | @CompilationFinal private ContextReference<PythonContext> contextRef;
|
67 | 71 | @Child PythonObjectFactory objectFactory;
|
68 | 72 |
|
| 73 | + private final BranchProfile emulatesJython = BranchProfile.create(); |
69 | 74 | @Child private CallNode callNode;
|
70 | 75 | @Child private GetDictNode getDictNode;
|
71 | 76 | @Child private PassCaughtExceptionNode passExceptionNode;
|
@@ -122,9 +127,40 @@ protected Object importModule(VirtualFrame frame, String name, Object globals, S
|
122 | 127 | return builtinModule;
|
123 | 128 | }
|
124 | 129 | }
|
| 130 | + Env env = getContext().getEnv(); |
| 131 | + if (env.isHostLookupAllowed() && PythonOptions.getOption(env, PythonOptions.EmulateJython)) { |
| 132 | + emulatesJython.enter(); |
| 133 | + forceClassloadingOnImport(name, fromList); |
| 134 | + } |
125 | 135 | return __import__(frame, name, globals, fromList, level);
|
126 | 136 | }
|
127 | 137 |
|
| 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 | + |
128 | 164 | Object __import__(VirtualFrame frame, String name, Object globals, String[] fromList, int level) {
|
129 | 165 | PMethod builtinImport = (PMethod) getContext().getCore().lookupBuiltinModule(BuiltinNames.BUILTINS).getAttribute(__IMPORT__);
|
130 | 166 | assert fromList != null;
|
|
0 commit comments