Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 62fe57ff8bf3
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: d7089435c941
Choose a head ref

Commits on Feb 24, 2016

  1. Copy the full SHA
    6e349f3 View commit details
  2. Copy the full SHA
    180a8d2 View commit details
  3. Copy the full SHA
    d8ab6eb View commit details
  4. Copy the full SHA
    05a8efa View commit details

Commits on Feb 25, 2016

  1. Copy the full SHA
    75d2230 View commit details
  2. Copy the full SHA
    ed998fc View commit details
  3. Copy the full SHA
    497c858 View commit details
  4. [Truffle] Formatting.

    chrisseaton committed Feb 25, 2016
    Copy the full SHA
    0b79bf1 View commit details
  5. Copy the full SHA
    777b2d5 View commit details
  6. Copy the full SHA
    4b2d77a View commit details
  7. Copy the full SHA
    1a0c048 View commit details

Commits on Feb 26, 2016

  1. Copy the full SHA
    34c1750 View commit details
  2. Copy the full SHA
    182fec8 View commit details
  3. Copy the full SHA
    c148b54 View commit details
  4. Copy the full SHA
    6e2110f View commit details
  5. [Truffle] JT: Use GraalVM-0.10

    eregon committed Feb 26, 2016
    Copy the full SHA
    82248b2 View commit details
  6. Copy the full SHA
    8f64a78 View commit details
  7. Copy the full SHA
    48b557d View commit details
  8. Copy the full SHA
    74165c3 View commit details
  9. Copy the full SHA
    5259d3d View commit details
  10. Copy the full SHA
    98e9c40 View commit details
  11. Copy the full SHA
    aaf2b01 View commit details
  12. [Truffle] Fix wrong usages of the Frame API.

    * Only FrameAccess.MATERIALIZE should call Frame.materialize().
    * READ_ONLY can obviously not write to the frame.
    eregon committed Feb 26, 2016
    Copy the full SHA
    dc0219b View commit details
  13. [Truffle] Fix bad usage of capacity.

    * Use capacity only if one of the existing store needs to grow.
    eregon committed Feb 26, 2016
    Copy the full SHA
    35323f6 View commit details
  14. Copy the full SHA
    d708943 View commit details
Showing with 273 additions and 168 deletions.
  1. +0 −1 core/pom.rb
  2. +0 −1 core/pom.xml
  3. +61 −34 core/src/main/java/org/jruby/ir/targets/IRBytecodeAdapter6.java
  4. +9 −11 core/src/main/java/org/jruby/runtime/backtrace/BacktraceData.java
  5. +1 −1 core/src/main/java/org/jruby/runtime/backtrace/BacktraceElement.java
  6. +9 −4 core/src/main/java/org/jruby/runtime/backtrace/FrameType.java
  7. +2 −2 tool/jruby_eclipse
  8. +19 −4 tool/jt.rb
  9. +0 −1 truffle/src/main/java/org/jruby/truffle/core/YieldingCoreMethodNode.java
  10. +2 −2 truffle/src/main/java/org/jruby/truffle/core/array/ArrayAppendManyNode.java
  11. +7 −2 truffle/src/main/java/org/jruby/truffle/core/regexp/RegexpNodes.java
  12. +6 −2 truffle/src/main/java/org/jruby/truffle/core/rubinius/DirPrimitiveNodes.java
  13. +2 −1 truffle/src/main/java/org/jruby/truffle/core/rubinius/RubiniusLastStringReadNode.java
  14. +2 −1 truffle/src/main/java/org/jruby/truffle/core/rubinius/RubiniusLastStringWriteNode.java
  15. +1 −0 truffle/src/main/java/org/jruby/truffle/core/rubinius/ThreadPrimitiveNodes.java
  16. +1 −0 truffle/src/main/java/org/jruby/truffle/core/thread/ThreadManager.java
  17. +1 −0 truffle/src/main/java/org/jruby/truffle/core/thread/ThreadNodes.java
  18. +1 −0 truffle/src/main/java/org/jruby/truffle/language/SafepointManager.java
  19. +4 −2 truffle/src/main/java/org/jruby/truffle/language/control/WhileNode.java
  20. +0 −4 truffle/src/main/java/org/jruby/truffle/language/defined/DefinedNode.java
  21. +7 −7 truffle/src/main/java/org/jruby/truffle/language/defined/DefinedWrapperNode.java
  22. +1 −1 truffle/src/main/java/org/jruby/truffle/language/exceptions/DisablingBacktracesNode.java
  23. +15 −17 truffle/src/main/java/org/jruby/truffle/language/exceptions/EnsureNode.java
  24. +1 −9 truffle/src/main/java/org/jruby/truffle/language/exceptions/RescueAnyNode.java
  25. +6 −14 truffle/src/main/java/org/jruby/truffle/language/exceptions/RescueClassesNode.java
  26. +14 −4 truffle/src/main/java/org/jruby/truffle/language/exceptions/RescueNode.java
  27. +2 −14 truffle/src/main/java/org/jruby/truffle/language/exceptions/RescueSplatNode.java
  28. +79 −0 truffle/src/main/java/org/jruby/truffle/language/exceptions/SetExceptionVariableNode.java
  29. +10 −17 truffle/src/main/java/org/jruby/truffle/language/exceptions/TryNode.java
  30. +1 −0 truffle/src/main/java/org/jruby/truffle/language/objects/ObjectGraph.java
  31. +6 −8 truffle/src/main/java/org/jruby/truffle/language/translator/BodyTranslator.java
  32. +0 −1 truffle/src/main/java/org/jruby/truffle/language/yield/YieldExpressionNode.java
  33. +2 −3 truffle/src/main/java/org/jruby/truffle/language/yield/YieldNode.java
  34. +1 −0 truffle/src/main/java/org/jruby/truffle/tools/InstrumentationServerManager.java
