Skip to content

Commit

Permalink
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 {
}
146 changes: 146 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/aot/JRubySupport.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/*
* 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.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.FileVisitResult;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.jcodings.Encoding;
import org.jcodings.EncodingDB;
import org.jcodings.transcode.Transcoder;
import org.jcodings.transcode.TranscoderDB;
import org.jcodings.util.ArrayReader;
import org.jcodings.util.CaseInsensitiveBytesHash;
import org.joda.time.DateTimeZone;
import org.joda.time.tz.DateTimeZoneBuilder;
import org.joda.time.tz.ZoneInfoProvider;
import org.jruby.anno.TypePopulator;

public final class JRubySupport {
public static final Map<String, DateTimeZone> allTimeZones = getTimeZones();
public static final Map<String, EncodingInstance> allEncodings = getEncodings();
public static final Map<String, byte[]> allJCodingsTables = getJcodingsTables();

private static Map<String, DateTimeZone> getTimeZones() {
Map<String, DateTimeZone> timeZones = new HashMap<>();

// read in ZoneInfoMap to determine available timezones
Map<String, Object> zoneInfoMap = new HashMap<>();
try {
String resourcePath = "org/joda/time/tz/data/";
java.lang.reflect.Method readZoneInfoMap = ZoneInfoProvider.class.getDeclaredMethod("readZoneInfoMap", DataInputStream.class, Map.class);
readZoneInfoMap.setAccessible(true);
try (DataInputStream mapIn = new DataInputStream(ClassLoader.getSystemResourceAsStream(resourcePath + "ZoneInfoMap"))) {
readZoneInfoMap.invoke(null, mapIn, zoneInfoMap);
}
// preload all DateTimeZone objects
for (Map.Entry<String, Object> e : zoneInfoMap.entrySet()) {
Object value = e.getValue();
if (value instanceof String) {
String id = (String) value;
String path = resourcePath + id;
try (InputStream zoneIn = ClassLoader.getSystemResourceAsStream(path)) {
if (zoneIn != null) {
timeZones.put(e.getKey(), DateTimeZoneBuilder.readFrom(zoneIn, id));
} else {
throw new Error("Unable to load timezone " + id);
}
} catch (IOException ex) {

This comment has been minimized.

Copy link
@eregon

eregon Nov 29, 2016

Member

I think it's always better to rethrow as a RuntimeException or Error, silently catching exceptions can be very confusing to debug. Same below.

}
}
}
} catch (Exception e) {
}
timeZones.put("UTC", DateTimeZone.UTC);
return timeZones;
}

private static Map<String, EncodingInstance> getEncodings() {
final Map<String, EncodingInstance> encodings = new HashMap<>();
final CaseInsensitiveBytesHash<EncodingDB.Entry> encodingdb = EncodingDB.getEncodings();
for (EncodingDB.Entry entry : encodingdb) {
final String encodingClassName = entry.getEncodingClass();
final Encoding encoding = Encoding.load(encodingClassName);
encodings.put(encodingClassName, new EncodingInstance(encoding, encoding));
}

return encodings;
}

private static Map<String, byte[]> getJcodingsTables() {
Map<String, byte[]> jcodingsTables = new HashMap<>();
Set<String> jcodingsTableNames = new HashSet<>();

RootedFileVisitor<Path> visitor = new SimpleRootedFileVisitor<Path>() {
// match files that start with "tables/" and end with ".bin"
Pattern filePattern = Pattern.compile("^tables/(.*)\\.bin$");

@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
String fileName = getRoot().relativize(file).toString();
Matcher m = filePattern.matcher(fileName);
if (m.matches()) {
jcodingsTableNames.add(m.group(1));
}
return FileVisitResult.CONTINUE;
}
};

RootedFileVisitor.visitEachFileOnClassPath(visitor);

for (String name : jcodingsTableNames) {
String entry = "/tables/" + name + ".bin";
try (InputStream is = ArrayReader.class.getResourceAsStream(entry)) {
if (is != null) {
byte[] buf = new byte[is.available()];
new DataInputStream(is).readFully(buf);
jcodingsTables.put(name, buf);
} else {
throw new Error("Unable to load Jcodings table " + name);
}
} catch (IOException e) {
}
}
return jcodingsTables;
}

static class EncodingInstance {
Encoding instance;
Encoding dummy;

EncodingInstance(Encoding instance, Encoding dummy) {
this.instance = instance;
this.dummy = dummy;
}

Encoding get(boolean useDummy) {
if (useDummy && this.dummy != null) {
return this.dummy;
} else {
return this.instance;
}
}
}

}
63 changes: 63 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/aot/RootedFileVisitor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* 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.File;
import java.io.IOException;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;

/**
* Visit files with knowledge of the root of the subtree the traversal started from.
*/
interface RootedFileVisitor<T> extends FileVisitor<T> {
void setRoot(T root);

T getRoot();

static String rubyJarPath() {
String svmJarPath = RootedFileVisitor.class.getProtectionDomain().getCodeSource().getLocation().getFile();
String parentDir = new File(svmJarPath).getParent();

try {
// First try reading in the primary Ruby binary suite JAR.
File ret = new File(parentDir + "/../mx.imports/binary/jruby/mxbuild/dists/ruby.jar");

if (ret.exists()) {
return ret.getCanonicalPath();
} else {
// Fallback to the locally built source suite JAR.
return new File(parentDir + "/../../../jruby/mxbuild/dists/ruby.jar").getCanonicalPath();
}

} catch (IOException e) {
return null;
}
}

static void visitEachFileOnClassPath(RootedFileVisitor<Path> visitor) {
try (FileSystem jarFileSystem = FileSystems.newFileSystem(URI.create("jar:file:" + rubyJarPath()), Collections.emptyMap())) {
Path root = jarFileSystem.getPath("/");
visitor.setRoot(root);
Files.walkFileTree(root, visitor);
} catch (IOException ex) {
throw new Error(ex);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2015 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.nio.file.SimpleFileVisitor;

class SimpleRootedFileVisitor<T> extends SimpleFileVisitor<T> implements RootedFileVisitor<T> {
private T root;

@Override
public void setRoot(T root) {
this.root = root;
}

@Override
public T getRoot() {
return root;
}
}
201 changes: 201 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/aot/substitutions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
[
{
"annotatedClass": "org.jruby.truffle.aot.Target_org_jcodings_Encoding",
"originalClass": "org.jcodings.Encoding",
"methods": [
{
"annotatedName": "load",
"substitute": true
}
]
},
{
"annotatedClass": "org.jruby.truffle.aot.Target_org_jcodings_util_ArrayReader",
"originalClass": "org.jcodings.util.ArrayReader",
"methods": [
{
"annotatedName": "openStream",
"substitute": true
}
]
},
{
"annotatedClass": "org.jruby.truffle.aot.Target_org_joda_time_DateTimeUtils",
"originalClass": "org.joda.time.DateTimeUtils",
"methods": [
{
"annotatedName": "getDateFormatSymbols",
"substitute": true
}
]
},
{
"annotatedClass": "org.jruby.truffle.aot.Target_org_joda_time_tz_ZoneInfoProvider",
"originalClass": "org.joda.time.tz.ZoneInfoProvider",
"methods": [
{
"annotatedName": "getZone",
"substitute": true
},
{
"annotatedName": "openResource",
"substitute": true
}
],
"fields": [
{
"annotatedName": "iFileDir",
"alias": true
}
]
},
{
"annotatedClass": "org.jruby.truffle.aot.Target_org_jruby_RubyBasicObject",
"originalClass": "org.jruby.RubyBasicObject",
"methods": [
{
"annotatedName": "defaultToJava",
"substitute": true
}
],
"fields": [
{
"annotatedName": "STAMP_OFFSET",
"delete": true
},
{
"annotatedName": "VAR_TABLE_OFFSET",
"delete": true
}
]
},
{
"annotatedClass": "org.jruby.truffle.aot.Target_org_jruby_RubyEncoding",
"originalClass": "org.jruby.RubyEncoding",
"fields": [
{
"annotatedName": "BYTE_ARRAY_BASE",
"delete": true
},
{
"annotatedName": "CHAR_ARRAY_BASE",
"delete": true
},
{
"annotatedName": "VALUE_FIELD_OFFSET",
"delete": true
}
]
},
{
"annotatedClass": "org.jruby.truffle.aot.Target_org_jruby_RubyInstanceConfig",
"originalClass": "org.jruby.RubyInstanceConfig",
"methods": [
{
"annotatedName": "calculateJRubyHome",
"substitute": true
},
{
"annotatedName": "defaultClassLoader",
"substitute": true
},
{
"annotatedName": "setupEnvironment",
"substitute": true
},
{
"annotatedName": "verifyHome",
"alias": true
}
],
"fields": [
{
"annotatedName": "environment",
"alias": true
},
{
"annotatedName": "error",
"alias": true
}
]
},
{
"annotatedClass": "org.jruby.truffle.aot.Target_org_jruby_truffle_language_loader_SourceLoader",
"originalClass": "org.jruby.truffle.language.loader.SourceLoader",
"methods": [
{
"annotatedName": "loadResource",
"substitute": true
}
]
},
{
"annotatedClass": "org.jruby.truffle.aot.Target_org_jruby_util_JarResource",
"originalClass": "org.jruby.util.JarResource",
"methods": [
{
"annotatedName": "create",
"substitute": true
}
]
},
{
"annotatedClass": "org.jruby.truffle.aot.Target_org_jruby_util_StringSupport",
"originalClass": "org.jruby.util.StringSupport",
"fields": [
{
"annotatedName": "ARRAY_BYTE_BASE_OFFSET",
"delete": true
}
]
},
{
"annotatedClass": "org.jruby.truffle.aot.Target_org_jruby_util_URLResource",
"originalClass": "org.jruby.util.URLResource",
"methods": [
{
"annotatedName": "createClassloaderURI",
"substitute": true
},
{
"annotatedName": "openInputStream",
"substitute": true
}
],
"fields": [
{
"annotatedName": "url",
"alias": true
}
]
},
{
"annotatedClass": "org.jruby.truffle.aot.Target_org_jruby_util_unsafe_UnsafeHolder",
"originalClass": "org.jruby.util.unsafe.UnsafeHolder",
"methods": [
{
"annotatedName": "fullFence",
"substitute": true
}
],
"fields": [
{
"annotatedName": "ARRAY_OBJECT_BASE_OFFSET",
"alias": true,
"kind": "ArrayBaseOffset",
"declClassName": "[Ljava.lang.Object;"
},
{
"annotatedName": "ARRAY_OBJECT_INDEX_SCALE",
"alias": true,
"kind": "ArrayIndexScale",
"declClassName": "[Ljava.lang.Object;"
},
{
"annotatedName": "SUPPORTS_FENCES",
"alias": true,
"kind": "FromAlias"
}
]
},
]
Original file line number Diff line number Diff line change
@@ -22,7 +22,9 @@
import org.jcodings.transcode.EConv;
import org.jcodings.transcode.EConvFlags;
import org.jcodings.transcode.EConvResult;
import org.jcodings.transcode.Transcoder;
import org.jcodings.transcode.TranscoderDB;
import org.jcodings.transcode.TranscodingManager;
import org.jcodings.util.CaseInsensitiveBytesHash;
import org.jcodings.util.Hash;
import org.jruby.runtime.Visibility;
@@ -39,6 +41,7 @@
import org.jruby.truffle.core.rope.RopeNodes;
import org.jruby.truffle.core.rope.RopeNodesFactory;
import org.jruby.truffle.core.rope.RopeOperations;
import org.jruby.truffle.core.rope.RopeTable;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.language.NotProvided;
import org.jruby.truffle.language.RubyGuards;
@@ -49,6 +52,8 @@
import org.jruby.truffle.util.StringUtils;
import org.jruby.util.ByteList;

import java.util.Map;

import static org.jruby.truffle.core.string.StringOperations.rope;

@CoreClass("Encoding::Converter")
@@ -69,11 +74,8 @@ public DynamicObject initialize(DynamicObject self, DynamicObject source, Dynami

Encoding sourceEncoding = Layouts.ENCODING.getEncoding(source);
Encoding destinationEncoding = Layouts.ENCODING.getEncoding(destination);
final byte[] sourceEncodingName = sourceEncoding.getName();
final byte[] destinationEncodingName = destinationEncoding.getName();

final EConv econv = TranscoderDB.open(sourceEncodingName, destinationEncodingName, rubiniusToJRubyFlags(options));

final EConv econv = TranscodingManager.create(sourceEncoding, destinationEncoding, options);
econv.sourceEncoding = sourceEncoding;
econv.destinationEncoding = destinationEncoding;

@@ -124,25 +126,18 @@ public TranscodingMapNode(RubyContext context, SourceSection sourceSection) {
public Object transcodingMap(VirtualFrame frame) {
final Object ret = newLookupTableNode.call(frame, coreLibrary().getLookupTableClass(), "new");

for (CaseInsensitiveBytesHash<TranscoderDB.Entry> sourceEntry : TranscoderDB.transcoders) {
Object key = null;
final Object value = newLookupTableNode.call(frame, coreLibrary().getLookupTableClass(), "new");
for (Map.Entry<String, Map<String, Transcoder>> sourceEntry : TranscodingManager.allTranscoders.entrySet()) {
final DynamicObject source = getContext().getSymbolTable().getSymbol(sourceEntry.getKey());
final Object destinations = newLookupTableNode.call(frame, coreLibrary().getLookupTableClass(), "new");

for (Hash.HashEntry<TranscoderDB.Entry> destinationEntry : sourceEntry.entryIterator()) {
final TranscoderDB.Entry e = destinationEntry.value;

if (key == null) {
final Object upcased = upcaseNode.call(frame, createString(e.getSource(), USASCIIEncoding.INSTANCE), "upcase");
key = toSymNode.call(frame, upcased, "to_sym");
}
for (Map.Entry<String, Transcoder> destinationEntry : sourceEntry.getValue().entrySet()) {
final DynamicObject destination = getContext().getSymbolTable().getSymbol(destinationEntry.getKey());
final Object lookupTableValue = newTranscodingNode.call(frame, coreLibrary().getTranscodingClass(), "create", source, destination);

final Object upcasedLookupTableKey = upcaseNode.call(frame, createString(e.getDestination(), USASCIIEncoding.INSTANCE), "upcase");
final Object lookupTableKey = toSymNode.call(frame, upcasedLookupTableKey, "to_sym");
final Object lookupTableValue = newTranscodingNode.call(frame, coreLibrary().getTranscodingClass(), "create", key, lookupTableKey);
lookupTableWriteNode.call(frame, value, "[]=", lookupTableKey, lookupTableValue);
lookupTableWriteNode.call(frame, destinations, "[]=", destination, lookupTableValue);
}

lookupTableWriteNode.call(frame, ret, "[]=", key, value);
lookupTableWriteNode.call(frame, ret, "[]=", source, destinations);
}

return ret;
@@ -247,7 +242,7 @@ private Object primitiveConvertHelper(DynamicObject encodingConverter, DynamicOb
inPtr.p = 0;
outPtr.p = offset;
int os = outPtr.p + size;
EConvResult res = ec.convert(sourceRope.getBytes(), inPtr, sourceRope.byteLength() + inPtr.p, outBytes.getUnsafeBytes(), outPtr, os, options);
EConvResult res = TranscodingManager.convert(ec, sourceRope.getBytes(), inPtr, sourceRope.byteLength() + inPtr.p, outBytes.getUnsafeBytes(), outPtr, os, options);

outBytes.setRealSize(outPtr.p - outBytes.begin());

Original file line number Diff line number Diff line change
@@ -194,12 +194,17 @@ public DynamicObject localtime(DynamicObject time) {

Layouts.TIME.setIsUtc(time, true);
Layouts.TIME.setRelativeOffset(time, false);
Layouts.TIME.setZone(time, create7BitString(UTC.getDisplayName(TextStyle.NARROW, Locale.ENGLISH), USASCIIEncoding.INSTANCE));
Layouts.TIME.setZone(time, create7BitString(getUTCDisplayName(), USASCIIEncoding.INSTANCE));
Layouts.TIME.setDateTime(time, inUTC(dateTime));

return time;
}

@TruffleBoundary
private String getUTCDisplayName() {
return UTC.getDisplayName(TextStyle.NARROW, Locale.ENGLISH);
}

@TruffleBoundary
private ZonedDateTime inUTC(final ZonedDateTime dateTime) {
return dateTime.withZoneSameInstant(UTC);
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@
import com.kenai.jffi.Platform.OS;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.TruffleOptions;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
@@ -193,6 +194,10 @@ public int getGroups(int max, DynamicObject pointer) {

@TruffleBoundary
private static long[] getGroups() {
if (TruffleOptions.AOT) {
throw new UnsupportedOperationException("UnixSystem is not supported with AOT.");
}

return new UnixSystem().getGroups();
}
}
Original file line number Diff line number Diff line change
@@ -52,7 +52,7 @@
import org.jcodings.specific.UTF8Encoding;
import org.jcodings.transcode.EConv;
import org.jcodings.transcode.EConvResult;
import org.jcodings.transcode.TranscoderDB;
import org.jcodings.transcode.TranscodingManager;
import org.jcodings.unicode.UnicodeEncoding;
import org.jruby.RubyEncoding;
import org.jruby.runtime.Helpers;
@@ -463,7 +463,7 @@ private static ByteList strConvEncOpts(RubyContext context, ByteList str, Encodi
ByteList newStr = new ByteList(len);
int olen = len;

EConv ec = econvOpenOpts(context, fromEncoding.getName(), toEncoding.getName(), ecflags, ecopts);
EConv ec = econvOpenOpts(context, fromEncoding, toEncoding, ecflags, ecopts);
if (ec == null) return str;

byte[] sbytes = strByteList.getUnsafeBytes();
@@ -479,7 +479,7 @@ private static ByteList strConvEncOpts(RubyContext context, ByteList str, Encodi
destbytes = newStr.getUnsafeBytes();
int dest = newStr.begin();
dp.p = dest + convertedOutput;
ret = ec.convert(sbytes, sp, start + len, destbytes, dp, dest + olen, 0);
ret = TranscodingManager.convert(ec, sbytes, sp, start + len, destbytes, dp, dest + olen, 0);

while (ret == EConvResult.DestinationBufferFull) {
int convertedInput = sp.p - start;
@@ -499,7 +499,7 @@ private static ByteList strConvEncOpts(RubyContext context, ByteList str, Encodi
destbytes = newStr.getUnsafeBytes();
dest = newStr.begin();
dp.p = dest + convertedOutput;
ret = ec.convert(sbytes, sp, start + len, destbytes, dp, dest + olen, 0);
ret = TranscodingManager.convert(ec, sbytes, sp, start + len, destbytes, dp, dest + olen, 0);
}
ec.close();

@@ -516,8 +516,8 @@ private static ByteList strConvEncOpts(RubyContext context, ByteList str, Encodi
}
}

private static EConv econvOpenOpts(RubyContext context, byte[] sourceEncoding, byte[] destinationEncoding, int ecflags, Object opthash) {
EConv ec = TranscoderDB.open(sourceEncoding, destinationEncoding, ecflags);
private static EConv econvOpenOpts(RubyContext context, Encoding sourceEncoding, Encoding destinationEncoding, int ecflags, Object opthash) {
EConv ec = TranscodingManager.create(sourceEncoding, destinationEncoding, ecflags);
return ec;
}

0 comments on commit 00938d2

Please sign in to comment.