Skip to content

Commit c565348

Browse files
committed
performance optimization: cheap explicit imports are checked first
1 parent 891bd5f commit c565348

1 file changed

Lines changed: 78 additions & 42 deletions

File tree

src/org/python/core/JavaImportHelper.java

Lines changed: 78 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package org.python.core;
22

3+
import java.util.ArrayList;
34
import java.util.Iterator;
5+
import java.util.List;
46
import java.util.Map;
57
import java.util.TreeMap;
68

@@ -9,6 +11,8 @@
911
*/
1012
public class JavaImportHelper {
1113

14+
private static final String DOT = ".";
15+
1216
/**
1317
* Try to add the java package.
1418
* <p>
@@ -24,56 +28,62 @@ public class JavaImportHelper {
2428
* @return <code>true</code> if a java package was doubtlessly identified and added, <code>false</code>
2529
* otherwise.
2630
*/
27-
protected static boolean tryAddPackage(String packageName, PyObject fromlist) {
31+
protected static boolean tryAddPackage(final String packageName, PyObject fromlist) {
2832
// make sure we do not turn off the added flag, once it is set
2933
boolean packageAdded = false;
3034

3135
if (packageName != null) {
32-
// build the actual map with the packages known to the VM
33-
Map packages = buildLoadedPackages();
36+
// check explicit imports first (performance optimization)
37+
38+
// handle 'from java.net import URL' like explicit imports
39+
List stringFromlist = getFromListAsStrings(fromlist);
40+
Iterator fromlistIterator = stringFromlist.iterator();
41+
while (fromlistIterator.hasNext()) {
42+
String fromName = (String) fromlistIterator.next();
43+
if (isJavaClass(packageName, fromName)) {
44+
packageAdded = addPackage(packageName, packageAdded);
3445

35-
// handle package name
36-
if (isLoadedPackage(packageName, packages)) {
37-
packageAdded = addPackage(packageName, packageAdded);
46+
}
3847
}
39-
String parentPackageName = packageName;
40-
int dotPos = 0;
41-
String lastDottedName = null;
42-
do {
43-
dotPos = parentPackageName.lastIndexOf(".");
44-
if (dotPos > 0) {
45-
parentPackageName = parentPackageName.substring(0, dotPos);
46-
if (isLoadedPackage(parentPackageName, packages)) {
47-
packageAdded = addPackage(parentPackageName, packageAdded);
48-
}
49-
// handle 'import java.net.URL' style explicit imports
50-
if (lastDottedName == null) {
51-
lastDottedName = packageName.substring(dotPos + 1);
52-
if (isJavaClass(parentPackageName, lastDottedName)) {
48+
49+
// handle 'import java.net.URL' style explicit imports
50+
int dotPos = packageName.lastIndexOf(DOT);
51+
if (dotPos > 0) {
52+
String lastDottedName = packageName.substring(dotPos + 1);
53+
String packageCand = packageName.substring(0, dotPos);
54+
if (isJavaClass(packageCand, lastDottedName)) {
55+
packageAdded = addPackage(packageCand, packageAdded);
56+
}
57+
}
58+
59+
// if all else fails, check already loaded packages
60+
if (!packageAdded) {
61+
// build the actual map with the packages known to the VM
62+
Map packages = buildLoadedPackages();
63+
64+
// add known packages
65+
String parentPackageName = packageName;
66+
if (isLoadedPackage(packageName, packages)) {
67+
packageAdded = addPackage(packageName, packageAdded);
68+
}
69+
dotPos = 0;
70+
do {
71+
dotPos = parentPackageName.lastIndexOf(DOT);
72+
if (dotPos > 0) {
73+
parentPackageName = parentPackageName.substring(0, dotPos);
74+
if (isLoadedPackage(parentPackageName, packages)) {
5375
packageAdded = addPackage(parentPackageName, packageAdded);
5476
}
5577
}
56-
}
57-
} while (dotPos > 0);
78+
} while (dotPos > 0);
5879

59-
// handle fromlist
60-
if (fromlist != null && fromlist != Py.EmptyTuple && fromlist instanceof PyTuple) {
61-
Iterator iterator = ((PyTuple) fromlist).iterator();
62-
while (iterator.hasNext()) {
63-
Object obj = iterator.next();
64-
if (obj instanceof String) {
65-
String fromName = (String) obj;
66-
if (!"*".equals(fromName)) {
67-
if (isJavaClass(packageName, fromName)) {
68-
packageAdded = addPackage(packageName, packageAdded);
69-
} else {
70-
// handle cases like: from java import math
71-
String fromPackageName = packageName + "." + fromName;
72-
if (isLoadedPackage(fromPackageName, packages)) {
73-
packageAdded = addPackage(fromPackageName, packageAdded);
74-
}
75-
}
76-
}
80+
// handle package imports like 'from java import math'
81+
fromlistIterator = stringFromlist.iterator();
82+
while (fromlistIterator.hasNext()) {
83+
String fromName = (String) fromlistIterator.next();
84+
String fromPackageName = packageName + DOT + fromName;
85+
if (isLoadedPackage(fromPackageName, packages)) {
86+
packageAdded = addPackage(fromPackageName, packageAdded);
7787
}
7888
}
7989
}
@@ -95,6 +105,32 @@ protected static boolean isLoadedPackage(String packageName) {
95105
return isLoadedPackage(packageName, buildLoadedPackages());
96106
}
97107

108+
/**
109+
* Convert the fromlist into a java.lang.String based list.
110+
* <p>
111+
* Do some sanity checks: filter out '*' and empty tuples, as well as non tuples.
112+
*
113+
* @param fromlist
114+
* @return a list containing java.lang.String entries
115+
*/
116+
private static final List getFromListAsStrings(PyObject fromlist) {
117+
List stringFromlist = new ArrayList();
118+
119+
if (fromlist != null && fromlist != Py.EmptyTuple && fromlist instanceof PyTuple) {
120+
Iterator iterator = ((PyTuple) fromlist).iterator();
121+
while (iterator.hasNext()) {
122+
Object obj = iterator.next();
123+
if (obj instanceof String) {
124+
String fromName = (String) obj;
125+
if (!"*".equals(fromName)) {
126+
stringFromlist.add(fromName);
127+
}
128+
}
129+
}
130+
}
131+
return stringFromlist;
132+
}
133+
98134
/**
99135
* Faster way to check if a java package is already known to the VM.
100136
* <p>
@@ -129,7 +165,7 @@ private static Map buildLoadedPackages() {
129165
packageMap.put(packageName, "");
130166
int dotPos = 0;
131167
do {
132-
dotPos = packageName.lastIndexOf(".");
168+
dotPos = packageName.lastIndexOf(DOT);
133169
if (dotPos > 0) {
134170
packageName = packageName.substring(0, dotPos);
135171
packageMap.put(packageName, "");
@@ -176,7 +212,7 @@ private static boolean addPackage(String packageName, boolean packageAdded) {
176212
PyJavaPackage p = PySystemState.add_package(packageName);
177213
Py.getSystemState().modules.__setitem__(internedPackageName, p);
178214
added = true;
179-
dotPos = packageName.lastIndexOf(".");
215+
dotPos = packageName.lastIndexOf(DOT);
180216
if (dotPos > 0) {
181217
packageName = packageName.substring(0, dotPos);
182218
}

0 commit comments

Comments
 (0)