1 change: 0 additions & 1 deletion core/pom.rb
Original file line number Diff line number Diff line change
@@ -218,7 +218,6 @@
'forkCount' => '1',
'reuseForks' => 'false',
'systemProperties' => {
'jruby.compat.version' => '1.9',
'jruby.home' => '${basedir}/..'
},
'argLine' => '-Xmx${jruby.test.memory} -XX:MaxPermSize=${jruby.test.memory.permgen} -Dfile.encoding=UTF-8 -Djava.awt.headless=true',
1 change: 0 additions & 1 deletion core/pom.xml
Original file line number Diff line number Diff line change
@@ -563,7 +563,6 @@ DO NOT MODIFIY - GENERATED CODE
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
<systemProperties>
<jruby.compat.version>1.9</jruby.compat.version>
<jruby.home>${basedir}/..</jruby.home>
</systemProperties>
<argLine>-Xmx${jruby.test.memory} -XX:MaxPermSize=${jruby.test.memory.permgen} -Dfile.encoding=UTF-8 -Djava.awt.headless=true</argLine>
95 changes: 61 additions & 34 deletions core/src/main/java/org/jruby/ir/targets/IRBytecodeAdapter6.java
Original file line number Diff line number Diff line change
@@ -174,27 +174,41 @@ public void run() {
});
}

