diff --git a/3rdparty/lz4/LICENSE.txt b/3rdparty/lz4/LICENSE.txt new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/3rdparty/lz4/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/3rdparty/lz4/lz4-java-1.8.0.jar b/3rdparty/lz4/lz4-java-1.8.0.jar new file mode 100644 index 0000000000..89c644b8e2 Binary files /dev/null and b/3rdparty/lz4/lz4-java-1.8.0.jar differ diff --git a/src/vm/jvm/runtime/org/raku/nqp/jast2bc/JASTCompiler.java b/src/vm/jvm/runtime/org/raku/nqp/jast2bc/JASTCompiler.java index 8f6bdadeb6..7103815608 100644 --- a/src/vm/jvm/runtime/org/raku/nqp/jast2bc/JASTCompiler.java +++ b/src/vm/jvm/runtime/org/raku/nqp/jast2bc/JASTCompiler.java @@ -1,5 +1,6 @@ package org.raku.nqp.jast2bc; +import java.io.File; import java.io.FileOutputStream; import java.lang.invoke.CallSite; @@ -13,6 +14,9 @@ import java.util.jar.JarOutputStream; import java.util.jar.Manifest; +import java.util.zip.CRC32; +import java.util.zip.ZipEntry; + import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Handle; @@ -26,6 +30,9 @@ import org.raku.nqp.sixmodel.SixModelObject; import org.raku.nqp.runtime.Ops; +import net.jpountz.lz4.LZ4Factory; +import net.jpountz.lz4.LZ4CompressorWithLength; + public class JASTCompiler { public static JavaClass buildClass(SixModelObject jast, SixModelObject jastNodes, boolean split, ThreadContext tc) { try { @@ -40,6 +47,13 @@ public static JavaClass buildClass(SixModelObject jast, SixModelObject jastNodes } } + private static final LZ4CompressorWithLength lz4 = + new LZ4CompressorWithLength(LZ4Factory.fastestInstance().highCompressor(8)); + // The lower the compression level, the faster the serialization, at the + // expense of deserialization and disk space; the higher the compression + // level, the lower the disk space, at the expense of both serialization + // and deserialization. 8 is a sweet spot of sorts. + public static void writeClass(SixModelObject jast, SixModelObject jastNodes, String filename, ThreadContext tc) { JavaClass c = buildClass(jast, jastNodes, false, tc); try { @@ -51,17 +65,29 @@ public static void writeClass(SixModelObject jast, SixModelObject jastNodes, Str } else { // writing a jar Manifest mf = new Manifest(); - - mf.getMainAttributes().put( Attributes.Name.MANIFEST_VERSION, "1.0" ); + mf.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); if (c.hasMain) - mf.getMainAttributes().put( Attributes.Name.MAIN_CLASS, c.name ); - + mf.getMainAttributes().put(Attributes.Name.MAIN_CLASS, c.name); JarOutputStream jos = new JarOutputStream(fos, mf); - jos.putNextEntry(new JarEntry(c.name.replace('.','/') + ".class")); + JarEntry jec = new JarEntry(c.name + ".class"); + jec.setComment(c.name.replace(File.pathSeparatorChar, '.')); + jos.putNextEntry(jec); jos.write(c.bytes); - jos.putNextEntry(new JarEntry(c.name.replace('.','/') + ".serialized")); - jos.write(c.serialized); + jos.closeEntry(); + + byte[] digest = lz4.compress(c.serialized); + CRC32 cipher = new CRC32(); + cipher.update(digest, 0, digest.length); + + JarEntry jes = new JarEntry(c.name + ".serialized.lz4"); + jes.setMethod(ZipEntry.STORED); + jes.setSize(digest.length); + jes.setCompressedSize(digest.length); + jes.setCrc(cipher.getValue()); + jos.putNextEntry(jes); + jos.write(digest); + jos.closeEntry(); jos.close(); } diff --git a/src/vm/jvm/runtime/org/raku/nqp/runtime/ByteClassLoader.java b/src/vm/jvm/runtime/org/raku/nqp/runtime/ByteClassLoader.java index 2fd9971696..dc3a7e03b5 100644 --- a/src/vm/jvm/runtime/org/raku/nqp/runtime/ByteClassLoader.java +++ b/src/vm/jvm/runtime/org/raku/nqp/runtime/ByteClassLoader.java @@ -1,6 +1,19 @@ package org.raku.nqp.runtime; +import java.lang.ref.SoftReference; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.Map; +import java.util.Hashtable; +import java.util.Set; +import java.util.WeakHashMap; + public class ByteClassLoader extends ClassLoader { + private final Set refs = new CopyOnWriteArraySet< >(); + + private final Map read = new WeakHashMap< >(); + + private final Map>> made = new Hashtable< >(); + public ByteClassLoader() { super(); } @@ -9,7 +22,43 @@ public ByteClassLoader(ClassLoader parent) { super(parent); } - public Class defineClass(String name, byte[] bytes) { - return defineClass(name, bytes, 0, bytes.length); + public boolean addRef(String name) { + return refs.add(name); + } + + public Class getMade(String name) { + if (name != null && made.containsKey(name)) + return made.get(name).get(); + return null; + } + + public Class setMade(String name, Class klass) { + if (name == null) + name = klass.getName(); + made.put(name, new SoftReference(klass)); + return klass; + } + + public Class getRead(ClassLoader child, String name) { + if (name != null && made.containsKey(name)) + return made.get(name).get(); + if (child != null && read.containsKey(child)) + if (made.containsKey(name = read.get(child))) + return made.get(name).get(); + return null; + } + + public Class setRead(ClassLoader child, String name, Class klass) { + if (name == null) + name = klass.getName(); + if (child != null) + read.put(child, name); + made.put(name, new SoftReference(klass)); + return klass; + } + + public Class defineClass(String name, byte[] bytes) throws ClassFormatError { + Class made = getMade(name); + return made == null ? setMade(name, defineClass(name, bytes, 0, bytes.length)) : made; } } diff --git a/src/vm/jvm/runtime/org/raku/nqp/runtime/GlobalContext.java b/src/vm/jvm/runtime/org/raku/nqp/runtime/GlobalContext.java index 276361d46a..6e3323217a 100644 --- a/src/vm/jvm/runtime/org/raku/nqp/runtime/GlobalContext.java +++ b/src/vm/jvm/runtime/org/raku/nqp/runtime/GlobalContext.java @@ -5,7 +5,6 @@ import java.io.UnsupportedEncodingException; import java.lang.ref.WeakReference; import java.util.HashMap; -import java.util.HashSet; import java.util.Timer; import java.util.WeakHashMap; @@ -171,11 +170,6 @@ public class GlobalContext { */ public HashMap scRefs; - /** - * Set of library filenames which have been loaded so far. - */ - public HashSet loaded; - /** * Whether to dump VM-level stack traces for all exceptions. */ @@ -241,7 +235,6 @@ public GlobalContext() scRefs = new HashMap(); compilerRegistry = new HashMap(); hllSyms = new HashMap>(); - loaded = new HashSet(); contConfigs = new HashMap(); contConfigs.put("code_pair", new CodePairContainerConfigurer()); diff --git a/src/vm/jvm/runtime/org/raku/nqp/runtime/LibraryLoader.java b/src/vm/jvm/runtime/org/raku/nqp/runtime/LibraryLoader.java index 8308d79ac9..53306012de 100644 --- a/src/vm/jvm/runtime/org/raku/nqp/runtime/LibraryLoader.java +++ b/src/vm/jvm/runtime/org/raku/nqp/runtime/LibraryLoader.java @@ -1,27 +1,39 @@ package org.raku.nqp.runtime; -import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; +import java.io.EOFException; import java.io.InputStream; -import java.nio.file.FileSystems; +import java.io.RandomAccessFile; +import java.lang.ref.WeakReference; +import java.nio.channels.FileChannel; import java.nio.file.Files; +import java.nio.file.InvalidPathException; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.nio.BufferUnderflowException; +import java.nio.BufferOverflowException; +import java.nio.ByteBuffer; +import java.util.concurrent.ConcurrentHashMap; import java.util.ArrayList; -import java.util.HashMap; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; import java.util.jar.JarEntry; +import java.util.jar.JarFile; import java.util.jar.JarInputStream; +import net.jpountz.lz4.LZ4Factory; +import net.jpountz.lz4.LZ4DecompressorWithLength; public class LibraryLoader { - static HashMap> sharedClassHash = new HashMap>(); + private static Map> sharedClasses = new ConcurrentHashMap< >(); - public void load(ThreadContext tc, String origFilename) { + public static void load(ThreadContext tc, String filename) { // Don't load the same thing multiple times. - if (tc.gc.loaded.contains(origFilename)) + if (!tc.gc.byteClassLoader.addRef(filename)) return; - - try { + else try { // Read in class data. - String filename = origFilename; File file = new File(filename); if (!file.exists() && filename.equals("ModuleLoader.class")) { /* We special case the initial ModuleLoader loading. */ @@ -40,138 +52,423 @@ public void load(ThreadContext tc, String origFilename) { } } - Class c = loadFile(filename, tc.gc.sharingHint); - loadClass(tc, c); - - // Note that we already loaded it. - tc.gc.loaded.add(origFilename); + resolveClass(tc, loadFile(filename, tc.gc.byteClassLoader, tc.gc.sharingHint)); + } + catch (IOException | IllegalArgumentException | ClassNotFoundException e) { + throw ExceptionHandling.dieInternal(tc, e); } - catch (ControlException e) { - throw e; + } + + public static void load(ThreadContext tc, byte[] buffer) { + ByteBuffer bb; + try { + bb = ByteBuffer.allocate(buffer.length); + bb.put(buffer); + bb.rewind(); } - catch (Throwable e) { - throw ExceptionHandling.dieInternal(tc, e.toString()); + catch (BufferOverflowException | IllegalArgumentException e) { + throw ExceptionHandling.dieInternal(tc, e); } + load(tc, bb); } - public void load(ThreadContext tc, byte[] buffer) { + public static void load(ThreadContext tc, ByteBuffer buffer) { try { - Class c = loadJar(buffer); - loadClass(tc, c); + resolveClass(tc, loadJar(buffer, tc.gc.byteClassLoader)); } - catch (ControlException e) { - throw e; + catch (IOException | IllegalArgumentException | ClassNotFoundException e) { + throw ExceptionHandling.dieInternal(tc, e); } - catch (Throwable e) { - throw ExceptionHandling.dieInternal(tc, e.toString()); + } + + public static Class loadFile( + String fn, + ByteClassLoader parent, + boolean shared + ) throws IOException, IllegalArgumentException, ClassNotFoundException { + if (shared) + return sharedClasses.computeIfAbsent(fn, (k) -> { + try { + return loadFile(k, parent, false); + } + catch (IOException | IllegalArgumentException | ClassNotFoundException e) { + return null; + } + }); + else try (RandomAccessFile fh = new RandomAccessFile(fn, "r")) { + switch (fh.readInt()) { + case 0xCAFEBABE: // classfile + return loadClass(fn, parent); + default: // JAR + // The manifest alone gives us at least an int's width. Let + // the JarInputStream decide if this is a JAR or not. + return loadJar(fn, parent); + } } + catch (EOFException e) { + throw new IllegalArgumentException("Unrecognized bytecode format in " + fn); + } + } - private static void loadClass(ThreadContext tc, Class c) throws Throwable { - CompilationUnit cu = (CompilationUnit)c.newInstance(); - cu.shared = tc.gc.sharingHint; - cu.initializeCompilationUnit(tc); - cu.runLoadIfAvailable(tc); + public static Class loadClass(String fn, ByteClassLoader parent) throws IOException, ClassNotFoundException { + return new FileClassLoader(fn, parent).loadSerialClass(null); } - private static Class loadJar(byte[] buffer) throws Exception { - // This is a (non-empty, non-self-extracting) zip file - // These are quite constrained for now + public static Class loadJar(String fn, ByteClassLoader parent) throws IOException, ClassNotFoundException { + return new JarFileClassLoader(fn, parent).loadSerialClass(null); + } + + public static Class loadJar( + ByteBuffer buffer, + ByteClassLoader parent + ) throws IOException, IllegalArgumentException, ClassNotFoundException { + String name = null; + ByteBuffer classfile = null; + ByteBuffer serial = null; + try (JarInputStream jis = new JarInputStream(new ByteBufferedInputStream(buffer))) { + JarEntry je; + while ((je = jis.getNextJarEntry()) != null) { + String jf = je.getName(); + if (jf.endsWith(".class") && classfile == null) { + name = je.getComment(); + classfile = readToHeapBuffer(jis); + } + else if (jf.endsWith(".serialized.lz4") && serial == null) + serial = readToHeapBuffer(jis); + else if (jf.endsWith(".serialized") && serial == null) + serial = readToHeapBuffer(jis); + else + throw new IllegalArgumentException("Bytecode jar contains unexpected file " + jf); + } + } + if (classfile == null) + throw new IllegalArgumentException("Bytecode jar lacks class file"); + if (serial == null) + throw new IllegalArgumentException("Bytecode jar lacks serialization file"); + return new MemoryClassLoader(classfile, serial, parent).loadSerialClass(name); + } + + public static void resolveClass(ThreadContext tc, Class c) { + try { + CompilationUnit cu = (CompilationUnit)c.getDeclaredConstructor().newInstance(); + cu.shared = tc.gc.sharingHint; + cu.initializeCompilationUnit(tc); + cu.runLoadIfAvailable(tc); + } + catch (ReflectiveOperationException e) { + throw ExceptionHandling.dieInternal(tc, e); + } + } + + public static ByteBuffer readToHeapBuffer(InputStream is) throws IOException { + return ByteBuffer.wrap(is.readAllBytes()); + } + + private static final LZ4DecompressorWithLength lz4 = + new LZ4DecompressorWithLength(LZ4Factory.fastestInstance().fastDecompressor()); + + public static ByteBuffer readToHeapBufferLz4(InputStream is) throws IOException { + return ByteBuffer.wrap(lz4.decompress(is.readAllBytes())); + } - JarEntry je; - JarInputStream jis = new JarInputStream(new ByteArrayInputStream(buffer)); - byte[] kl = null; - byte[] ser = null; + private static abstract class SerialClassLoader extends ClassLoader { + protected SerialClassLoader(ByteClassLoader parent) { + super(parent); + } - while ((je = jis.getNextJarEntry()) != null) { - byte[] data = readEverything(jis); + protected abstract Class findSerialClass(String name) throws ClassNotFoundException; - if (je.getName().endsWith(".class") && kl == null) kl = data; - else if (je.getName().endsWith(".serialized") && ser == null) ser = data; - else throw new RuntimeException("Bytecode jar contains unexpected file "+je.getName()); + protected synchronized Class loadSerialClass(String name) throws ClassNotFoundException { + Class klass = name == null ? null : findLoadedClass(name); + if (klass == null) { + klass = getRead(name); + if (klass == null) { + setRead(name, klass = findSerialClass(name)); + if (klass == null) + throw new ClassNotFoundException(name); + } + } + resolveClass(klass); + return klass; } - if (kl == null) throw new RuntimeException("Bytecode jar lacks class file"); - if (ser == null) throw new RuntimeException("Bytecode jar lacks serialization file"); + private Class getRead(String name) { + ByteClassLoader parent = (ByteClassLoader)getParent(); + return parent == null ? null : parent.getRead(this, name); + } - return loadNew(kl, ser); + private Class setRead(String name, Class klass) { + ByteClassLoader parent = (ByteClassLoader)getParent(); + return parent == null ? null : parent.setRead(this, name, klass); + } } - public static Class loadFile(String cf, boolean shared) throws Exception { - if (shared) { - synchronized(sharedClassHash) { - if (sharedClassHash.containsKey(cf)) - return sharedClassHash.get(cf); + private static abstract class StreamClassLoader extends SerialClassLoader { + protected final String filename; + protected InputStream classfile; + + protected StreamClassLoader(String filename, InputStream classfile, ByteClassLoader parent) { + super(parent); + this.filename = filename; + this.classfile = classfile; + } - Class n = loadFile(cf, false); - sharedClassHash.put(cf, n); - return n; + public String getFileName() { + return filename; + } + + protected Class findSerialClass(String name) throws ClassNotFoundException { + try { + byte[] buffer = classfile.readAllBytes(); + return defineClass(name, buffer, 0, buffer.length); + } + catch (IOException | IndexOutOfBoundsException e) { + throw new ClassNotFoundException("could not read serial class" + name, e); + } + catch (NoClassDefFoundError e) { + throw new ClassNotFoundException("serial class not named " + name, e); + } + catch (SecurityException e) { + throw new ClassNotFoundException("serial class is insecurely named " + name, e); } } + } - byte[] b = Files.readAllBytes( FileSystems.getDefault().getPath(cf) ); - long sig = b.length < 4 ? 0 : - (b[3] & 0xFF) | ((b[2] & 0xFF) << 8) | ((b[1] & 0xFF) << 16) | ((b[0] & 0xFFL) << 24); + private static class FileClassLoader extends StreamClassLoader { + static { ClassLoader.registerAsParallelCapable(); } - if (sig == 0xCAFEBABEL) { - // This is a class file + protected FileClassLoader(String filename, ByteClassLoader parent) { + super(filename, null, parent); + } - return loadNew(b, null); - } else if (sig == 0x504B0304) { - return loadJar(b); - } else { - throw new RuntimeException("Unrecognized bytecode format in "+cf); + @Override + protected Class findSerialClass(String name) throws ClassNotFoundException { + try { + classfile = Files.newInputStream(Paths.get(filename), StandardOpenOption.READ); + Class klass = super.findSerialClass( + name == null ? filename.replace(File.pathSeparatorChar, '.') : name); + classfile.close(); + classfile = null; + return klass; + } + catch (InvalidPathException e) { + throw new ClassNotFoundException("no such classfile " + filename, e); + } + catch (IllegalArgumentException | UnsupportedOperationException | IOException e) { + throw new ClassNotFoundException("cannot read " + filename, e); + } + } + + @Override + public InputStream getResourceAsStream(String name) { + return null; } } - public static Class loadNew(byte[] bytes, byte[] serial) { - IgnoreNameClassLoader incl = new IgnoreNameClassLoader(bytes, serial); - return incl.loadClass(); + private static class JarFileClassLoader extends StreamClassLoader { + static { ClassLoader.registerAsParallelCapable(); } + + protected JarFileClassLoader(String filename, ByteClassLoader parent) { + super(filename, null, parent); + } + + @Override + protected Class findSerialClass(String name) throws ClassNotFoundException { + try (JarFile jar = new JarFile(filename)) { + JarEntry entry = null; + for (Enumeration entries = jar.entries(); entries.hasMoreElements(); ) + if ((entry = entries.nextElement()).getName().endsWith(".class")) + break; + if (entry == null) + throw new ClassNotFoundException(name + " in " + filename); + classfile = jar.getInputStream(entry); + return super.findSerialClass( + name == null ? entry.getComment() : name); + } + catch (IOException | ClassNotFoundException e) { + throw new ClassNotFoundException(name + " in " + filename, e); + } + } + + @Override + public InputStream getResourceAsStream(String name) { + try { + JarFile jar = new JarFile(filename); + JarEntry entry = jar.getJarEntry(name); + return entry == null ? null : jar.getInputStream(entry); + } + catch (IOException e) { + return null; + } + } } - private static class IgnoreNameClassLoader extends ClassLoader { - private byte[] bytes; - private byte[] serial; + private static class MemoryClassLoader extends SerialClassLoader { + static { ClassLoader.registerAsParallelCapable(); } - public IgnoreNameClassLoader(byte[] bytes, byte[] serial) { - this.bytes = bytes; + private final WeakReference classfile; + private final ByteBuffer serial; + + protected MemoryClassLoader(ByteBuffer classfile, ByteBuffer serial, ByteClassLoader parent) { + super(parent); + this.classfile = new WeakReference(classfile); this.serial = serial; } - public Class loadClass() { - return defineClass(null, this.bytes, 0, this.bytes.length); + protected Class findSerialClass(String name) throws ClassNotFoundException { + ByteBuffer classfile = this.classfile.get(); + if (classfile == null) { + throw new ClassNotFoundException("in-memory classfile missing; probably already loaded " + name); + } + else try { + return defineClass(name, classfile, null); + } + catch (NoClassDefFoundError e) { + throw new ClassNotFoundException("classfile not named " + name, e); + } + catch (IndexOutOfBoundsException e) { + throw new ClassNotFoundException("could not read classfile " + name, e); + } + catch (SecurityException e) { + throw new ClassNotFoundException("classfile is insecurely named " + name, e); + } } @Override public InputStream getResourceAsStream(String name) { - return new ByteArrayInputStream(serial); + if (serial == null) + return null; + else try { + return ByteBufferedInputStream.copy(serial); + } + catch (IllegalArgumentException e) { + return null; + } } } - // this is dumb - public static byte[] readEverything(InputStream from) throws IOException { - final int bufSize = 65536; - ArrayList chunks = new ArrayList(); - byte[] currentChunk = new byte[bufSize]; - int currentFill = 0; + private static class ByteBufferedInputStream extends InputStream { + private ByteBuffer bb; + + public ByteBufferedInputStream(ByteBuffer bb) { + this.bb = bb; + } + + public static ByteBufferedInputStream copy(ByteBuffer src) throws IllegalArgumentException { + int offset = src.position(); + ByteBuffer bb = ByteBuffer.allocate(src.capacity() - offset); + bb.put(src); + bb.rewind(); + src.position(offset); + return new ByteBufferedInputStream(bb); + } + + public static InputStream nullInputStream() { + return new ByteBufferedInputStream(null); + } + + private int get() throws IOException { + try { + return bb.get(); + } + catch (BufferUnderflowException e) { + throw new IOException(e); + } + } - while (true) { - if (currentFill == bufSize) { - chunks.add(currentChunk); - currentChunk = new byte[bufSize]; - currentFill = 0; + private void get(byte[] dst) throws IOException { + try { + bb.get(dst); } + catch (BufferUnderflowException e) { + throw new IOException(e); + } + } + + @Override + public int read() throws IOException { + return bb != null && bb.hasRemaining() ? get() : -1; + } + + @Override + public int read(byte[] dst) throws IOException { + if (bb == null) + return -1; - int addl = from.read(currentChunk, currentFill, bufSize - currentFill); - if (addl < 0) break; - currentFill += addl; + int length = Math.min(dst.length, available()); + if (length <= 0) + return 0; + + byte[] src = new byte[length]; + get(src); + System.arraycopy(src, 0, dst, 0, length); + return length; } - byte[] finished = new byte[chunks.size() * bufSize + currentFill]; - for (int i = 0; i < chunks.size(); i++) - System.arraycopy(chunks.get(i), 0, finished, i*bufSize, bufSize); - System.arraycopy(currentChunk, 0, finished, chunks.size()*bufSize, currentFill); + @Override + public int read(byte[] dst, int offset, int length) throws IOException { + if (bb == null) + return -1; + + length = Math.min(length, available()); + if (length <= 0) + return 0; - return finished; + byte[] src = new byte[length]; + get(src); + System.arraycopy(src, 0, dst, offset, length); + return length; + } + + @Override + public int readNBytes(byte[] dst, int offset, int length) throws IOException { + if (bb == null) + return -1; + + length = Math.min(length, available()); + if (length <= 0) + return 0; + + byte[] src = new byte[length]; + get(src); + System.arraycopy(src, 0, dst, offset, length); + return length; + } + + @Override + public byte[] readAllBytes() throws IOException { + byte[] dst = new byte[available()]; + if (dst.length > 0) + get(dst); + return dst; + } + + @Override + public long skip(long length) { + if (bb == null) + return 0; + + int offset = bb.position(); + length = Long.min(length, bb.capacity() - offset); + bb.position(offset + (int)length); + return length; + } + + @Override + public int available() { + return bb == null ? 0 : (bb.capacity() - bb.position()); + } + + @Override + public void reset() { + if (bb != null) + bb.rewind(); + } + + @Override + public void close() { + this.bb = null; + } } } diff --git a/src/vm/jvm/runtime/org/raku/nqp/runtime/Ops.java b/src/vm/jvm/runtime/org/raku/nqp/runtime/Ops.java index 8a2b6d168c..49dd9571bc 100644 --- a/src/vm/jvm/runtime/org/raku/nqp/runtime/Ops.java +++ b/src/vm/jvm/runtime/org/raku/nqp/runtime/Ops.java @@ -28,6 +28,8 @@ import java.math.BigInteger; import java.math.RoundingMode; import java.net.InetAddress; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; import java.nio.ByteBuffer; import java.nio.BufferUnderflowException; import java.nio.CharBuffer; @@ -5341,46 +5343,69 @@ public static SixModelObject serializetobuf(SixModelObject scRef, SixModelObject throw ExceptionHandling.dieInternal(tc, "serialize was not passed a valid SCRef"); } } - public static String deserialize(String blob, SixModelObject scRef, SixModelObject sh, SixModelObject cr, SixModelObject conflict, ThreadContext tc) throws IOException { - if (scRef instanceof SCRefInstance) { - SerializationContext sc = ((SCRefInstance)scRef).referencedSC; + public static String deserialize( + String blob, + SixModelObject scRef, + SixModelObject sh, + SixModelObject cr, + SixModelObject conflict, + ThreadContext tc + ) { + if (!(scRef instanceof SCRefInstance)) + throw ExceptionHandling.dieInternal(tc, "deserialize was not passed a valid SCRef"); + SerializationContext sc = ((SCRefInstance)scRef).referencedSC; - String[] shArray = new String[(int)sh.elems(tc)]; - for (int i = 0; i < shArray.length; i++) { - sh.at_pos_native(tc, i); - shArray[i] = tc.native_s; - } + String[] shArray = new String[(int)sh.elems(tc)]; + for (int i = 0; i < shArray.length; i++) { + sh.at_pos_native(tc, i); + shArray[i] = tc.native_s; + } - CodeRef[] crArray; - int crCount; + CompilationUnit cu = tc.curFrame.codeRef.staticInfo.compUnit; + CodeRef[] crArray; + int crCount; + if (isnull(cr) == 1) { + crArray = cu.qbidToCodeRef; + crCount = cu.serializedCodeRefCount(); + } else { + crArray = new CodeRef[(int)cr.elems(tc)]; + crCount = crArray.length; + for (int i = 0; i < crArray.length; i++) + crArray[i] = (CodeRef)cr.at_pos_boxed(tc, i); + } - CompilationUnit cu = tc.curFrame.codeRef.staticInfo.compUnit; - if (isnull(cr) == 1) { - crArray = cu.qbidToCodeRef; - crCount = cu.serializedCodeRefCount(); - } else { - crArray = new CodeRef[(int)cr.elems(tc)]; - crCount = crArray.length; - for (int i = 0; i < crArray.length; i++) - crArray[i] = (CodeRef)cr.at_pos_boxed(tc, i); + ByteBuffer binaryBlob; + if (blob == null) + try { + Class cuKlass = cu.getClass(); + String cuName = cuKlass.getSimpleName(); + InputStream cuStream = cuKlass.getResourceAsStream(cuName + ".serialized.lz4"); + try { + if (cuStream != null) + binaryBlob = LibraryLoader.readToHeapBufferLz4(cuStream); + else { + cuStream = cuKlass.getResourceAsStream(cuName + ".serialized"); + binaryBlob = LibraryLoader.readToHeapBuffer(cuStream); + } + } + finally { + cuStream.close(); + } } - - ByteBuffer binaryBlob; - if (blob == null) { - binaryBlob = ByteBuffer.wrap( LibraryLoader.readEverything( cu.getClass().getResourceAsStream( cu.getClass().getSimpleName() + ".serialized" ) ) ); - } else { + catch (IOException e) { + throw ExceptionHandling.dieInternal(tc, e); + } + else + try { binaryBlob = Base64.decode(blob); } + catch (IllegalArgumentException e) { + throw ExceptionHandling.dieInternal(tc, e); + } - SerializationReader sr = new SerializationReader( - tc, sc, shArray, crArray, crCount, binaryBlob); - sr.deserialize(); - - return blob; - } - else { - throw ExceptionHandling.dieInternal(tc, "deserialize was not passed a valid SCRef"); - } + SerializationReader sr = new SerializationReader(tc, sc, shArray, crArray, crCount, binaryBlob); + sr.deserialize(); + return blob; } public static SixModelObject wval(String sc, long idx, ThreadContext tc) { return tc.gc.scs.get(sc).getObject((int)idx); @@ -6506,19 +6531,16 @@ public static SixModelObject bindhllsym(String hllName, String name, SixModelObj return value; } public static String loadbytecode(String filename, ThreadContext tc) { - new LibraryLoader().load(tc, filename); + LibraryLoader.load(tc, filename); return filename; } - public static SixModelObject loadbytecodebuffer(SixModelObject buffer, ThreadContext tc) throws Exception { - if (buffer instanceof VMArrayInstance_i8) { - new LibraryLoader().load(tc, ((VMArrayInstance_i8)buffer).slots); - } - else if (buffer instanceof VMArrayInstance_u8) { - new LibraryLoader().load(tc, ((VMArrayInstance_u8)buffer).slots); - } - else { - throw new RuntimeException("Must pass a uint8 or int8 buffer to loadbytecodebuffer"); - } + public static SixModelObject loadbytecodebuffer(SixModelObject buffer, ThreadContext tc) { + if (buffer instanceof VMArrayInstance_i8) + LibraryLoader.load(tc, ((VMArrayInstance_i8)buffer).slots); + else if (buffer instanceof VMArrayInstance_u8) + LibraryLoader.load(tc, ((VMArrayInstance_u8)buffer).slots); + else + throw ExceptionHandling.dieInternal(tc, "loadbytecodebuffer expects a uint8 or int8 VMArray"); return buffer; } public static SixModelObject settypehll(SixModelObject type, String language, ThreadContext tc) { diff --git a/src/vm/jvm/runtime/org/raku/nqp/tools/EvalServer.java b/src/vm/jvm/runtime/org/raku/nqp/tools/EvalServer.java index 87cb8304c7..fbc825b21e 100644 --- a/src/vm/jvm/runtime/org/raku/nqp/tools/EvalServer.java +++ b/src/vm/jvm/runtime/org/raku/nqp/tools/EvalServer.java @@ -38,6 +38,7 @@ public class EvalServer { private String cookiePath; private String mainPath; + private GlobalContext gc; private Class cuType; private String cookie; private ServerSocketChannel serv; @@ -53,12 +54,12 @@ public String run(String appPath, String code) throws Exception { public String run(String appPath, String[] argv) throws Exception { try { - cuType = LibraryLoader.loadFile( appPath, true ); + cuType = LibraryLoader.loadFile(appPath, gc.byteClassLoader, true); } catch (ThreadDeath td) { throw new RuntimeException("Couldn't loadFile. Your CLASSPATH might not be set up correctly."); } - GlobalContext gc = new GlobalContext(); + gc = new GlobalContext(); gc.in = new ByteArrayInputStream(new byte[0]); ByteArrayOutputStream baos = new ByteArrayOutputStream(); gc.out = gc.err = new PrintStream( baos, true, "UTF-8" ); @@ -90,7 +91,7 @@ public static void main(String[] args) throws Exception { } private void run() throws Exception { - cuType = LibraryLoader.loadFile( mainPath, true ); + cuType = LibraryLoader.loadFile(mainPath, gc.byteClassLoader, true); SecureRandom rng = new SecureRandom(); byte[] raw = new byte[16]; diff --git a/tools/build/install-jvm-runner.pl.in b/tools/build/install-jvm-runner.pl.in index 1b29a5521c..f50d53b897 100644 --- a/tools/build/install-jvm-runner.pl.in +++ b/tools/build/install-jvm-runner.pl.in @@ -21,7 +21,7 @@ if ($^O eq 'MSWin32') { open my $fh, ">", $install_to or die "Could not open $install_to: $!"; print $fh '@java -Xss1m -Xmx1324m -Xbootclasspath/a:' . $jar_dir . '\\nqp-runtime.jar;' . - "$jar_dir\\@asmfile@;$jar_dir\\@jlinefile@;$jar_dir\\@jnafile@;$jar_dir\\@jnaplatformfile@;$lib_dir\\nqp.jar -cp $lib_dir nqp %*\n"; + "$jar_dir\\@asmfile@;$jar_dir\\@jlinefile@;$jar_dir\\@jnafile@;$jar_dir\\@jnaplatformfile@;$jar_dir\\@lz4file@;$lib_dir\\nqp.jar -cp $lib_dir nqp %*\n"; close $fh or die "Could not close $install_to: $!"; } @@ -29,7 +29,7 @@ else { my $nqp_dir = File::Spec->catfile($prefix, qw/share nqp/); my $jar_dir = File::Spec->catfile('${NQP_DIR}', 'runtime'); my $lib_dir = File::Spec->catfile('${NQP_DIR}', 'lib'); - my $jars = "$jar_dir/nqp-runtime.jar:$jar_dir/@asmfile@:$jar_dir/@jlinefile@:$jar_dir/@jnafile@:$jar_dir/@jnaplatformfile@:$lib_dir/nqp.jar"; + my $jars = "$jar_dir/nqp-runtime.jar:$jar_dir/@asmfile@:$jar_dir/@jlinefile@:$jar_dir/@jnafile@:$jar_dir/@jnaplatformfile@:$jar_dir/@lz4file@:$lib_dir/nqp.jar"; my $install_to = File::Spec->catfile($realpath, 'bin', 'nqp-j'); open my $fh, ">", $install_to diff --git a/tools/lib/NQP/Config/NQP.pm b/tools/lib/NQP/Config/NQP.pm index e13fdf3603..49ec726209 100644 --- a/tools/lib/NQP/Config/NQP.pm +++ b/tools/lib/NQP/Config/NQP.pm @@ -249,6 +249,7 @@ sub configure_jars { jline => [qw<3rdparty jline jline-1.0.jar>], jna => [qw<3rdparty jna jna-4.5.0.jar>], 'jna-platform' => [qw<3rdparty jna jna-platform-4.5.0.jar>], + lz4 => [qw<3rdparty lz4 lz4-java-1.8.0.jar>], } ); } diff --git a/tools/templates/jvm/Makefile.in b/tools/templates/jvm/Makefile.in index ade161148a..7a0ad3f467 100644 --- a/tools/templates/jvm/Makefile.in +++ b/tools/templates/jvm/Makefile.in @@ -15,6 +15,7 @@ ASMTREE = @asmtree@ JLINE = @jline@ JNA = @jna@ JNAPLATFORM = @jnaplatform@ +LZ4 = @lz4@ RUNTIME_JAVAS = \ @nfp(src/vm/jvm/runtime/org/raku/nqp/io/*.java)@ \ @@ -25,13 +26,13 @@ RUNTIME_JAVAS = \ @nfp(src/vm/jvm/runtime/org/raku/nqp/tools/*.java)@ \ @bsv(RUNTIME)@ = @nfp(@bpm(RUNNER_JAR_DIR)@/nqp-runtime.@bext@)@ -THIRDPARTY_JARS = $(ASM)@cpsep@$(ASMTREE)@cpsep@$(JLINE)@cpsep@$(JNA)@cpsep@$(JNAPLATFORM) -@bpv(RUNNER_JARS)@ = @nfplq($(ASM) $(ASMTREE) $(JLINE) $(JNA) $(JNAPLATFORM))@ +THIRDPARTY_JARS = $(ASM)@cpsep@$(ASMTREE)@cpsep@$(JLINE)@cpsep@$(JNA)@cpsep@$(JNAPLATFORM)@cpsep@$(LZ4) +@bpv(RUNNER_JARS)@ = @nfplq($(ASM) $(ASMTREE) $(JLINE) $(JNA) $(JNAPLATFORM) $(LZ4))@ @bpv(RUNNER_LIBS)@ = @nfplq(nqp.@bext@)@ @bpv(EVAL_CLIENT)@ = @nfp(tools/jvm/eval-client.pl)@ -@bpv(STAGE0_NQP)@ = $(JAVA) -cp @bpm(STAGE0_DIR)@ -Xbootclasspath/a:@bpm(STAGE0_DIR)@@cpsep@@bsm(RUNTIME)@@cpsep@@q($(THIRDPARTY_JARS))@@cpsep@@nfp(@bpm(STAGE0_DIR)@/nqp.jar)@ nqp --bootstrap -@bpv(STAGE1_NQP)@ = $(JAVA) -cp @bpm(STAGE1_DIR)@ -Xbootclasspath/a:@bpm(STAGE1_DIR)@@cpsep@@bsm(RUNTIME)@@cpsep@@q($(THIRDPARTY_JARS))@@cpsep@@nfp(@bpm(STAGE1_DIR)@/nqp.jar)@ nqp --bootstrap +@bpv(STAGE0_NQP)@ = $(JAVA) -XX:+AggressiveHeap -XX:+AllowParallelDefineClass -cp @bpm(STAGE0_DIR)@ -Xbootclasspath/a:@bpm(STAGE0_DIR)@@cpsep@@bsm(RUNTIME)@@cpsep@@q($(THIRDPARTY_JARS))@@cpsep@@nfp(@bpm(STAGE0_DIR)@/nqp.jar)@ nqp --bootstrap +@bpv(STAGE1_NQP)@ = $(JAVA) -XX:+AggressiveHeap -XX:+AllowParallelDefineClass -cp @bpm(STAGE1_DIR)@ -Xbootclasspath/a:@bpm(STAGE1_DIR)@@cpsep@@bsm(RUNTIME)@@cpsep@@q($(THIRDPARTY_JARS))@@cpsep@@nfp(@bpm(STAGE1_DIR)@/nqp.jar)@ nqp --bootstrap @for_stages(@bpv(@ucstage@_GEN_CAT)@ = @bpm(GEN_CAT)@ @lcstage@ @bpv(NQP_@ucstage@_FLAGS)@ = --javaclass=nqp @@ -62,6 +63,7 @@ THIRDPARTY_JARS = $(ASM)@cpsep@$(ASMTREE)@cpsep@$(JLINE)@cpsep@$(JNA)@cpsep@$(JN $(NOECHO)$(CP) @q($(ASM))@ @q($(ASMTREE))@ @q($(DESTDIR@nop())@@bsm(NQP_LIB_DIR)@)@ $(NOECHO)$(CP) @q($(JLINE))@ @q($(JNA))@ @q($(DESTDIR@nop())@@bsm(NQP_LIB_DIR)@)@ $(NOECHO)$(CP) @q($(JNAPLATFORM))@ @q($(DESTDIR@nop())@@bsm(NQP_LIB_DIR)@)@ + $(NOECHO)$(CP) @q($(LZ4))@ @q($(DESTDIR@nop())@@bsm(NQP_LIB_DIR)@)@ $(NOECHO)$(CP) @q(@bsm(RUNTIME)@)@ @q($(DESTDIR@nop())@@bsm(NQP_LIB_DIR)@)@ $(NOECHO)$(CP) @q(@bpm(EVAL_CLIENT)@)@ @q($(DESTDIR)$(BIN_DIR))@ $(NOECHO)$(CHMOD) 0755 @nfpq($(DESTDIR)$(BIN_DIR)/eval-client.pl)@ @@ -75,7 +77,7 @@ THIRDPARTY_JARS = $(ASM)@cpsep@$(ASMTREE)@cpsep@$(JLINE)@cpsep@$(JNA)@cpsep@$(JN @bsm(RUNTIME)@: $(RUNTIME_JAVAS) @mkquot(@script(gen-jvm-properties.pl)@)@ @echo(+++ Preparing Java runtime)@ $(NOECHO)$(MKPATH) bin - $(NOECHO)$(JAVAC) --release 9 -cp @q($(THIRDPARTY_JARS))@ -g -d bin -encoding UTF8 $(RUNTIME_JAVAS) + $(NOECHO)$(JAVAC) --release 9 -cp @q($(THIRDPARTY_JARS))@ -g:none -d bin -encoding UTF8 $(RUNTIME_JAVAS) $(NOECHO)$(PERL5) @shquot(@script(gen-jvm-properties.pl)@)@ . @nfpq($(STATIC_NQP_HOME))@ @q($(THIRDPARTY_JARS))@ > jvmconfig.properties $(NOECHO)$(PERL5) @shquot(@script(gen-jvm-properties.pl)@)@ @nfpq(@prefix@)@ @nfpq($(STATIC_NQP_HOME))@ @q($(THIRDPARTY_JARS))@ > @nfpq(bin/jvmconfig.properties)@ $(NOECHO)$(JAR) cf0 @bsm(RUNTIME)@ -C @nfp(bin/)@ . diff --git a/tools/templates/jvm/nqp-j.in b/tools/templates/jvm/nqp-j.in index ac944d7187..ba649005f4 100644 --- a/tools/templates/jvm/nqp-j.in +++ b/tools/templates/jvm/nqp-j.in @@ -32,4 +32,4 @@ DIR=$(dirname -- "$EXEC") @setenv(JAR_DIR)@@q(@jar_dir@)@ @setenv(LIB_DIR)@@q(@lib_dir@)@ -@exec(java)@ -Dnqp.execname="$EXEC" -Xss1m -Xmx1324m -Xbootclasspath/a:"@cur_dir@@envvar(LIB_DIR)@@cpsep@@nfp(@envvar(JAR_DIR)@/nqp-runtime.jar)@@cpsep@@nfp(@envvar(JAR_DIR)@/@asmfile@)@@cpsep@@nfp(@envvar(JAR_DIR)@/@jlinefile@)@@cpsep@@nfp(@envvar(JAR_DIR)@/@jnafile@)@@cpsep@@nfp(@envvar(JAR_DIR)@/@jnaplatformfile@)@@cpsep@@nfp(@envvar(LIB_DIR)@/nqp.jar)@" -cp "@cur_dir@@envvar(LIB_DIR)@" nqp "@sh_allparams@" +@exec(java)@ -Dnqp.execname="$EXEC" -XX:+AggressiveHeap -XX:+AllowParallelDefineClass -Xbootclasspath/a:"@cur_dir@@envvar(LIB_DIR)@@cpsep@@nfp(@envvar(JAR_DIR)@/nqp-runtime.jar)@@cpsep@@nfp(@envvar(JAR_DIR)@/@asmfile@)@@cpsep@@nfp(@envvar(JAR_DIR)@/@jlinefile@)@@cpsep@@nfp(@envvar(JAR_DIR)@/@jnafile@)@@cpsep@@nfp(@envvar(JAR_DIR)@/@jnaplatformfile@)@@cpsep@@nfp(@envvar(JAR_DIR)@/@lz4file@)@@cpsep@@nfp(@envvar(LIB_DIR)@/nqp.jar)@" -cp "@cur_dir@@envvar(LIB_DIR)@" nqp "@sh_allparams@" diff --git a/tools/templates/jvm/nqp-j.windows b/tools/templates/jvm/nqp-j.windows index df5f084afa..d0ae89a176 100644 --- a/tools/templates/jvm/nqp-j.windows +++ b/tools/templates/jvm/nqp-j.windows @@ -1,4 +1,4 @@ @setenv(JAR_DIR)@@jar_dir@ @setenv(LIB_DIR)@@lib_dir@ -@exec(java)@ -Dnqp.execname="%~dpf0" -Xss1m -Xmx1324m -Xbootclasspath/a:"@cur_dir@@envvar(LIB_DIR)@@cpsep@@nfp(@envvar(JAR_DIR)@/nqp-runtime.jar)@@cpsep@@nfp(@envvar(JAR_DIR)@/@asmfile@)@@cpsep@@nfp(@envvar(JAR_DIR)@/@jlinefile@)@@cpsep@@nfp(@envvar(JAR_DIR)@/@jnafile@)@@cpsep@@nfp(@envvar(JAR_DIR)@/@jnaplatformfile@)@@cpsep@@nfp(@envvar(LIB_DIR)@/nqp.jar)@" -cp "@cur_dir@@envvar(LIB_DIR)@" nqp @sh_allparams@ +@exec(java)@ -Dnqp.execname="%~dpf0" -XX:+AggressiveHeap -XX:+AllowParallelDefineClass -Xbootclasspath/a:"@cur_dir@@envvar(LIB_DIR)@@cpsep@@nfp(@envvar(JAR_DIR)@/nqp-runtime.jar)@@cpsep@@nfp(@envvar(JAR_DIR)@/@asmfile@)@@cpsep@@nfp(@envvar(JAR_DIR)@/@jlinefile@)@@cpsep@@nfp(@envvar(JAR_DIR)@/@jnafile@)@@cpsep@@nfp(@envvar(JAR_DIR)@/@jnaplatformfile@)@@cpsep@@nfp(@envvar(JAR_DIR)@/@lz4file@)@@cpsep@@nfp(@envvar(LIB_DIR)@/nqp.jar)@" -cp "@cur_dir@@envvar(LIB_DIR)@" nqp @sh_allparams@