Skip to content

Commit

Permalink
[Truffle] Consolidated support code for AOT image.
Browse files Browse the repository at this point in the history
  • Loading branch information
nirvdrum committed Nov 28, 2016
1 parent 81a3a8c commit 00938d2
Show file tree
Hide file tree
Showing 11 changed files with 1,316 additions and 27 deletions.
518 changes: 518 additions & 0 deletions truffle/src/main/java/org/jcodings/transcode/TranscodingManager.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*
*
* Some of the code in this class is modified from org.jruby.util.StringSupport,
* licensed under the same EPL1.0/GPL 2.0/LGPL 2.1 used throughout.
*/
package org.jruby.truffle.aot;

import java.io.IOException;
import java.io.Reader;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.jruby.truffle.language.loader.SourceLoader;
import com.oracle.truffle.api.source.Source;

public final class JRubySourceLoaderSupport {
public static final Map<String, CoreLibraryFile> allCoreLibraryFiles = getCoreLibrary();

public static String canonicalizeResourcePath(String path) {
String tmpPath = path;
if (path.startsWith(SourceLoader.TRUFFLE_SCHEME)) {
tmpPath = path.substring(SourceLoader.TRUFFLE_SCHEME.length());
} else if (path.startsWith(SourceLoader.JRUBY_SCHEME)) {
tmpPath = path.substring(SourceLoader.JRUBY_SCHEME.length());
} else if (tmpPath.startsWith("core:/")) {
tmpPath = tmpPath.substring("core:/".length());
} else if (tmpPath.startsWith("uri:classloader:/")) {
tmpPath = tmpPath.substring("uri:classloader:/".length());
}

if (tmpPath.startsWith("/")) {
tmpPath = tmpPath.substring(1);
}

try {
return new URI(tmpPath).normalize().getPath();
} catch (URISyntaxException e) {
return tmpPath;
}
}

private static Set<String> getCoreLibraryFiles() {
Set<String> coreLibraryFiles = new HashSet<>();

RootedFileVisitor<Path> visitor = new SimpleRootedFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
String fileName = getRoot().relativize(file).toString();
if (fileName.endsWith(".rb")) {
coreLibraryFiles.add(fileName);
}
return FileVisitResult.CONTINUE;
}
};

RootedFileVisitor.visitEachFileOnClassPath(visitor);
return coreLibraryFiles;
}