private static String keyFor(Object... objs) {
StringBuilder sb = new StringBuilder();
for (Object obj : objs) {
sb.append(obj.toString());
if (obj instanceof ByteList) sb.append('_').append(((ByteList) obj).getEncoding());
sb.append("_");
}
private static String keyFor(Object obj1, Object obj2) {
StringBuilder sb = new StringBuilder(16);
keyFor(sb, obj1);
keyFor(sb, obj2);
return sb.toString();
}

private static String keyFor(Object obj1, Object obj2, Object obj3) {
StringBuilder sb = new StringBuilder(24);
keyFor(sb, obj1);
keyFor(sb, obj2);
keyFor(sb, obj3);
return sb.toString();
}

private static void keyFor(StringBuilder builder, Object obj) {
builder.append(obj.toString());
if (obj instanceof ByteList) builder.append('_').append(((ByteList) obj).getEncoding());
builder.append('_');
}

public void pushDRegexp(final Runnable callback, final RegexpOptions options, final int arity) {
if (arity > MAX_ARGUMENTS) throw new NotCompilableException("dynamic regexp has more than " + MAX_ARGUMENTS + " elements");

SkinnyMethodAdapter adapter2;
final String incomingSig = sig(RubyRegexp.class, params(ThreadContext.class, RubyString.class, arity, int.class));

if (!getClassData().dregexpMethodsDefined.contains(arity)) {
final String methodName = "dregexp:" + arity;
final ClassData classData = getClassData();

if (!classData.dregexpMethodsDefined.contains(arity)) {
adapter2 = new SkinnyMethodAdapter(
adapter.getClassVisitor(),
Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC,
"dregexp:" + arity,
methodName,
incomingSig,
null,
null);
@@ -207,32 +221,34 @@ public void pushDRegexp(final Runnable callback, final RegexpOptions options, fi
adapter2.areturn();
adapter2.end();

getClassData().dregexpMethodsDefined.add(arity);
classData.dregexpMethodsDefined.add(arity);
}

final String className = classData.clsName;

if (options.isOnce()) {
// need to cache result forever, but do it under sync to avoid double init
final String cacheField = "dregexp" + getClassData().callSiteCount.getAndIncrement();
final String cacheField = "dregexp" + classData.callSiteCount.getAndIncrement();
final Label done = new Label();
final String clsDesc = "L" + getClassData().clsName.replaceAll("\\.", "/") + ";";
final String clsDesc = 'L' + className.replace('.', '/') + ';';
adapter.ldc(Type.getType(clsDesc));
adapter.monitorenter();
adapter.trycatch(p(Throwable.class),
new Runnable() {
public void run() {
adapter.getClassVisitor().visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, cacheField, ci(RubyRegexp.class), null, null).visitEnd();
adapter.getstatic(getClassData().clsName, cacheField, ci(RubyRegexp.class));
adapter.getstatic(className, cacheField, ci(RubyRegexp.class));
adapter.dup();
adapter.ifnonnull(done);
adapter.pop();

// call synthetic method if we still need to build dregexp
callback.run();
adapter.ldc(options.toEmbeddedOptions());
adapter.invokestatic(getClassData().clsName, "dregexp:" + arity, incomingSig);
adapter.invokestatic(className, methodName, incomingSig);

adapter.dup();
adapter.putstatic(getClassData().clsName, cacheField, ci(RubyRegexp.class));
adapter.putstatic(className, cacheField, ci(RubyRegexp.class));
adapter.label(done);

adapter.ldc(Type.getType(clsDesc));
@@ -250,7 +266,7 @@ public void run() {
// call synthetic method if we still need to build dregexp
callback.run();
adapter.ldc(options.toEmbeddedOptions());
adapter.invokestatic(getClassData().clsName, "dregexp:" + arity, incomingSig);
adapter.invokestatic(className, methodName, incomingSig);
}
}

@@ -475,7 +491,7 @@ public void invokeOtherOneFloat(String name, double flote) {
String incomingSig = sig(JVM.OBJECT, params(ThreadContext.class, JVM.OBJECT, JVM.OBJECT));
String outgoingSig = sig(JVM.OBJECT, params(ThreadContext.class, JVM.OBJECT, JVM.OBJECT, double.class));

String methodName = "invokeOtherOneFloat" + getClassData().callSiteCount.getAndIncrement() + ":" + JavaNameMangler.mangleMethodName(name);
String methodName = "invokeOtherOneFloat" + getClassData().callSiteCount.getAndIncrement() + ':' + JavaNameMangler.mangleMethodName(name);

adapter2 = new SkinnyMethodAdapter(
adapter.getClassVisitor(),
@@ -561,7 +577,7 @@ private void performSuper(String name, int arity, boolean hasClosure, boolean[]
sig(JVM.OBJECT, params(ThreadContext.class, IRubyObject.class, String.class, RubyModule.class, JVM.OBJECT_ARRAY, Block.class, boolean[].class));
}

String methodName = "invokeSuper" + getClassData().callSiteCount.getAndIncrement() + ":" + JavaNameMangler.mangleMethodName(name);
String methodName = "invokeSuper" + getClassData().callSiteCount.getAndIncrement() + ':' + JavaNameMangler.mangleMethodName(name);
adapter2 = new SkinnyMethodAdapter(
adapter.getClassVisitor(),
Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC,
@@ -663,7 +679,7 @@ private void cacheVariableAccessor(String name, boolean write) {
SkinnyMethodAdapter adapter2;
String incomingSig = sig(VariableAccessor.class, params(JVM.OBJECT));

String methodName = (write ? "ivarSet" : "ivarGet") + getClassData().callSiteCount.getAndIncrement() + ":" + JavaNameMangler.mangleMethodName(name);
String methodName = (write ? "ivarSet" : "ivarGet") + getClassData().callSiteCount.getAndIncrement() + ':' + JavaNameMangler.mangleMethodName(name);

adapter2 = new SkinnyMethodAdapter(
adapter.getClassVisitor(),
@@ -676,8 +692,10 @@ private void cacheVariableAccessor(String name, boolean write) {
// call site object field
adapter.getClassVisitor().visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, methodName, ci(VariableAccessor.class), null, null).visitEnd();

final String className = getClassData().clsName;

// retrieve accessor, verifying if non-null
adapter2.getstatic(getClassData().clsName, methodName, ci(VariableAccessor.class));
adapter2.getstatic(className, methodName, ci(VariableAccessor.class));
adapter2.dup();
Label get = new Label();
adapter2.ifnull(get);
@@ -695,13 +713,13 @@ private void cacheVariableAccessor(String name, boolean write) {
adapter2.ldc(name);
adapter2.invokestatic(p(IRRuntimeHelpers.class), write ? "getVariableAccessorForWrite" : "getVariableAccessorForRead", sig(VariableAccessor.class, IRubyObject.class, String.class));
adapter2.dup();
adapter2.putstatic(getClassData().clsName, methodName, ci(VariableAccessor.class));
adapter2.putstatic(className, methodName, ci(VariableAccessor.class));
adapter2.areturn();

adapter2.end();

// call it from original method to get accessor
adapter.invokestatic(getClassData().clsName, methodName, incomingSig);
adapter.invokestatic(className, methodName, incomingSig);
}

public void array(int length) {
@@ -710,11 +728,14 @@ public void array(int length) {
SkinnyMethodAdapter adapter2;
String incomingSig = sig(JVM.OBJECT, params(ThreadContext.class, JVM.OBJECT, length));

if (!getClassData().arrayMethodsDefined.contains(length)) {
final String methodName = "array:" + length;
final ClassData classData = getClassData();

if (!classData.arrayMethodsDefined.contains(length)) {
adapter2 = new SkinnyMethodAdapter(
adapter.getClassVisitor(),
Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC,
"array:" + length,
methodName,
incomingSig,
null,
null);
@@ -727,11 +748,11 @@ public void array(int length) {
adapter2.areturn();
adapter2.end();

getClassData().arrayMethodsDefined.add(length);
classData.arrayMethodsDefined.add(length);
}

// now call it
adapter.invokestatic(getClassData().clsName, "array:" + length, incomingSig);
adapter.invokestatic(classData.clsName, methodName, incomingSig);
}

public void hash(int length) {
@@ -740,11 +761,14 @@ public void hash(int length) {
SkinnyMethodAdapter adapter2;
String incomingSig = sig(JVM.OBJECT, params(ThreadContext.class, JVM.OBJECT, length * 2));

if (!getClassData().hashMethodsDefined.contains(length)) {
final String methodName = "hash:" + length;
final ClassData classData = getClassData();

if (!classData.hashMethodsDefined.contains(length)) {
adapter2 = new SkinnyMethodAdapter(
adapter.getClassVisitor(),
Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC,
"hash:" + length,
methodName,
incomingSig,
null,
null);
@@ -757,11 +781,11 @@ public void hash(int length) {
adapter2.areturn();
adapter2.end();

getClassData().hashMethodsDefined.add(length);
classData.hashMethodsDefined.add(length);
}

// now call it
adapter.invokestatic(getClassData().clsName, "hash:" + length, incomingSig);
adapter.invokestatic(classData.clsName, methodName, incomingSig);
}

public void kwargsHash(int length) {
@@ -770,11 +794,14 @@ public void kwargsHash(int length) {
SkinnyMethodAdapter adapter2;
String incomingSig = sig(JVM.OBJECT, params(ThreadContext.class, RubyHash.class, IRubyObject.class, length * 2));

if (!getClassData().kwargsHashMethodsDefined.contains(length)) {
final String methodName = "kwargsHash:" + length;
final ClassData classData = getClassData();

if (!classData.kwargsHashMethodsDefined.contains(length)) {
adapter2 = new SkinnyMethodAdapter(
adapter.getClassVisitor(),
Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC,
"kwargsHash:" + length,
methodName,
incomingSig,
null,
null);
@@ -787,11 +814,11 @@ public void kwargsHash(int length) {
adapter2.areturn();
adapter2.end();

getClassData().kwargsHashMethodsDefined.add(length);
classData.kwargsHashMethodsDefined.add(length);
}

// now call it
adapter.invokestatic(getClassData().clsName, "kwargsHash:" + length, incomingSig);
adapter.invokestatic(classData.clsName, methodName, incomingSig);
}

public void checkpoint() {
20 changes: 9 additions & 11 deletions core/src/main/java/org/jruby/runtime/backtrace/BacktraceData.java
Original file line number Diff line number Diff line change
@@ -34,13 +34,14 @@ public BacktraceData(StackTraceElement[] javaTrace, BacktraceElement[] rubyTrace
false,
false);

public RubyStackTraceElement[] getBacktrace(Ruby runtime) {
public final RubyStackTraceElement[] getBacktrace(Ruby runtime) {
if (backtraceElements == null) {
backtraceElements = constructBacktrace(runtime.getBoundMethods());
}
return backtraceElements;
}

@SuppressWarnings("unchecked")
public RubyStackTraceElement[] getBacktraceWithoutRuby() {
return constructBacktrace(Collections.EMPTY_MAP);
}
@@ -112,23 +113,23 @@ private RubyStackTraceElement[] constructBacktrace(Map<String, Map<String, Strin
}

// Interpreted frames
if ( rubyFrameIndex >= 0 && FrameType.isInterpreterFrame(className, methodName) ) {
final FrameType frameType;
if ( rubyFrameIndex >= 0 && (frameType = FrameType.getInterpreterFrame(className, methodName)) != null ) {

// pop interpreter frame
BacktraceElement rubyFrame = rubyTrace[rubyFrameIndex--];

FrameType frameType = FrameType.getInterpreterFrame(methodName);

// construct Ruby trace element
String newName = rubyFrame.method;
final String newName;
switch (frameType) {
case METHOD: newName = rubyFrame.method; break;
case BLOCK: newName = "block in " + rubyFrame.method; break;
case CLASS: newName = "<class:" + rubyFrame.method + ">"; break;
case MODULE: newName = "<module:" + rubyFrame.method + ">"; break;
case CLASS: newName = "<class:" + rubyFrame.method + '>'; break;
case MODULE: newName = "<module:" + rubyFrame.method + '>'; break;
case METACLASS: newName = "singleton class"; break;
case ROOT: newName = "<top>"; break;
case EVAL: newName = "<eval>"; break;
default: newName = rubyFrame.method;
}
RubyStackTraceElement rubyElement = new RubyStackTraceElement("RUBY", newName, rubyFrame.filename, rubyFrame.line + 1, false);

@@ -154,10 +155,7 @@ private RubyStackTraceElement[] constructBacktrace(Map<String, Map<String, Strin

public static String getBoundMethodName(Map<String,Map<String,String>> boundMethods, String className, String methodName) {
Map<String, String> javaToRuby = boundMethods.get(className);

if (javaToRuby == null) return null;

return javaToRuby.get(methodName);
return javaToRuby == null ? null : javaToRuby.get(methodName);
}

private static String packagedFilenameFromElement(final String filename, final String className) {
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

import org.jruby.lexer.yacc.ISourcePosition;

public class BacktraceElement {
public final class BacktraceElement implements Cloneable {

public static final BacktraceElement[] EMPTY_ARRAY = new BacktraceElement[0];

13 changes: 9 additions & 4 deletions core/src/main/java/org/jruby/runtime/backtrace/FrameType.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.jruby.runtime.backtrace;

import java.util.HashSet;
import java.util.Set;

import org.jruby.internal.runtime.methods.InterpretedIRBodyMethod;
import org.jruby.internal.runtime.methods.InterpretedIRMethod;
@@ -11,7 +10,7 @@
public enum FrameType {
METHOD, BLOCK, EVAL, CLASS, MODULE, METACLASS, ROOT;

private static final Set<String> INTERPRETED_CLASSES = new HashSet<String>(4, 1);
private static final HashSet<String> INTERPRETED_CLASSES = new HashSet<String>(6, 1);

static {
INTERPRETED_CLASSES.add(Interpreter.class.getName());
@@ -21,8 +20,7 @@ public enum FrameType {
}

public static boolean isInterpreterFrame(final String className, final String methodName) {
if ( ! INTERPRETED_CLASSES.contains(className) ) return false;
return getInterpreterFrame(methodName) != null;
return getInterpreterFrame(className, methodName) != null;
}

public static FrameType getInterpreterFrame(final String methodName) {
@@ -38,4 +36,11 @@ public static FrameType getInterpreterFrame(final String methodName) {
return null;
}

public static FrameType getInterpreterFrame(final String className, final String methodName) {
if ( INTERPRETED_CLASSES.contains(className) ) {
return getInterpreterFrame(methodName);
}
return null;
}

}
4 changes: 2 additions & 2 deletions tool/jruby_eclipse
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ TRUFFLEJARS = %W[
SNAKEYAMLJAR = "#{M2REPO}/org/yaml/snakeyaml/1.14/snakeyaml-1.14.jar"
ANTLR4JAR = "#{M2REPO}/org/antlr/antlr4-runtime/4.5/antlr4-runtime-4.5.jar"

GRAAL_OPTIONS_PREFIX = "jvmci.option."
GRAAL_OPTIONS_PREFIX = "graal."

JRUBY = File.expand_path('../..', __FILE__)

@@ -30,7 +30,7 @@ ARGV.each { |arg|
case arg
when /^-Xmx/, "-ea"
java_flags << arg
when /^-J-G:+/
when /^-J-G:\+/
java_flags << "-D#{GRAAL_OPTIONS_PREFIX}#{$'}=true"
when /^-J-G:-/
java_flags << "-D#{GRAAL_OPTIONS_PREFIX}#{$'}=false"
23 changes: 19 additions & 4 deletions tool/jt.rb
Original file line number Diff line number Diff line change
@@ -14,6 +14,8 @@
require 'fileutils'
require 'digest/sha1'

GRAALVM_VERSION = "0.10"

JRUBY_DIR = File.expand_path('../..', __FILE__)

JDEBUG_PORT = 51819
@@ -39,9 +41,9 @@ def self.find_graal
graal_locations = [
ENV['GRAAL_BIN'],
ENV["GRAAL_BIN_#{mangle_for_env(git_branch)}"],
"GraalVM-0.9/jre/bin/javao",
"../GraalVM-0.9/jre/bin/javao",
"../../GraalVM-0.9/jre/bin/javao",
"GraalVM-#{GRAALVM_VERSION}/jre/bin/javao",
"../GraalVM-#{GRAALVM_VERSION}/jre/bin/javao",
"../../GraalVM-#{GRAALVM_VERSION}/jre/bin/javao",
].compact.map { |path| File.expand_path(path, JRUBY_DIR) }

not_found = -> {
@@ -64,6 +66,19 @@ def self.jruby_eclipse?
ENV["JRUBY_ECLIPSE"] == "true" && Utilities.git_branch == "master"
end

def self.find_ruby
if ENV["RUBY_BIN"]
ENV["RUBY_BIN"]
else
version = `ruby -e 'print RUBY_VERSION' 2>/dev/null`
if version.start_with?("2.")
"ruby"
else
find_jruby
end
end
end

def self.find_jruby
if jruby_eclipse?
"#{JRUBY_DIR}/tool/jruby_eclipse"
@@ -220,7 +235,7 @@ def mspec(command, *args)
args.unshift "-ttool/jruby_eclipse"
end

sh env_vars, Utilities.find_jruby, 'spec/mspec/bin/mspec', command, '--config', 'spec/truffle/truffle.mspec', *args
sh env_vars, Utilities.find_ruby, 'spec/mspec/bin/mspec', command, '--config', 'spec/truffle/truffle.mspec', *args
end
end

Original file line number Diff line number Diff line change
@@ -16,7 +16,6 @@
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.cast.BooleanCastNode;
import org.jruby.truffle.core.cast.BooleanCastNodeGen;
import org.jruby.truffle.language.methods.DeclarationContext;
import org.jruby.truffle.language.yield.YieldNode;

public abstract class YieldingCoreMethodNode extends CoreMethodArrayArgumentsNode {
Original file line number Diff line number Diff line change
@@ -169,7 +169,7 @@ public DynamicObject appendManyLongIntoInteger(DynamicObject array, int otherSiz
final int newSize = oldSize + otherSize;

final int[] oldStore = (int[]) Layouts.ARRAY.getStore(array);
long[] newStore = ArrayUtils.longCopyOf(oldStore, ArrayUtils.capacity(oldStore.length, newSize));
long[] newStore = ArrayUtils.longCopyOf(oldStore, newSize);

System.arraycopy(other, 0, newStore, oldSize, otherSize);

@@ -232,7 +232,7 @@ public DynamicObject appendManyGeneralizeDoubleObject(DynamicObject array, int o
public void appendManyGeneralizeGeneric(DynamicObject array, ArrayMirror storeMirror, int otherSize, ArrayMirror otherStoreMirror) {
final int oldSize = Layouts.ARRAY.getSize(array);
final int newSize = oldSize + otherSize;
Object[] newStore = storeMirror.getBoxedCopy(ArrayUtils.capacity(storeMirror.getLength(), newSize));
Object[] newStore = storeMirror.getBoxedCopy(newSize);
otherStoreMirror.copyTo(newStore, 0, oldSize, otherSize);
Layouts.ARRAY.setStore(array, newStore);
Layouts.ARRAY.setSize(array, newSize);
Original file line number Diff line number Diff line change
@@ -27,6 +27,7 @@
import com.oracle.truffle.api.frame.FrameSlot;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.Node.Child;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jcodings.Encoding;
@@ -62,10 +63,11 @@
import org.jruby.truffle.language.control.RaiseException;
import org.jruby.truffle.language.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.language.dispatch.DispatchHeadNodeFactory;
import org.jruby.truffle.language.objects.AllocateObjectNode;
import org.jruby.truffle.language.objects.AllocateObjectNodeGen;
import org.jruby.util.ByteList;
import org.jruby.util.RegexpOptions;
import org.jruby.util.RegexpSupport;

import java.nio.charset.StandardCharsets;
import java.util.Iterator;

@@ -605,13 +607,16 @@ public static boolean anyNames(DynamicObject regexp) {
@CoreMethod(names = "allocate", constructor = true)
public abstract static class AllocateNode extends CoreMethodArrayArgumentsNode {

@Child private AllocateObjectNode allocateNode;

public AllocateNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
allocateNode = AllocateObjectNodeGen.create(context, sourceSection, null, null);
}

@Specialization
public DynamicObject allocate(DynamicObject rubyClass) {
return Layouts.REGEXP.createRegexp(Layouts.CLASS.getInstanceFactory(rubyClass), null, null, RegexpOptions.NULL_OPTIONS, null);
return allocateNode.allocate(rubyClass, null, null, RegexpOptions.NULL_OPTIONS, null);
}

}
Original file line number Diff line number Diff line change
@@ -47,21 +47,25 @@
import org.jruby.truffle.core.Layouts;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.language.control.RaiseException;

import org.jruby.truffle.language.objects.AllocateObjectNode;
import org.jruby.truffle.language.objects.AllocateObjectNodeGen;
import java.io.File;

public abstract class DirPrimitiveNodes {

@RubiniusPrimitive(name = "dir_allocate")
public static abstract class DirAllocatePrimitiveNode extends RubiniusPrimitiveArrayArgumentsNode {

@Child private AllocateObjectNode allocateNode;

public DirAllocatePrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
allocateNode = AllocateObjectNodeGen.create(context, sourceSection, null, null);
}

@Specialization
public DynamicObject allocate(DynamicObject dirClass) {
return Layouts.DIR.createDir(Layouts.CLASS.getInstanceFactory(dirClass), null, 0);
return allocateNode.allocate(dirClass, null, 0);
}

}
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@
package org.jruby.truffle.core.rubinius;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.Frame;
import com.oracle.truffle.api.frame.FrameInstance;
import com.oracle.truffle.api.frame.FrameSlot;
import com.oracle.truffle.api.frame.FrameSlotTypeException;
@@ -33,7 +34,7 @@ public Object execute(VirtualFrame frame) {

// Rubinius expects $_ to be thread-local, rather than frame-local. If we see it in a method call, we need
// to look to the caller's frame to get the correct value, otherwise it will be nil.
final MaterializedFrame callerFrame = getContext().getCallStack().getCallerFrameIgnoringSend().getFrame(FrameInstance.FrameAccess.READ_ONLY, true).materialize();
final Frame callerFrame = getContext().getCallStack().getCallerFrameIgnoringSend().getFrame(FrameInstance.FrameAccess.READ_ONLY, true);

// TODO CS 4-Jan-16 - but it could be in higher frames!
final FrameSlot slot = callerFrame.getFrameDescriptor().findFrameSlot("$_");
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.Frame;
import com.oracle.truffle.api.frame.FrameInstance;
import com.oracle.truffle.api.frame.FrameSlot;
import com.oracle.truffle.api.frame.FrameSlotTypeException;
@@ -36,7 +37,7 @@ public Object lastStringWrite(Object value) {

// Rubinius expects $_ to be thread-local, rather than frame-local. If we see it in a method call, we need
// to look to the caller's frame to get the correct value, otherwise it will be nil.
MaterializedFrame callerFrame = getContext().getCallStack().getCallerFrameIgnoringSend().getFrame(FrameInstance.FrameAccess.READ_ONLY, true).materialize();
Frame callerFrame = getContext().getCallStack().getCallerFrameIgnoringSend().getFrame(FrameInstance.FrameAccess.READ_WRITE, true);

FrameSlot slot = callerFrame.getFrameDescriptor().findFrameSlot("$_");

Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@
import org.jruby.truffle.language.SafepointAction;
import org.jruby.truffle.language.backtrace.Backtrace;
import org.jruby.truffle.language.control.RaiseException;

import static org.jruby.RubyThread.RUBY_MAX_THREAD_PRIORITY;
import static org.jruby.RubyThread.RUBY_MIN_THREAD_PRIORITY;
import static org.jruby.RubyThread.javaPriorityToRubyPriority;
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@
import org.jruby.truffle.language.SafepointManager;
import org.jruby.truffle.language.backtrace.BacktraceFormatter;
import org.jruby.truffle.language.control.RaiseException;

import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
Original file line number Diff line number Diff line change
@@ -39,6 +39,7 @@
import org.jruby.truffle.language.control.RaiseException;
import org.jruby.truffle.language.control.ReturnException;
import org.jruby.truffle.language.control.ThreadExitException;

import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.InterruptMode;
import org.jruby.truffle.core.Layouts;

import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.RepeatingNode;
import com.oracle.truffle.api.profiles.BranchProfile;
import com.oracle.truffle.api.profiles.LoopConditionProfile;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.cast.BooleanCastNode;
@@ -53,6 +54,7 @@ private static abstract class WhileRepeatingBaseNode extends Node implements Rep
@Child protected BooleanCastNode condition;
@Child protected RubyNode body;

protected final LoopConditionProfile conditionProfile = LoopConditionProfile.createCountingProfile();
protected final BranchProfile redoUsed = BranchProfile.create();
protected final BranchProfile nextUsed = BranchProfile.create();

@@ -77,7 +79,7 @@ public WhileRepeatingNode(RubyContext context, RubyNode condition, RubyNode body

@Override
public boolean executeRepeating(VirtualFrame frame) {
if (!condition.executeBoolean(frame)) {
if (!conditionProfile.profile(condition.executeBoolean(frame))) {
return false;
}

@@ -117,7 +119,7 @@ public boolean executeRepeating(VirtualFrame frame) {
return true;
}

return condition.executeBoolean(frame);
return conditionProfile.profile(condition.executeBoolean(frame));
}

}
Original file line number Diff line number Diff line change
@@ -14,10 +14,6 @@
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.RubyNode;

/**
* Switches execution to the parallel {@link RubyNode#isDefined} semantic path. Represents the
* {@code defined?} keyword in Ruby.
*/
public class DefinedNode extends RubyNode {

@Child private RubyNode child;
Original file line number Diff line number Diff line change
@@ -11,21 +11,21 @@

import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.jcodings.specific.UTF8Encoding;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.core.string.CoreString;
import org.jruby.truffle.language.RubyNode;

public class DefinedWrapperNode extends RubyNode {

@Child private RubyNode child;
private final CoreString definition;

private final String definition;
@Child private RubyNode child;

public DefinedWrapperNode(RubyContext context, SourceSection sourceSection, RubyNode child, String definition) {
public DefinedWrapperNode(RubyContext context, SourceSection sourceSection,
CoreString definition, RubyNode child) {
super(context, sourceSection);
this.child = child;
this.definition = definition;
this.child = child;
}

@Override
@@ -35,7 +35,7 @@ public Object execute(VirtualFrame frame) {

@Override
public Object isDefined(VirtualFrame frame) {
return createString(StringOperations.encodeRope(definition, UTF8Encoding.INSTANCE));
return definition.createInstance();
}

}
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@ public class DisablingBacktracesNode extends RubyNode {
protected Boolean initialValue() {
return false;
}

};

public DisablingBacktracesNode(RubyContext context, SourceSection sourceSection, RubyNode child) {
@@ -37,7 +38,6 @@ public Object execute(VirtualFrame frame) {

try {
areBacktracesDisabledThreadLocal.set(true);

return child.execute(frame);
} finally {
areBacktracesDisabledThreadLocal.set(backtracesPreviouslyDisabled);
Original file line number Diff line number Diff line change
@@ -9,23 +9,21 @@
*/
package org.jruby.truffle.language.exceptions;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.profiles.BranchProfile;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.Layouts;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.control.RaiseException;

/**
* Represents an ensure clause in exception handling. Represented separately to the try part.
*/
public class EnsureNode extends RubyNode {

@Child private RubyNode tryPart;
@Child private RubyNode ensurePart;

@Child private SetExceptionVariableNode setExceptionVariableNode;

private final BranchProfile rubyExceptionPath = BranchProfile.create();
private final BranchProfile javaExceptionPath = BranchProfile.create();

@@ -38,18 +36,21 @@ public EnsureNode(RubyContext context, SourceSection sourceSection, RubyNode try
@Override
public Object execute(VirtualFrame frame) {
final Object value;

try {
value = tryPart.execute(frame);
} catch (RaiseException exception) {
rubyExceptionPath.enter();
throw setLastExceptionAndRunEnsure(frame, exception);
setLastExceptionAndRunEnsure(frame, exception);
throw exception;
} catch (Throwable throwable) {
javaExceptionPath.enter();
ensurePart.executeVoid(frame);
throw throwable;
}

ensurePart.executeVoid(frame);

return value;
}

@@ -59,7 +60,8 @@ public void executeVoid(VirtualFrame frame) {
tryPart.executeVoid(frame);
} catch (RaiseException exception) {
rubyExceptionPath.enter();
throw setLastExceptionAndRunEnsure(frame, exception);
setLastExceptionAndRunEnsure(frame, exception);
throw exception;
} catch (Throwable throwable) {
javaExceptionPath.enter();
ensurePart.executeVoid(frame);
@@ -69,17 +71,13 @@ public void executeVoid(VirtualFrame frame) {
ensurePart.executeVoid(frame);
}

private RaiseException setLastExceptionAndRunEnsure(VirtualFrame frame, RaiseException exception) {
final DynamicObject threadLocals = Layouts.THREAD.getThreadLocals(getContext().getThreadManager().getCurrentThread());

final Object lastException = threadLocals.get("$!", nil());
threadLocals.set("$!", exception.getException());
try {
ensurePart.executeVoid(frame);
return exception;
} finally {
threadLocals.set("$!", lastException);
private void setLastExceptionAndRunEnsure(VirtualFrame frame, RaiseException exception) {
if (setExceptionVariableNode == null) {
CompilerDirectives.transferToInterpreter();
setExceptionVariableNode = insert(new SetExceptionVariableNode(getContext()));
}

setExceptionVariableNode.setLastExceptionAndRun(frame, exception, ensurePart);
}

}
Original file line number Diff line number Diff line change
@@ -14,24 +14,16 @@
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.objects.IsANode;
import org.jruby.truffle.language.objects.IsANodeGen;

/**
* Rescues any exception where {@code $!.is_a?(StandardError)}.
*/
public class RescueAnyNode extends RescueNode {

@Child private IsANode isANode;

public RescueAnyNode(RubyContext context, SourceSection sourceSection, RubyNode body) {
super(context, sourceSection, body);
isANode = IsANodeGen.create(context, sourceSection, null, null);
}

@Override
public boolean canHandle(VirtualFrame frame, DynamicObject exception) {
return isANode.executeIsA(exception, coreLibrary().getStandardErrorClass());
return getIsANode().executeIsA(exception, coreLibrary().getStandardErrorClass());
}

}
Original file line number Diff line number Diff line change
@@ -9,43 +9,35 @@
*/
package org.jruby.truffle.language.exceptions;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.Layouts;
import org.jruby.truffle.core.module.ModuleOperations;
import org.jruby.truffle.language.RubyNode;

/**
* Rescues any of a set of classes.
*/
public class RescueClassesNode extends RescueNode {

@Children final RubyNode[] handlingClassNodes;

public RescueClassesNode(RubyContext context, SourceSection sourceSection, RubyNode[] handlingClassNodes, RubyNode body) {
public RescueClassesNode(RubyContext context, SourceSection sourceSection,
RubyNode[] handlingClassNodes, RubyNode body) {
super(context, sourceSection, body);
this.handlingClassNodes = handlingClassNodes;
}

@ExplodeLoop
@Override
public boolean canHandle(VirtualFrame frame, DynamicObject exception) {
CompilerDirectives.transferToInterpreter();

final DynamicObject exceptionRubyClass = Layouts.BASIC_OBJECT.getLogicalClass(exception);

for (RubyNode handlingClassNode : handlingClassNodes) {
// TODO(CS): what if we don't get a class?

final DynamicObject handlingClass = (DynamicObject) handlingClassNode.execute(frame);

if (ModuleOperations.assignableTo(exceptionRubyClass, handlingClass)) {
if (getIsANode().executeIsA(exception, handlingClass)) {
return true;
}
}

return false;
}

}
Original file line number Diff line number Diff line change
@@ -9,20 +9,21 @@
*/
package org.jruby.truffle.language.exceptions;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.objects.IsANode;
import org.jruby.truffle.language.objects.IsANodeGen;

/**
* Base node for all nodes which may be able to rescue an exception. They have a test method
* {@link #canHandle} and a body to execute if that test passes.
*/
public abstract class RescueNode extends RubyNode {

@Child private RubyNode body;

@Child private IsANode isANode;

public RescueNode(RubyContext context, SourceSection sourceSection, RubyNode body) {
super(context, sourceSection);
this.body = body;
@@ -40,4 +41,13 @@ public void executeVoid(VirtualFrame frame) {
body.executeVoid(frame);
}

protected IsANode getIsANode() {
if (isANode == null) {
CompilerDirectives.transferToInterpreter();
isANode = insert(IsANodeGen.create(getContext(), getSourceSection(), null, null));
}

return isANode;
}

}
Original file line number Diff line number Diff line change
@@ -9,24 +9,16 @@
*/
package org.jruby.truffle.language.exceptions;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.Layouts;
import org.jruby.truffle.core.array.ArrayOperations;
import org.jruby.truffle.core.module.ModuleOperations;
import org.jruby.truffle.language.RubyNode;

/**
* Rescue any of several classes, that we get from an expression that evaluates to an array of
* classes.
*
*/
public class RescueSplatNode extends RescueNode {

@Child RubyNode handlingClassesArray;
@Child private RubyNode handlingClassesArray;

public RescueSplatNode(RubyContext context, SourceSection sourceSection, RubyNode handlingClassesArray, RubyNode body) {
super(context, sourceSection, body);
@@ -35,14 +27,10 @@ public RescueSplatNode(RubyContext context, SourceSection sourceSection, RubyNod

@Override
public boolean canHandle(VirtualFrame frame, DynamicObject exception) {
CompilerDirectives.transferToInterpreter();

final DynamicObject handlingClasses = (DynamicObject) handlingClassesArray.execute(frame);

final DynamicObject exceptionRubyClass = Layouts.BASIC_OBJECT.getLogicalClass(exception);

for (Object handlingClass : ArrayOperations.toIterable(handlingClasses)) {
if (ModuleOperations.assignableTo(exceptionRubyClass, (DynamicObject) handlingClass)) {
if (getIsANode().executeIsA(exception, (DynamicObject) handlingClass)) {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2013, 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
*/
package org.jruby.truffle.language.exceptions;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.DynamicObject;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.control.RaiseException;
import org.jruby.truffle.language.objects.ReadObjectFieldNode;
import org.jruby.truffle.language.objects.ReadObjectFieldNodeGen;
import org.jruby.truffle.language.objects.ThreadLocalObjectNode;
import org.jruby.truffle.language.objects.ThreadLocalObjectNodeGen;
import org.jruby.truffle.language.objects.WriteObjectFieldNode;
import org.jruby.truffle.language.objects.WriteObjectFieldNodeGen;

public class SetExceptionVariableNode extends Node {

private final RubyContext context;

@Child private ThreadLocalObjectNode threadLocalNode;
@Child private ReadObjectFieldNode readDollarBang;
@Child private WriteObjectFieldNode writeDollarBang;

public SetExceptionVariableNode(RubyContext context) {
this.context = context;
}

public Object setLastExceptionAndRun(VirtualFrame frame, RaiseException exception, RubyNode node) {
final DynamicObject threadLocals = getThreadLocalsObject(frame);

final Object lastException = readDollarBang(threadLocals);
writeDollarBang(threadLocals, exception.getException());

try {
return node.execute(frame);
} finally {
writeDollarBang(threadLocals, lastException);
}
}

private DynamicObject getThreadLocalsObject(VirtualFrame frame) {
if (threadLocalNode == null) {
CompilerDirectives.transferToInterpreter();
threadLocalNode = insert(ThreadLocalObjectNodeGen.create(context, getEncapsulatingSourceSection()));
}

return threadLocalNode.executeDynamicObject(frame);
}

private void writeDollarBang(DynamicObject threadLocals, Object value) {
if (writeDollarBang == null) {
CompilerDirectives.transferToInterpreter();
writeDollarBang = insert(WriteObjectFieldNodeGen.create(context, "$!"));
}

writeDollarBang.execute(threadLocals, value);
}

private Object readDollarBang(DynamicObject threadLocals) {
if (readDollarBang == null) {
CompilerDirectives.transferToInterpreter();
readDollarBang = insert(ReadObjectFieldNodeGen.create(context, "$!",
context.getCoreLibrary().getNilObject()));
}

return readDollarBang.execute(threadLocals);
}

}
Original file line number Diff line number Diff line change
@@ -9,29 +9,26 @@
*/
package org.jruby.truffle.language.exceptions;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.ControlFlowException;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.profiles.BranchProfile;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.Layouts;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.control.RaiseException;
import org.jruby.truffle.language.control.RetryException;
import org.jruby.truffle.language.methods.ExceptionTranslatingNode;

/**
* Represents a block of code run with exception handlers. There's no {@code try} keyword in Ruby -
* it's implicit - but it's similar to a try statement in any other language.
*/
public class TryNode extends RubyNode {

@Child private ExceptionTranslatingNode tryPart;
@Children final RescueNode[] rescueParts;
@Children private final RescueNode[] rescueParts;
@Child private RubyNode elsePart;

@Child private SetExceptionVariableNode setExceptionVariableNode;

private final BranchProfile elseProfile = BranchProfile.create();
private final BranchProfile controlFlowProfile = BranchProfile.create();
private final BranchProfile raiseExceptionProfile = BranchProfile.create();
@@ -82,20 +79,16 @@ private Object handleException(VirtualFrame frame, RaiseException exception) {
}
}

// Not handled by any of the rescue
throw exception;
}

private Object setLastExceptionAndRunRescue(VirtualFrame frame, RaiseException exception, RescueNode rescue) {
final DynamicObject threadLocals = Layouts.THREAD.getThreadLocals(getContext().getThreadManager().getCurrentThread());

final Object lastException = threadLocals.get("$!", nil());
threadLocals.set("$!", exception.getException());
try {
return rescue.execute(frame);
} finally {
threadLocals.set("$!", lastException);
private Object setLastExceptionAndRunRescue(VirtualFrame frame, RaiseException exception, RubyNode rescue) {
if (setExceptionVariableNode == null) {
CompilerDirectives.transferToInterpreter();
setExceptionVariableNode = insert(new SetExceptionVariableNode(getContext()));
}

return setExceptionVariableNode.setLastExceptionAndRun(frame, exception, rescue);
}

}
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@
import org.jruby.truffle.core.hash.Entry;
import org.jruby.truffle.language.SafepointAction;
import org.jruby.truffle.language.arguments.RubyArguments;

import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
Original file line number Diff line number Diff line change
@@ -2427,7 +2427,7 @@ public RubyNode visitMultipleAsgnNode(org.jruby.ast.MultipleAsgnNode node) {
result = nilNode(sourceSection);
}

final RubyNode ret = new DefinedWrapperNode(context, sourceSection, result, "assignment");
final RubyNode ret = new DefinedWrapperNode(context, sourceSection, context.getCoreStrings().ASSIGNMENT, result);
return addNewlineIfNeeded(node, ret);
}

@@ -2494,7 +2494,7 @@ public RubyNode visitOpAsgnAndNode(org.jruby.ast.OpAsgnAndNode node) {
final org.jruby.ast.Node lhs = node.getFirstNode();
final org.jruby.ast.Node rhs = node.getSecondNode();

final RubyNode ret = new DefinedWrapperNode(context, sourceSection, new AndNode(context, sourceSection, lhs.accept(this), rhs.accept(this)), "assignment");
final RubyNode ret = new DefinedWrapperNode(context, sourceSection, context.getCoreStrings().ASSIGNMENT, new AndNode(context, sourceSection, lhs.accept(this), rhs.accept(this)));
return addNewlineIfNeeded(node, ret);
}

@@ -2516,9 +2516,8 @@ public RubyNode visitOpAsgnNode(org.jruby.ast.OpAsgnNode node) {
RubyNode lhs = readMethod.accept(this);
RubyNode rhs = writeMethod.accept(this);

final RubyNode ret = new DefinedWrapperNode(context, sourceSection,
sequence(context, sourceSection, Arrays.asList(writeReceiverToTemp.accept(this), new OrNode(context, sourceSection, lhs, rhs))),
"assignment");
final RubyNode ret = new DefinedWrapperNode(context, sourceSection, context.getCoreStrings().ASSIGNMENT,
sequence(context, sourceSection, Arrays.asList(writeReceiverToTemp.accept(this), new OrNode(context, sourceSection, lhs, rhs))));

return addNewlineIfNeeded(node, ret);
}
@@ -2567,9 +2566,8 @@ public RubyNode visitOpAsgnOrNode(org.jruby.ast.OpAsgnOrNode node) {
lhs = new AndNode(context, lhs.getSourceSection(), defined, lhs);
}

final RubyNode ret = new DefinedWrapperNode(context, sourceSection,
new OrNode(context, sourceSection, lhs, rhs),
"assignment");
final RubyNode ret = new DefinedWrapperNode(context, sourceSection, context.getCoreStrings().ASSIGNMENT,
new OrNode(context, sourceSection, lhs, rhs));

return addNewlineIfNeeded(node, ret);
}
Original file line number Diff line number Diff line change
@@ -16,7 +16,6 @@
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.profiles.BranchProfile;
import com.oracle.truffle.api.source.SourceSection;
import org.jcodings.specific.UTF8Encoding;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.array.ArrayOperations;
import org.jruby.truffle.language.RubyGuards;
Original file line number Diff line number Diff line change
@@ -15,13 +15,12 @@
import com.oracle.truffle.api.object.DynamicObject;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.Layouts;
import org.jruby.truffle.language.RubyGuards;
import org.jruby.truffle.language.methods.DeclarationContext;

public class YieldNode extends Node {

private RubyContext context;
private DeclarationContext declarationContext;
private final RubyContext context;
private final DeclarationContext declarationContext;

@Child private CallBlockNode callBlockNode;

Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@
import org.jruby.truffle.language.SafepointAction;
import org.jruby.truffle.language.backtrace.Backtrace;
import org.jruby.truffle.language.backtrace.BacktraceFormatter;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;