Skip to content

Commit b52adfa

Browse files
committed
Add HLL::Compiler switch --with-cu and use parent ClassLoaders.
This allows us to package nested jars with e.g. one-jar, which I will also implement a flag for in HLL::Compiler. Using parent ClassLoaders for IgnoreNameClassloader and ByteCodeClassLoader is neccessary to chain into e.g. JarClassLoader (which one-jar uses) to find nested jars.
1 parent a5d6dda commit b52adfa

File tree

7 files changed

+135
-21
lines changed

7 files changed

+135
-21
lines changed

src/HLL/Compiler.nqp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class HLL::Compiler does HLL::Backend::Default {
2121
@!stages := nqp::split(' ', 'start parse ast ' ~ $!backend.stages());
2222

2323
# Command options and usage.
24-
@!cmdoptions := nqp::split(' ', 'e=s help|h target=s trace|t=s encoding=s output|o=s combine version|v show-config verbose-config|V stagestats=s? ll-exception rxtrace nqpevent=s profile profile-compile profile-filename=s');
24+
@!cmdoptions := nqp::split(' ', 'e=s help|h target=s trace|t=s encoding=s output|o=s combine version|v show-config verbose-config|V stagestats=s? ll-exception rxtrace nqpevent=s profile profile-compile profile-filename=s with-cu=s');
2525
%!config := nqp::hash();
2626
}
2727

@@ -259,6 +259,12 @@ class HLL::Compiler does HLL::Backend::Default {
259259
self.dumper($result, $target, |%adverbs);
260260
}
261261
}
262+
elsif %adverbs<with-cu> && nqp::can($!backend, 'with_cu') {
263+
while self.stages()[0] ne $!backend.cu_start_stage() {
264+
self.removestage(self.stages()[0]);
265+
}
266+
$result := $!backend.with_cu(%adverbs<with-cu>);
267+
}
262268
elsif !@a { $result := self.interactive(|%adverbs) }
263269
elsif %adverbs<combine> { $result := self.evalfiles(@a, |%adverbs) }
264270
else { $result := self.evalfiles(@a[0], |@a, |%adverbs) }

src/vm/jvm/HLL/Backend.nqp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,15 @@ class HLL::Backend::JVM {
109109
method compunit_coderefs($cu) {
110110
nqp::compunitcodes($cu)
111111
}
112+
113+
method cu_start_stage() {
114+
'jvm'
115+
}
116+
117+
method with_cu($cu) {
118+
my $*MAIN_CTX;
119+
nqp::loadbytecode($cu);
120+
}
112121
}
113122

114123
# Role specifying the default backend for this build.