@SuppressWarnings("deprecation")
private static Map<String, CoreLibraryFile> getCoreLibrary() {
Map<String, CoreLibraryFile> coreLibrary = new HashMap<>();
Set<String> coreLibraryFiles = getCoreLibraryFiles();
try (FileSystem jarFileSystem = FileSystems.newFileSystem(URI.create("jar:file:" + RootedFileVisitor.rubyJarPath()), Collections.emptyMap())) {
for (String name : coreLibraryFiles) {
Path filePath = jarFileSystem.getPath("/" + name);
try (Reader reader = Files.newBufferedReader(filePath)) {
if (reader != null) {
Source source = Source.fromReader(reader, name);

byte[] code = source.getCode().getBytes(StandardCharsets.UTF_8);
coreLibrary.put(name, new CoreLibraryFile(code, null));
} else {
throw new Error("Unable to load ruby core library file " + name);
}
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
return coreLibrary;
}

public static class CoreLibraryFile {
public final byte[] code;
public final Map<Integer, CoreLibraryMethod> methods;

public CoreLibraryFile(byte[] code, Map<Integer, CoreLibraryMethod> methods) {
this.code = code;
this.methods = methods;
}
}

public static class CoreLibraryMethod {
public final String name;
public final byte[] code;

public CoreLibraryMethod(String name, byte[] code) {
this.name = name;
this.code = code;
}
}

}
200 changes: 200 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/aot/JRubySubstitutions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
/*
* Copyright (c) 2014, 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*
*
* Some of the code in this class is modified from org.jruby.util.StringSupport,
* licensed under the same EPL1.0/GPL 2.0/LGPL 2.1 used throughout.
*/
package org.jruby.truffle.aot;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.DateFormatSymbols;
import java.util.Locale;
import java.util.Map;

import org.jcodings.exception.InternalException;
import org.joda.time.DateTimeZone;
import org.jruby.Ruby;
import org.jruby.truffle.RubyLanguage;
import org.jruby.truffle.language.loader.SourceLoader;
import org.jruby.util.FileResource;
import org.jruby.util.SafePropertyAccessor;

import com.oracle.truffle.api.source.Source;

// Checkstyle: stop

final class Target_org_jruby_util_unsafe_UnsafeHolder {
static boolean SUPPORTS_FENCES = false;
static long ARRAY_OBJECT_BASE_OFFSET;
static long ARRAY_OBJECT_INDEX_SCALE;

static void fullFence() {
}
}

final class Target_org_jcodings_Encoding {
static org.jcodings.Encoding load(String name) {
JRubySupport.EncodingInstance instance = JRubySupport.allEncodings.get(name);
if (instance == null) {
throw new InternalException(org.jcodings.exception.ErrorMessages.ERR_ENCODING_CLASS_DEF_NOT_FOUND, "org.jcodings.specific." + name + "Encoding");
}
return instance.get(false);
}
}

final class Target_org_jcodings_util_ArrayReader {
static DataInputStream openStream(String name) {
byte[] table = JRubySupport.allJCodingsTables.get(name);
if (table == null) {
throw new InternalException(("entry: /tables/" + name + ".bin not found"));
}
return new DataInputStream(new ByteArrayInputStream(table));
}
}

@SuppressWarnings("static-method")
final class Target_org_joda_time_tz_ZoneInfoProvider {
File iFileDir;

DateTimeZone getZone(String id) {
return JRubySupport.allTimeZones.get(id);
}

InputStream openResource(String name) throws IOException {
if (iFileDir != null) {
return new FileInputStream(new File(iFileDir, name));
} else {
throw new IllegalArgumentException("Not supported on SubstrateVM");
}
}
}

@SuppressWarnings("unused")
final class Target_org_jruby_util_URLResource {
URL url;

static FileResource createClassloaderURI(Ruby runtime, String pathname, boolean isFile) {
throw new RuntimeException("Not supported on Substrate VM");
}

InputStream openInputStream() throws IOException {
return url.openStream();
}
}

final class Target_org_jruby_RubyInstanceConfig {
PrintStream error;
Map<String, String> environment;

static native String verifyHome(String home, PrintStream error);

static ClassLoader defaultClassLoader() {
return null;
}

void setupEnvironment(String jrubyHome) {
if (!new File(jrubyHome).exists() && !environment.containsKey("RUBY")) {
environment.put("RUBY", "svm_jruby");
}
}

String calculateJRubyHome() {
String newJRubyHome = null;

// try the normal property first
if (!Ruby.isSecurityRestricted()) {
newJRubyHome = SafePropertyAccessor.getProperty("jruby.home");
}

if (newJRubyHome != null) {
// verify it if it's there
newJRubyHome = verifyHome(newJRubyHome, error);
} else {
try {
newJRubyHome = SafePropertyAccessor.getenv("JRUBY_HOME");
} catch (Exception e) {
}

if (newJRubyHome != null) {
// verify it if it's there
newJRubyHome = verifyHome(newJRubyHome, error);
} else {
// otherwise fall back on system temp location
newJRubyHome = SafePropertyAccessor.getProperty("java.io.tmpdir");
}
}

return newJRubyHome;
}
}

final class Target_org_joda_time_DateTimeUtils {
static DateFormatSymbols getDateFormatSymbols(Locale locale) {
return DateFormatSymbols.getInstance(locale);
}
}

@SuppressWarnings("unused")
final class Target_org_jruby_util_JarResource {
static Object create(String pathname) {
return null;
}
}

@SuppressWarnings({"static-method", "unused"})
final class Target_org_jruby_RubyBasicObject {
static long VAR_TABLE_OFFSET;
static long STAMP_OFFSET;

<T> T defaultToJava(Class<T> target) {
return null;
}
}

final class Target_org_jruby_RubyEncoding {
static int CHAR_ARRAY_BASE;
static int BYTE_ARRAY_BASE;
static long VALUE_FIELD_OFFSET;
}

final class Target_org_jruby_util_StringSupport {
static int ARRAY_BYTE_BASE_OFFSET;
}

@SuppressWarnings("static-method")
final class Target_org_jruby_truffle_language_loader_SourceLoader {
Source loadResource(String path) throws IOException {
if (!(path.startsWith(SourceLoader.TRUFFLE_SCHEME) || path.startsWith(SourceLoader.JRUBY_SCHEME))) {
throw new UnsupportedOperationException();
}

final String canonicalPath = JRubySourceLoaderSupport.canonicalizeResourcePath(path);
final JRubySourceLoaderSupport.CoreLibraryFile coreFile = JRubySourceLoaderSupport.allCoreLibraryFiles.get(canonicalPath);
if (coreFile == null) {
throw new FileNotFoundException(path);
}

return Source.newBuilder(new InputStreamReader(new ByteArrayInputStream(coreFile.code), StandardCharsets.UTF_8)).name(path).mimeType(RubyLanguage.MIME_TYPE).build();
}
}

/** Dummy class to have a class with the file's name. */
public final class JRubySubstitutions {
}
Loading

0 comments on commit 00938d2

Please sign in to comment.