Skip to content

Commit 8d2eba8

Browse files
committed
go the route of a thread-local to make load the full path of a java import
1 parent a8672dd commit 8d2eba8

File tree

5 files changed

+69
-32
lines changed

5 files changed

+69
-32
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
import static com.oracle.graal.python.nodes.BuiltinNames.__BUILTIN__;
6262
import static com.oracle.graal.python.nodes.BuiltinNames.__DEBUG__;
6363
import static com.oracle.graal.python.nodes.BuiltinNames.__DUMP_TRUFFLE_AST__;
64+
import static com.oracle.graal.python.nodes.BuiltinNames.__JYTHON_CURRENT_IMPORT__;
6465
import static com.oracle.graal.python.nodes.HiddenAttributes.ID_KEY;
6566
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__NAME__;
6667
import static com.oracle.graal.python.nodes.SpecialMethodNames.__INSTANCECHECK__;
@@ -1881,6 +1882,15 @@ protected static boolean isFunction(Object callee) {
18811882
}
18821883
}
18831884

1885+
@Builtin(name = __JYTHON_CURRENT_IMPORT__, minNumOfPositionalArgs = 0)
1886+
@GenerateNodeFactory
1887+
public abstract static class CurrentImport extends PythonBuiltinNode {
1888+
@Specialization
1889+
String doIt() {
1890+
return getContext().getCurrentImport();
1891+
}
1892+
}
1893+
18841894
@Builtin(name = "input", parameterNames = {"prompt"})
18851895
@GenerateNodeFactory
18861896
abstract static class InputNode extends PythonUnaryBuiltinNode {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/BuiltinNames.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,4 +135,5 @@ public abstract class BuiltinNames {
135135
// truffle specific builtins
136136
public static final String __BUILTIN__ = "__builtin__";
137137
public static final String __DUMP_TRUFFLE_AST__ = "__dump_truffle_ast__";
138+
public static final String __JYTHON_CURRENT_IMPORT__ = "__jython_current_import__";
138139
}

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

Lines changed: 19 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -58,22 +58,19 @@
5858
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
5959
import com.oracle.truffle.api.CompilerDirectives;
6060
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
61-
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
6261
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
63-
import com.oracle.truffle.api.TruffleLanguage.Env;
6462
import com.oracle.truffle.api.frame.VirtualFrame;
6563
import com.oracle.truffle.api.instrumentation.StandardTags;
6664
import com.oracle.truffle.api.instrumentation.Tag;
67-
import com.oracle.truffle.api.profiles.BranchProfile;
6865

6966
public abstract class AbstractImportNode extends StatementNode {
7067
@CompilationFinal private ContextReference<PythonContext> contextRef;
7168
@Child PythonObjectFactory objectFactory;
7269

73-
private final BranchProfile emulatesJython = BranchProfile.create();
7470
@Child private CallNode callNode;
7571
@Child private GetDictNode getDictNode;
7672
@Child private PassCaughtExceptionNode passExceptionNode;
73+
@CompilationFinal private Boolean emulateJython;
7774

7875
public AbstractImportNode() {
7976
super();
@@ -127,37 +124,19 @@ protected Object importModule(VirtualFrame frame, String name, Object globals, S
127124
return builtinModule;
128125
}
129126
}
130-
Env env = getContext().getEnv();
131-
if (env.isHostLookupAllowed() && PythonOptions.getOption(env, PythonOptions.EmulateJython)) {
132-
emulatesJython.enter();
133-
forceClassloadingOnImport(name, fromList);
127+
if (emulateJython()) {
128+
if (fromList.length > 0) {
129+
getContext().pushCurrentImport(name + "." + fromList[0]);
130+
} else {
131+
getContext().pushCurrentImport(name);
132+
}
134133
}
135-
return __import__(frame, name, globals, fromList, level);
136-
}
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();
148134
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;
135+
return __import__(frame, name, globals, fromList, level);
136+
} finally {
137+
if (emulateJython()) {
138+
getContext().popCurrentImport();
158139
}
159-
// if we got here, we can stop. the package was loaded
160-
break;
161140
}
162141
}
163142

@@ -174,6 +153,14 @@ Object __import__(VirtualFrame frame, String name, Object globals, String[] from
174153
});
175154
}
176155

156+
private boolean emulateJython() {
157+
if (emulateJython == null) {
158+
CompilerDirectives.transferToInterpreterAndInvalidate();
159+
emulateJython = PythonOptions.getFlag(getContext(), PythonOptions.EmulateJython);
160+
}
161+
return emulateJython;
162+
}
163+
177164
@Override
178165
public boolean hasTag(Class<? extends Tag> tag) {
179166
return tag == StandardTags.CallTag.class || super.hasTag(tag);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import java.util.ArrayList;
4040
import java.util.HashMap;
4141
import java.util.List;
42+
import java.util.Stack;
4243
import java.util.concurrent.atomic.AtomicLong;
4344
import java.util.concurrent.locks.ReentrantLock;
4445
import java.util.function.Supplier;
@@ -142,6 +143,9 @@ public final class PythonContext {
142143
private final PosixResources resources;
143144
private final AsyncHandler handler;
144145

146+
// A thread-local to store the full path to the currently active import statement, for Jython compat
147+
private final ThreadLocal<Stack<String>> currentImport = ThreadLocal.withInitial(() -> new Stack<>());
148+
145149
public PythonContext(PythonLanguage language, TruffleLanguage.Env env, PythonCore core) {
146150
this.language = language;
147151
this.core = core;
@@ -721,4 +725,24 @@ public boolean isPyFileInLanguageHome(TruffleFile path) {
721725
PythonLanguage.getLogger().log(Level.FINE, () -> "Cannot access file " + path + " because there is no language home.");
722726
return false;
723727
}
728+
729+
@TruffleBoundary
730+
public String getCurrentImport() {
731+
Stack<String> ci = currentImport.get();
732+
if (ci.isEmpty()) {
733+
return "";
734+
} else {
735+
return ci.peek();
736+
}
737+
}
738+
739+
@TruffleBoundary
740+
public void pushCurrentImport(String object) {
741+
currentImport.get().push(object);
742+
}
743+
744+
@TruffleBoundary
745+
public void popCurrentImport() {
746+
currentImport.get().pop();
747+
}
724748
}

graalpython/lib-graalpython/java.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,16 @@ class JavaImportFinder:
130130
if sys.graal_python_jython_emulation_enabled:
131131
@staticmethod
132132
def find_spec(fullname, path, target=None):
133+
# Because of how Jython allows you to import classes that have not
134+
# been loaded, yet, we need attempt to load types with the full
135+
# string. This will ensure that if there is such a Java class, its
136+
# package will have been initialized and thus the is_java_package
137+
# check below will work
138+
try:
139+
type(__jython_current_import__())
140+
except KeyError:
141+
pass
142+
# continue normally with import
133143
if JavaPackageLoader.is_java_package(fullname):
134144
return _frozen_importlib.ModuleSpec(fullname, JavaPackageLoader, is_package=True)
135145
else:
@@ -151,3 +161,8 @@ def find_spec(fullname, path, target=None):
151161
sys.meta_path.append(JavaImportFinder)
152162
if sys.graal_python_jython_emulation_enabled:
153163
__getattr__ = JavaPackageLoader._make_getattr("java")
164+
else:
165+
# remove __jython_current_import__ function from builtins module
166+
import builtins
167+
del builtins.__jython_current_import__
168+
del builtins

0 commit comments

Comments
 (0)