src/vm/jvm/QAST/Compiler.nqp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2705,6 +2705,8 @@ QAST::OperationsJAST.add_core_op('getcodelocation', -> $qastcomp, $op {
27052705

27062706
QAST::OperationsJAST.map_classlib_core_op('getuniname', $TYPE_OPS, 'getuniname', [$RT_INT], $RT_STR, :tc);
27072707

2708+
QAST::OperationsJAST.map_classlib_core_op('getmoduleurl', $TYPE_OPS, 'getmoduleurl', [$RT_STR], $RT_STR, :tc);
2709+
27082710
class QAST::CompilerJAST {
27092711
# Responsible for handling issues around code references, building the
27102712
# switch statement dispatcher, etc.

src/vm/jvm/runtime/org/perl6/nqp/runtime/GlobalContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ public GlobalContext()
266266

267267
neverRepossess = new WeakHashMap<SixModelObject, Object>();
268268

269-
byteClassLoader = new ByteClassLoader();
269+
byteClassLoader = new ByteClassLoader(GlobalContext.class.getClassLoader());
270270
}
271271

272272
/**

src/vm/jvm/runtime/org/perl6/nqp/runtime/LibraryLoader.java

Lines changed: 86 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.perl6.nqp.runtime;
22

33
import java.io.ByteArrayInputStream;
4+
import java.io.ByteArrayOutputStream;
45
import java.io.File;
56
import java.io.IOException;
67
import java.io.InputStream;
@@ -10,23 +11,32 @@
1011
import java.util.HashMap;
1112
import java.util.jar.JarEntry;
1213
import java.util.jar.JarInputStream;
14+
import java.net.URL;
1315

1416
public class LibraryLoader {
1517
static HashMap<String,Class<?>> sharedClassHash = new HashMap<String,Class<?>>();
1618

1719
public void load(ThreadContext tc, String origFilename) {
20+
String filename;
21+
if( origFilename.indexOf("!") != -1 ) {
22+
filename = origFilename.substring(origFilename.lastIndexOf("!") + 1);
23+
}
24+
else {
25+
filename = origFilename;
26+
}
1827
// Don't load the same thing multiple times.
1928
if (tc.gc.loaded.contains(origFilename))
2029
return;
2130

2231
try {
2332
// Read in class data.
24-
String filename = origFilename;
2533
File file = new File(filename);
2634
if (!file.exists() && filename.equals("ModuleLoader.class")) {
2735
/* We special case the initial ModuleLoader loading. */
2836
String[] cps = System.getProperty("java.class.path").split("[:;]");
2937
for (int i = 0; i < cps.length; i++) {
38+
if(System.getenv("NQP_BUILD_DEBUG") != null)
39+
System.out.println("checking classpath: " + cps[i]);
3040
file = new File(cps[i] + "/" + filename);
3141
if (file.exists()) {
3242
filename = cps[i] + "/" + filename;
@@ -40,7 +50,36 @@ public void load(ThreadContext tc, String origFilename) {
4050
}
4151
}
4252

43-
Class<?> c = loadFile(filename, tc.gc.sharingHint);
53+
// TODO: untangle the logic somewhat...
54+
// "the filename wasn't changed" is a bad metric for "we didn't find the right file"...
55+
Class<?> c = null;
56+
if( filename.equals("ModuleLoader.class") ) {
57+
if(System.getenv("NQP_BUILD_DEBUG") != null)
58+
System.out.println("first branch");
59+
c = loadFile(LibraryLoader.class.getResource("/lib/ModuleLoader.jar"), tc.gc.sharingHint);
60+
}
61+
else if ( origFilename.indexOf("!") != -1 || origFilename.indexOf(":") != -1 ) {
62+
if(System.getenv("NQP_BUILD_DEBUG") != null)
63+
System.out.println("second branch with " + origFilename);
64+
c = loadFile(new URL(origFilename), tc.gc.sharingHint);
65+
}
66+
else if ( !(new File(filename)).exists() ) {
67+
if(System.getenv("NQP_BUILD_DEBUG") != null)
68+
System.out.println("third branch, with " + origFilename);
69+
URL res = LibraryLoader.class.getResource("/lib/" + filename);
70+
if( res != null ) {
71+
c = loadFile(res, tc.gc.sharingHint);
72+
}
73+
else {
74+
res = LibraryLoader.class.getResource("/lib/" + filename + ".jar");
75+
c = loadFile(res, tc.gc.sharingHint);
76+
}
77+
}
78+
else {
79+
if(System.getenv("NQP_BUILD_DEBUG") != null)
80+
System.out.println("fourth branch, with " + origFilename);
81+
c = loadFile(filename, tc.gc.sharingHint);
82+
}
4483

4584
// Load the class.
4685
CompilationUnit cu = (CompilationUnit)c.newInstance();
@@ -60,31 +99,65 @@ public void load(ThreadContext tc, String origFilename) {
6099
}
61100

62101
public static Class<?> loadFile(String cf, boolean shared) throws Exception {
102+
return loadFile(new URL("file:" + cf), shared);
103+
}
104+
105+
public static Class<?> loadFile(URL cf, boolean shared) throws Exception {
63106
if (shared) {
107+
if(System.getenv("NQP_BUILD_DEBUG") != null)
108+
System.out.println("cf is shared, " + cf);
64109
synchronized(sharedClassHash) {
65-
if (sharedClassHash.containsKey(cf))
66-
return sharedClassHash.get(cf);
110+
if (sharedClassHash.containsKey(cf.getPath()))
111+
return sharedClassHash.get(cf.getPath());
67112

68113
Class<?> n = loadFile(cf, false);
69-
sharedClassHash.put(cf, n);
114+
sharedClassHash.put(cf.getPath(), n);
70115
return n;
71116
}
72117
}
73118

74-
byte[] b = Files.readAllBytes( FileSystems.getDefault().getPath(cf) );
75-
long sig = b.length < 4 ? 0 :
76-
(b[3] & 0xFF) | ((b[2] & 0xFF) << 8) | ((b[1] & 0xFF) << 16) | ((b[0] & 0xFFL) << 24);
119+
byte[] bs = null;
120+
121+
if(System.getenv("NQP_BUILD_DEBUG") != null)
122+
System.out.println("cf is " + cf);
123+
if(cf.getProtocol().equals("jar")) {
124+
// XXX: this is a bit gnarly, currently.
125+
// basically, before we only ever loaded files from disk, but self-executable jars
126+
// have our libs as jar inside of a jar, and getResource gets us an URL
127+
// so instead of properly untangling this i'm taking a shortcut (for now)
128+
// and assume that URLs always point to jars, so we read the resource instead
129+
// of reading the file
130+
String res = cf.getPath();
131+
res = res.substring(res.lastIndexOf("!") + 1);
132+
InputStream is = LibraryLoader.class.getResourceAsStream(res);
133+
if(is == null) {
134+
throw new RuntimeException("Couldn't find resource " + res);
135+
}
136+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
137+
int b = is.read();
138+
while( b != -1 ) {
139+
baos.write(b);
140+
b = is.read();
141+
}
142+
bs = baos.toByteArray();
143+
}
144+
else {
145+
bs = Files.readAllBytes( FileSystems.getDefault().getPath(cf.getPath()) );
146+
}
147+
148+
long sig = bs.length < 4 ? 0 :
149+
(bs[3] & 0xFF) | ((bs[2] & 0xFF) << 8) | ((bs[1] & 0xFF) << 16) | ((bs[0] & 0xFFL) << 24);
77150

78151
if (sig == 0xCAFEBABEL) {
79152
// This is a class file
80153

81-
return loadNew(b, null);
154+
return loadNew(bs, null);
82155
} else if (sig == 0x504B0304) {
83156
// This is a (non-empty, non-self-extracting) zip file
84157
// These are quite constrained for now
85158

86159
JarEntry je;
87-
JarInputStream jis = new JarInputStream(new ByteArrayInputStream(b));
160+
JarInputStream jis = new JarInputStream(new ByteArrayInputStream(bs));
88161
byte[] kl = null;
89162
byte[] ser = null;
90163

@@ -106,14 +179,15 @@ public static Class<?> loadFile(String cf, boolean shared) throws Exception {
106179
}
107180

108181
public static Class<?> loadNew(byte[] bytes, byte[] serial) {
109-
return new IgnoreNameClassLoader(bytes, serial).loadClass();
182+
return new IgnoreNameClassLoader(bytes, serial, LibraryLoader.class.getClassLoader()).loadClass();
110183
}
111184

112185
private static class IgnoreNameClassLoader extends ClassLoader {
113186
private byte[] bytes;
114187
private byte[] serial;
115188

116-
public IgnoreNameClassLoader(byte[] bytes, byte[] serial) {
189+
public IgnoreNameClassLoader(byte[] bytes, byte[] serial, ClassLoader parent) {
190+
super(parent);
117191
this.bytes = bytes;
118192
this.serial = serial;
119193
}

src/vm/jvm/runtime/org/perl6/nqp/runtime/Ops.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import java.math.BigInteger;
1414
import java.math.RoundingMode;
1515
import java.net.InetAddress;
16+
import java.net.URL;
1617
import java.nio.ByteBuffer;
1718
import java.nio.charset.Charset;
1819
import java.nio.file.DirectoryStream;
@@ -6276,4 +6277,15 @@ public static String getuniname(long codePoint, ThreadContext tc) {
62766277
}
62776278
return name;
62786279
}
6280+
6281+
public static String getmoduleurl(String filename, ThreadContext tc) {
6282+
URL fileurl = Ops.class.getResource("/" + filename);
6283+
if( fileurl == null ) {
6284+
fileurl = Ops.class.getResource("/lib/" + filename);
6285+
}
6286+
if( fileurl == null ) {
6287+
fileurl = Ops.class.getResource("/lib/" + filename + ".jar");
6288+
}
6289+
return fileurl.toString();
6290+
}
62796291
}

src/vm/jvm/runtime/org/perl6/nqp/tools/EvalServer.java

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,20 +44,21 @@ public class EvalServer {
4444
private WritableByteChannel tokenCh;
4545
private Path tokenPath;
4646

47+
public String run(Class<?> cuType, String code) throws Exception {
48+
String[] argv = new String[2];
49+
argv[0] = "-e";
50+
argv[1] = code;
51+
return run(cuType, argv);
52+
}
53+
4754
public String run(String appPath, String code) throws Exception {
4855
String[] argv = new String[2];
4956
argv[0] = "-e";
5057
argv[1] = code;
5158
return run(appPath, argv);
5259
}
5360

54-
public String run(String appPath, String[] argv) throws Exception {
55-
try {
56-
cuType = LibraryLoader.loadFile( appPath, true );
57-
} catch (ThreadDeath td) {
58-
throw new RuntimeException("Couldn't loadFile. Your CLASSPATH might not be set up correctly.");
59-
}
60-
61+
public String run(Class<?> cuType, String[] argv) throws Exception {
6162
GlobalContext gc = new GlobalContext();
6263
gc.in = new ByteArrayInputStream(new byte[0]);
6364
ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -78,6 +79,16 @@ public String run(String appPath, String[] argv) throws Exception {
7879
return baos.toString("UTF-8");
7980
}
8081

82+
public String run(String appPath, String[] argv) throws Exception {
83+
try {
84+
cuType = LibraryLoader.loadFile( appPath, true );
85+
} catch (ThreadDeath td) {
86+
throw new RuntimeException("Couldn't loadFile. Your CLASSPATH might not be set up correctly.");
87+
}
88+
89+
return run(cuType, argv);
90+
}
91+
8192
public static void main(String[] args) throws Exception {
8293

8394
String executableName = System.getProperty("perl6.execname");

0 commit comments

Comments
 (0)