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: bf6c11f3900c
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 8466f7a1f8e2
Choose a head ref

Commits on Oct 13, 2015

  1. Copy the full SHA
    e9ecbb4 View commit details
  2. Copy the full SHA
    fd1a5f5 View commit details
  3. Copy the full SHA
    d83c57a View commit details
  4. [Truffle] Calling a private method with insufficient rights should de…

    …legate to #method_missing.
    eregon committed Oct 13, 2015
    Copy the full SHA
    3aa50dc View commit details
  5. [Truffle] Fixed a performance issue when adding two Strings by preser…

    …ving a negotiated code range.
    nirvdrum committed Oct 13, 2015
    Copy the full SHA
    c3ad290 View commit details
  6. Copy the full SHA
    b546429 View commit details
  7. Copy the full SHA
    256c8ce View commit details
  8. Copy the full SHA
    1e9936b View commit details
  9. [Truffle] Correct handling of at_exit, exit and abort.

    * Do not close stderr when printing a backtrace!
    * Move #abort to ruby code.
    * TruffleContextInterface.execute() will execute at_exit handlers
      since it is fully part of the execution. If a hard exit is not desired,
      we can pass a parameter or so to just return the exit status.
    * Properly split running at_exit and actual shutdown.
    * Fix Thread#kill on the main thread.
    eregon committed Oct 13, 2015
    Copy the full SHA
    ed8e127 View commit details
  10. Copy the full SHA
    e1732d1 View commit details
  11. Copy the full SHA
    0ff4930 View commit details
  12. Copy the full SHA
    ccb14cc View commit details
  13. Copy the full SHA
    f313270 View commit details
  14. Copy the full SHA
    991a4a5 View commit details
  15. Copy the full SHA
    9e7b589 View commit details
  16. 4
    Copy the full SHA
    6a52113 View commit details
  17. [Truffle] Findbugs.

    chrisseaton committed Oct 13, 2015
    Copy the full SHA
    ea61f78 View commit details
  18. Copy the full SHA
    c15f99b View commit details
  19. [Truffle] Removed boundary for string_substring primitive.

    This primitive is used by String#[] amongst others.
    nirvdrum committed Oct 13, 2015
    3
    Copy the full SHA
    09ecd35 View commit details
  20. Copy the full SHA
    8d893fc View commit details
  21. Copy the full SHA
    060f5f3 View commit details
  22. Copy the full SHA
    f2683ee View commit details
  23. Copy the full SHA
    2a68822 View commit details
  24. [Truffle] Fixed an issue I introduced whereby we weren't properly car…

    …rying over the encoding on substrings.
    nirvdrum committed Oct 13, 2015
    Copy the full SHA
    c437aec View commit details
  25. Merge remote-tracking branch 'origin/master' into truffle-head

    Conflicts:
    	core/src/main/java/org/jruby/Ruby.java
    	truffle/src/main/java/org/jruby/truffle/runtime/RubyContext.java
    nirvdrum committed Oct 13, 2015
    Copy the full SHA
    8466f7a View commit details
Showing with 496 additions and 275 deletions.
  1. +0 −2 core/src/main/java/org/jruby/Main.java
  2. +4 −2 core/src/main/java/org/jruby/RubyModule.java
  3. +4 −0 core/src/main/java/org/jruby/internal/runtime/methods/ProcMethod.java
  4. +1 −1 core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java
  5. +4 −10 core/src/main/java/org/jruby/util/cli/ArgumentProcessor.java
  6. +8 −0 spec/ruby/core/module/fixtures/classes.rb
  7. +6 −0 spec/ruby/core/module/prepend_spec.rb
  8. +0 −4 spec/tags/ruby/core/module/const_defined_tags.txt
  9. +0 −6 spec/truffle/tags/core/basicobject/method_missing_tags.txt
  10. +0 −12 spec/truffle/tags/core/kernel/abort_tags.txt
  11. +0 −4 spec/truffle/tags/core/kernel/at_exit_tags.txt
  12. +0 −2 spec/truffle/tags/core/kernel/raise_tags.txt
  13. +0 −6 spec/truffle/tags/core/string/modulo_tags.txt
  14. +1 −0 tool/truffle/jruby_truffle_runner/gem_configurations/activesupport.yaml
  15. +0 −1 truffle/src/main/java/org/jruby/truffle/Main.java
  16. +51 −0 truffle/src/main/java/org/jruby/truffle/format/nodes/read/ReadHashValueNode.java
  17. +1 −1 truffle/src/main/java/org/jruby/truffle/format/nodes/read/ReadStringNode.java
  18. +6 −1 truffle/src/main/java/org/jruby/truffle/format/parser/FormatDirective.java
  19. +33 −8 truffle/src/main/java/org/jruby/truffle/format/parser/FormatParser.java
  20. +50 −28 truffle/src/main/java/org/jruby/truffle/format/parser/FormatTokenizer.java
  21. +23 −20 truffle/src/main/java/org/jruby/truffle/nodes/core/BasicObjectNodes.java
  22. +16 −0 truffle/src/main/java/org/jruby/truffle/nodes/core/BignumNodes.java
  23. +1 −1 truffle/src/main/java/org/jruby/truffle/nodes/core/BindingNodes.java
  24. +16 −0 truffle/src/main/java/org/jruby/truffle/nodes/core/EncodingNodes.java
  25. +0 −26 truffle/src/main/java/org/jruby/truffle/nodes/core/KernelNodes.java
  26. +18 −0 truffle/src/main/java/org/jruby/truffle/nodes/core/MatchDataNodes.java
  27. +16 −0 truffle/src/main/java/org/jruby/truffle/nodes/core/MethodNodes.java
  28. +3 −3 truffle/src/main/java/org/jruby/truffle/nodes/core/ModuleNodes.java
  29. +1 −1 truffle/src/main/java/org/jruby/truffle/nodes/core/ProcNodes.java
  30. +1 −1 truffle/src/main/java/org/jruby/truffle/nodes/core/StringGuards.java
  31. +3 −2 truffle/src/main/java/org/jruby/truffle/nodes/core/StringNodes.java
  32. +17 −0 truffle/src/main/java/org/jruby/truffle/nodes/core/SymbolNodes.java
  33. +9 −3 truffle/src/main/java/org/jruby/truffle/nodes/core/ThreadNodes.java
  34. +16 −0 truffle/src/main/java/org/jruby/truffle/nodes/core/UnboundMethodNodes.java
  35. +3 −14 truffle/src/main/java/org/jruby/truffle/nodes/dispatch/DispatchNode.java
  36. +0 −2 truffle/src/main/java/org/jruby/truffle/nodes/dispatch/UnresolvedDispatchNode.java
  37. +21 −20 truffle/src/main/java/org/jruby/truffle/nodes/exceptions/TopLevelRaiseHandler.java
  38. +18 −0 truffle/src/main/java/org/jruby/truffle/nodes/rubinius/ByteArrayNodes.java
  39. +18 −6 truffle/src/main/java/org/jruby/truffle/nodes/rubinius/StringPrimitiveNodes.java
  40. +1 −2 truffle/src/main/java/org/jruby/truffle/nodes/rubinius/VMPrimitiveNodes.java
  41. +18 −18 truffle/src/main/java/org/jruby/truffle/runtime/RubyContext.java
  42. +1 −3 truffle/src/main/java/org/jruby/truffle/runtime/backtrace/BacktraceFormatter.java
  43. +53 −44 truffle/src/main/java/org/jruby/truffle/runtime/core/CoreLibrary.java
  44. +17 −1 truffle/src/main/java/org/jruby/truffle/runtime/core/StringOperations.java
  45. +28 −18 truffle/src/main/java/org/jruby/truffle/runtime/subsystems/AtExitManager.java
  46. +1 −1 truffle/src/main/java/org/jruby/truffle/runtime/subsystems/ThreadManager.java
  47. +3 −0 truffle/src/main/ruby/core/float.rb
  48. +5 −1 truffle/src/main/ruby/core/string.rb
2 changes: 0 additions & 2 deletions core/src/main/java/org/jruby/Main.java
Original file line number Diff line number Diff line change
@@ -406,8 +406,6 @@ private Status doRunFromMain(Ruby runtime, InputStream in, String filename) {
doCheckSecurityManager();

runtime.runFromMain(in, filename);

runtime.shutdownTruffleContextIfRunning();
} catch (RaiseException rj) {
return new Status(handleRaiseException(rj));
}
6 changes: 4 additions & 2 deletions core/src/main/java/org/jruby/RubyModule.java
Original file line number Diff line number Diff line change
@@ -3063,8 +3063,10 @@ public RubyBoolean const_defined_p19(ThreadContext context, IRubyObject[] args)
if (segment.length() == 0) throw context.runtime.newNameError("wrong constant name " + fullName, symbol);
symbol = symbol.substring(sep + 2);
IRubyObject obj = mod.getConstantNoConstMissing(validateConstant(segment, args[0]), inherit, inherit);
if(obj instanceof RubyModule) {
mod = (RubyModule)obj;
if (obj instanceof RubyModule) {
mod = (RubyModule) obj;
} else if (obj == null) {
return runtime.getFalse();
} else {
throw runtime.newTypeError(segment + " does not refer to class/module");
}
Original file line number Diff line number Diff line change
@@ -96,4 +96,8 @@ public Signature getSignature() {
public ArgumentDescriptor[] getArgumentDescriptors() {
return proc.getBlock().getBody().getArgumentDescriptors();
}

public RubyProc getProc() {
return proc;
}
}
Original file line number Diff line number Diff line change
@@ -912,7 +912,7 @@ public static IRubyObject classSuperSplatArgs(ThreadContext context, IRubyObject

@Interp
public static IRubyObject classSuper(ThreadContext context, IRubyObject self, String methodName, RubyModule definingModule, IRubyObject[] args, Block block) {
RubyClass superClass = definingModule.getMetaClass().getSuperClass();
RubyClass superClass = definingModule.getMetaClass().getMethodLocation().getSuperClass();
DynamicMethod method = superClass != null ? superClass.searchMethod(methodName) : UndefinedMethod.INSTANCE;
IRubyObject rVal = method.isUndefined() ? Helpers.callMethodMissing(context, self, method.getVisibility(), methodName, CallType.SUPER, args, block)
: method.call(context, self, superClass, methodName, args, block);
14 changes: 4 additions & 10 deletions core/src/main/java/org/jruby/util/cli/ArgumentProcessor.java
Original file line number Diff line number Diff line change
@@ -45,6 +45,7 @@
import java.util.List;
import java.util.Set;
import java.util.HashSet;
import java.util.regex.Pattern;

/**
* Encapsulated logic for processing JRuby's command-line arguments.
@@ -78,6 +79,8 @@ public String toString() {
private boolean endOfArguments = false;
private int characterIndex = 0;

private static final Pattern VERSION_FLAG = Pattern.compile("^--[12]\\.[89012]$");

public ArgumentProcessor(String[] arguments, RubyInstanceConfig config) {
this(arguments, true, false, false, config);
}
@@ -482,18 +485,9 @@ private void processArgument() {
}

break FOR;
} else if (argument.equals("--1.8")) {
config.getError().println("warning: " + argument + " ignored");
break FOR;
} else if (argument.equals("--1.9")) {
} else if (VERSION_FLAG.matcher(argument).matches()) {
config.getError().println("warning: " + argument + " ignored");
break FOR;
} else if (argument.equals("--2.0")) {
config.getError().println("warning: " + argument + " ignored");
break FOR;
} else if (argument.equals("--2.1")) {
// keep the switch for consistency
break FOR;
} else if (argument.equals("--disable-gems")) {
config.setDisableGems(true);
break FOR;
8 changes: 8 additions & 0 deletions spec/ruby/core/module/fixtures/classes.rb
Original file line number Diff line number Diff line change
@@ -504,6 +504,14 @@ def self.get_constant_from_scope_with_send(method)
send(method, "Lookup")
end
end

class SuperInClassMethodWithPrepend
def self.inherited(base)
super
end
end

SuperInClassMethodWithPrepend.singleton_class.prepend(Module.new)
end

class Object
6 changes: 6 additions & 0 deletions spec/ruby/core/module/prepend_spec.rb
Original file line number Diff line number Diff line change
@@ -287,4 +287,10 @@ class ModuleSpecs::PrependSuperInSingletonClass
end
end.should_not raise_error
end

it "supports super when the module is prepended into a singleton class with a class super" do
lambda do
Class.new(ModuleSpecs::SuperInClassMethodWithPrepend)
end.should_not raise_error
end
end
4 changes: 0 additions & 4 deletions spec/tags/ruby/core/module/const_defined_tags.txt

This file was deleted.

6 changes: 0 additions & 6 deletions spec/truffle/tags/core/basicobject/method_missing_tags.txt

This file was deleted.

12 changes: 0 additions & 12 deletions spec/truffle/tags/core/kernel/abort_tags.txt

This file was deleted.

4 changes: 0 additions & 4 deletions spec/truffle/tags/core/kernel/at_exit_tags.txt
Original file line number Diff line number Diff line change
@@ -2,7 +2,3 @@ slow:Kernel.at_exit runs after all other code
slow:Kernel.at_exit runs in reverse order of registration
slow:Kernel.at_exit allows calling exit inside at_exit handler
slow:Kernel.at_exit gives access to the last raised exception
fails:Kernel.at_exit gives access to the last raised exception
fails:Kernel.at_exit runs after all other code
fails:Kernel.at_exit runs in reverse order of registration
fails:Kernel.at_exit allows calling exit inside at_exit handler
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/kernel/raise_tags.txt

This file was deleted.

6 changes: 0 additions & 6 deletions spec/truffle/tags/core/string/modulo_tags.txt
Original file line number Diff line number Diff line change
@@ -80,9 +80,3 @@ fails:String#% behaves as if calling Kernel#Float for %g arguments, when the pas
fails:String#% behaves as if calling Kernel#Float for %g arguments, when the passed argument is hexadecimal string
fails:String#% behaves as if calling Kernel#Float for %G arguments, when the passed argument does not respond to #to_ary
fails:String#% behaves as if calling Kernel#Float for %G arguments, when the passed argument is hexadecimal string
fails:String#% when format string contains %{} sections replaces %{} sections with values from passed-in hash
fails:String#% when format string contains %{} sections raises KeyError if key is missing from passed-in hash
fails:String#% when format string contains %{} sections should raise ArgumentError if no hash given
fails:String#% when format string contains %<> formats uses the named argument for the format's value
fails:String#% when format string contains %<> formats raises KeyError if key is missing from passed-in hash
fails:String#% when format string contains %<> formats should raise ArgumentError if no hash given
Original file line number Diff line number Diff line change
@@ -29,3 +29,4 @@
- date
- bigdecimal
- rubygems
- pathname
1 change: 0 additions & 1 deletion truffle/src/main/java/org/jruby/truffle/Main.java
Original file line number Diff line number Diff line change
@@ -72,7 +72,6 @@ public static void main(String[] args) {
runtime.getTruffleContext().execute(scriptNode);
} finally {
context.setFileAndLine(oldFile, oldLine);
runtime.shutdownTruffleContextIfRunning();
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* 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
*/
package org.jruby.truffle.format.nodes.read;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import org.jruby.truffle.format.nodes.PackNode;
import org.jruby.truffle.format.nodes.SourceNode;
import org.jruby.truffle.nodes.RubyGuards;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.core.hash.HashNodes;
import org.jruby.truffle.nodes.core.hash.HashNodesFactory;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;

@NodeChildren({
@NodeChild(value = "source", type = SourceNode.class),
})
public abstract class ReadHashValueNode extends PackNode {

private final Object key;

public ReadHashValueNode(RubyContext context, Object key) {
super(context);
this.key = key;
}

@Specialization
@CompilerDirectives.TruffleBoundary
public Object read(Object[] source) {
if (source.length != 1 || !RubyGuards.isRubyHash(source[0])) {
throw new RaiseException(getContext().getCoreLibrary().argumentError("one hash required", this));
}

// We're not in a Ruby frame here, so we can't run arbitrary Ruby nodes like Hash#[]. Instead use a slow send.

return getContext().send(source[0], "fetch", null, key);
}

}
Original file line number Diff line number Diff line change
@@ -47,7 +47,7 @@ public ReadStringNode(RubyContext context, boolean convertNumbersToStrings,
}

@Specialization(guards = "isNull(source)")
public long read(VirtualFrame frame, Object source) {
public Object read(VirtualFrame frame, Object source) {
CompilerDirectives.transferToInterpreter();

// Advance will handle the error
Original file line number Diff line number Diff line change
@@ -23,13 +23,15 @@ public class FormatDirective {
private final boolean leftJustified;
private final int precision;
private final char type;
private final Object key;

public FormatDirective(int spacePadding, int zeroPadding, boolean leftJustified, int precision, char type) {
public FormatDirective(int spacePadding, int zeroPadding, boolean leftJustified, int precision, char type, Object key) {
this.spacePadding = spacePadding;
this.zeroPadding = zeroPadding;
this.leftJustified = leftJustified;
this.precision = precision;
this.type = type;
this.key = key;
}

public int getSpacePadding() {
@@ -52,4 +54,7 @@ public char getType() {
return type;
}

public Object getKey() {
return key;
}
}
Original file line number Diff line number Diff line change
@@ -18,10 +18,12 @@
import org.jruby.truffle.format.nodes.format.FormatFloatNodeGen;
import org.jruby.truffle.format.nodes.format.FormatIntegerNodeGen;
import org.jruby.truffle.format.nodes.read.LiteralBytesNode;
import org.jruby.truffle.format.nodes.read.ReadHashValueNodeGen;
import org.jruby.truffle.format.nodes.read.ReadStringNodeGen;
import org.jruby.truffle.format.nodes.read.ReadValueNodeGen;
import org.jruby.truffle.format.nodes.type.ToDoubleWithCoercionNodeGen;
import org.jruby.truffle.format.nodes.type.ToIntegerNodeGen;
import org.jruby.truffle.format.nodes.type.ToStringNodeGen;
import org.jruby.truffle.format.nodes.write.WriteByteNode;
import org.jruby.truffle.format.nodes.write.WriteBytesNodeGen;
import org.jruby.truffle.format.nodes.write.WritePaddedBytesNodeGen;
@@ -46,7 +48,7 @@ public FormatParser(RubyContext context) {
}

public CallTarget parse(ByteList format) {
final FormatTokenizer tokenizer = new FormatTokenizer(format);
final FormatTokenizer tokenizer = new FormatTokenizer(context, format);
final PackNode body = parse(tokenizer);
return Truffle.getRuntime().createCallTarget(new PackRootNode(PackParser.describe(format.toString()), encoding, body));
}
@@ -74,17 +76,40 @@ public PackNode parse(FormatTokenizer tokenizer) {
} else if (token instanceof FormatDirective) {
final FormatDirective directive = (FormatDirective) token;

final PackNode valueNode;

if (directive.getKey() == null) {
valueNode = ReadValueNodeGen.create(context, new SourceNode());
} else {
valueNode = ReadHashValueNodeGen.create(context, directive.getKey(), new SourceNode());
}

switch (directive.getType()) {
case '%':
node = new WriteByteNode(context, (byte) '%');
break;
case '{':
node = WriteBytesNodeGen.create(context,
ToStringNodeGen.create(context, true, "to_s", false, new ByteList(),
valueNode));
break;
case 's':
if (directive.getSpacePadding() == FormatDirective.DEFAULT) {
node = WriteBytesNodeGen.create(context, ReadStringNodeGen.create(
context, true, "to_s", false, new ByteList(), new SourceNode()));
if (directive.getKey() == null) {
if (directive.getSpacePadding() == FormatDirective.DEFAULT) {
node = WriteBytesNodeGen.create(context, ReadStringNodeGen.create(
context, true, "to_s", false, new ByteList(), new SourceNode()));
} else {
node = WritePaddedBytesNodeGen.create(context, directive.getSpacePadding(), directive.getLeftJustified(),
ReadStringNodeGen.create(context, true, "to_s", false, new ByteList(), new SourceNode()));
}
} else {
node = WritePaddedBytesNodeGen.create(context, directive.getSpacePadding(), directive.getLeftJustified(),
ReadStringNodeGen.create(context, true, "to_s", false, new ByteList(), new SourceNode()));
if (directive.getSpacePadding() == FormatDirective.DEFAULT) {
node = WriteBytesNodeGen.create(context, ToStringNodeGen.create(
context, true, "to_s", false, new ByteList(), valueNode));
} else {
node = WritePaddedBytesNodeGen.create(context, directive.getSpacePadding(), directive.getLeftJustified(),
ToStringNodeGen.create(context, true, "to_s", false, new ByteList(), valueNode));
}
}
break;
case 'd':
@@ -127,7 +152,7 @@ public PackNode parse(FormatTokenizer tokenizer) {
node = WriteBytesNodeGen.create(context,
FormatIntegerNodeGen.create(context, spacePadding, zeroPadding, format,
ToIntegerNodeGen.create(context,
ReadValueNodeGen.create(context, new SourceNode()))));
valueNode)));
break;
case 'f':
case 'g':
@@ -139,7 +164,7 @@ public PackNode parse(FormatTokenizer tokenizer) {
directive.getZeroPadding(), directive.getPrecision(),
directive.getType(),
ToDoubleWithCoercionNodeGen.create(context,
ReadValueNodeGen.create(context, new SourceNode()))));
valueNode)));
break;
default:
throw new UnsupportedOperationException();
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@
*/
package org.jruby.truffle.format.parser;

import org.jruby.truffle.runtime.RubyContext;
import org.jruby.util.ByteList;

/**
@@ -19,33 +20,20 @@ public class FormatTokenizer {

private static final String TYPE_CHARS = "%-sdiuxXfgGeE";

private final RubyContext context;
private final ByteList format;
private int position;
private Object peek;

/**
* Construct a tokenizer.
* @param format the pack expression
*/
public FormatTokenizer(ByteList format) {
public FormatTokenizer(RubyContext context, ByteList format) {
this.context = context;
this.format = format;
}

public Object peek() {
if (peek == null) {
peek = next();
}

return peek;
}

public Object next() {
if (peek != null) {
final Object token = peek;
peek = null;
return token;
}

if (position >= format.length()) {
return null;
}
@@ -66,30 +54,43 @@ public Object next() {

position++;

Object key = null;

if (format.charAt(position) == '{') {
position++;
key = readUntil('}');
position++;
return new FormatDirective(0, 0, false, 0, '{', key);
} else if (format.charAt(position) == '<') {
position++;
key = readUntil('>');
position++;
}

boolean leftJustified = false;

if (format.charAt(position) == '-') {
if (position < format.length() && format.charAt(position) == '-') {
leftJustified = true;
position++;
}

int spacePadding;
int zeroPadding;

if (format.charAt(position) == ' ') {
if (position < format.length() && format.charAt(position) == ' ') {
position++;
spacePadding = readInt();
zeroPadding = FormatDirective.DEFAULT;
} else if (format.charAt(position) == '0') {
} else if (position < format.length() && format.charAt(position) == '0') {
spacePadding = FormatDirective.DEFAULT;
zeroPadding = readInt();
} else if (Character.isDigit(format.charAt(position))) {
} else if (position < format.length() && Character.isDigit(format.charAt(position))) {
spacePadding = readInt();
zeroPadding = FormatDirective.DEFAULT;
} else {
spacePadding = FormatDirective.DEFAULT;

if (format.charAt(position) == '0') {
if (position < format.length() && format.charAt(position) == '0') {
position++;
zeroPadding = readInt();
} else {
@@ -99,26 +100,37 @@ public Object next() {

final int precision;

if (format.charAt(position) == '.') {
if (position < format.length() && format.charAt(position) == '.') {
position++;
precision = readInt();
} else {
precision = FormatDirective.DEFAULT;
}

if (Character.isDigit(format.charAt(position))) {
if (position < format.length() && Character.isDigit(format.charAt(position))) {
spacePadding = readInt();
}

final char type = format.charAt(position);
char type;

if (TYPE_CHARS.indexOf(type) == -1) {
throw new UnsupportedOperationException("Unknown format type '" + format.charAt(position) + "'");
if (key != null && position >= format.length()) {
type = 's';
} else {
type = format.charAt(position);

if (key != null && Character.isWhitespace(type)) {
type = 's';
} else {
if (TYPE_CHARS.indexOf(type) == -1) {
throw new UnsupportedOperationException("Unknown format type '" + format.charAt(position) + "'");
}
}

position++;
}

position++;

return new FormatDirective(spacePadding, zeroPadding, leftJustified, precision, type);
return new FormatDirective(spacePadding, zeroPadding, leftJustified, precision, type, key);
}

private int readInt() {
@@ -131,4 +143,14 @@ private int readInt() {
return Integer.parseInt(format.subSequence(start, position).toString());
}

private Object readUntil(char end) {
final int start = position;

while (format.charAt(position) != end) {
position++;
}

return context.getSymbol((ByteList) format.subSequence(start, position));
}

}
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.CreateCast;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
@@ -25,18 +26,21 @@
import org.jruby.truffle.nodes.cast.BooleanCastNodeGen;
import org.jruby.truffle.nodes.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNodeFactory;
import org.jruby.truffle.nodes.dispatch.DispatchNode;
import org.jruby.truffle.nodes.dispatch.MissingBehavior;
import org.jruby.truffle.nodes.dispatch.RubyCallNode;
import org.jruby.truffle.nodes.methods.DeclarationContext;
import org.jruby.truffle.nodes.methods.UnsupportedOperationBehavior;
import org.jruby.truffle.nodes.objects.AllocateObjectNode;
import org.jruby.truffle.nodes.objects.AllocateObjectNodeGen;
import org.jruby.truffle.nodes.yield.YieldDispatchHeadNode;
import org.jruby.truffle.runtime.ModuleOperations;
import org.jruby.truffle.runtime.NotProvided;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.StringOperations;
import org.jruby.truffle.runtime.layouts.Layouts;
import org.jruby.truffle.runtime.methods.InternalMethod;

@CoreClass(name = "BasicObject")
public abstract class BasicObjectNodes {
@@ -197,40 +201,39 @@ public Object methodMissingNoName(Object self, NotProvided name, Object[] args,

@Specialization
public Object methodMissingNoBlock(Object self, DynamicObject name, Object[] args, NotProvided block) {
return methodMissingBlock(self, name, args, (DynamicObject) null);
return methodMissing(self, name, args, null);
}

@Specialization(guards = "isRubyProc(block)")
public Object methodMissingBlock(Object self, DynamicObject name, Object[] args, DynamicObject block) {
return methodMissing(self, name, args, block);
}

private Object methodMissing(Object self, DynamicObject name, Object[] args, DynamicObject block) {
CompilerDirectives.transferToInterpreter();

assert block == null || RubyGuards.isRubyProc(block);
@TruffleBoundary
private Object methodMissing(Object self, DynamicObject nameObject, Object[] args, DynamicObject block) {
final String name = nameObject.toString();

// TODO: should not be a call to Java toString(), but rather sth like name_err_mesg_to_str() in MRI error.c
if (lastCallWasVCall()) {
throw new RaiseException(
getContext().getCoreLibrary().nameErrorUndefinedLocalVariableOrMethod(
Layouts.SYMBOL.getString(name),
Layouts.MODULE.getFields(getContext().getCoreLibrary().getLogicalClass(self)).getName(),
this));
if (lastCallWasCallingPrivateMethod(self, name)) {
throw new RaiseException(getContext().getCoreLibrary().privateMethodError(name, self, this));
} else if (lastCallWasVCall()) {
throw new RaiseException(getContext().getCoreLibrary().nameErrorUndefinedLocalVariableOrMethod(name, self, this));
} else {
throw new RaiseException(getContext().getCoreLibrary().noMethodErrorOnReceiver(Layouts.SYMBOL.getString(name), self, this));
throw new RaiseException(getContext().getCoreLibrary().noMethodErrorOnReceiver(name, self, this));
}
}

/**
* See {@link org.jruby.truffle.nodes.dispatch.DispatchNode#lookup}.
* The only way to fail if method is not null and not undefined is visibility.
*/
private boolean lastCallWasCallingPrivateMethod(Object self, String name) {
final InternalMethod method = ModuleOperations.lookupMethod(getContext().getCoreLibrary().getMetaClass(self), name);
return method != null && !method.isUndefined();
}

private boolean lastCallWasVCall() {
final RubyCallNode callNode = NodeUtil.findParent(Truffle.getRuntime().getCallerFrame().getCallNode(), RubyCallNode.class);

if (callNode == null) {
return false;
}

return callNode.isVCall();

return callNode != null && callNode.isVCall();
}

}
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.utilities.BranchProfile;

import org.jcodings.specific.USASCIIEncoding;
import org.jruby.truffle.nodes.cast.BooleanCastNode;
import org.jruby.truffle.nodes.cast.BooleanCastNodeGen;
@@ -657,4 +658,19 @@ public DynamicObject toS(DynamicObject value, int base) {

}

@CoreMethod(names = "allocate", constructor = true)
public abstract static class AllocateNode extends UnaryCoreMethodNode {

public AllocateNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public DynamicObject allocate(DynamicObject rubyClass) {
throw new RaiseException(getContext().getCoreLibrary().typeErrorAllocatorUndefinedFor(rubyClass, this));
}

}

}
Original file line number Diff line number Diff line change
@@ -325,7 +325,7 @@ public Object receiver(DynamicObject binding) {
}

@CoreMethod(names = "allocate", constructor = true)
public abstract static class AllocateNode extends CoreMethodArrayArgumentsNode {
public abstract static class AllocateNode extends UnaryCoreMethodNode {

public AllocateNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;

import org.jcodings.Encoding;
import org.jcodings.EncodingDB;
import org.jcodings.specific.ASCIIEncoding;
@@ -477,4 +478,19 @@ public DynamicObject toS(DynamicObject encoding) {
}
}

@CoreMethod(names = "allocate", constructor = true)
public abstract static class AllocateNode extends UnaryCoreMethodNode {

public AllocateNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public DynamicObject allocate(DynamicObject rubyClass) {
throw new RaiseException(getContext().getCoreLibrary().typeErrorAllocatorUndefinedFor(rubyClass, this));
}

}

}
Original file line number Diff line number Diff line change
@@ -256,32 +256,6 @@ public Object compare(VirtualFrame frame, Object self, Object other) {

}

@CoreMethod(names = "abort", isModuleFunction = true, optional = 1)
public abstract static class AbortNode extends CoreMethodArrayArgumentsNode {

public AbortNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization(guards = "isRubyString(message)")
public DynamicObject abort(DynamicObject message) {
System.err.println(message.toString());
return abort();
}

@Specialization
public DynamicObject abort(NotProvided message) {
return abort();
}

@TruffleBoundary
private DynamicObject abort() {
getContext().innerShutdown(false);
throw new MainExitException(1, true);
}
}

@CoreMethod(names = "binding", isModuleFunction = true)
public abstract static class BindingNode extends CoreMethodArrayArgumentsNode {

Original file line number Diff line number Diff line change
@@ -10,12 +10,14 @@
package org.jruby.truffle.nodes.core;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.utilities.ConditionProfile;

import org.jcodings.Encoding;
import org.joni.Region;
import org.joni.exception.ValueException;
@@ -474,6 +476,22 @@ public DynamicObject regexp(DynamicObject matchData) {
}
}

@CoreMethod(names = "allocate", constructor = true)
public abstract static class AllocateNode extends UnaryCoreMethodNode {

public AllocateNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

// MatchData can be allocated in MRI but it does not seem to be any useful
@TruffleBoundary
@Specialization
public DynamicObject allocate(DynamicObject rubyClass) {
throw new RaiseException(getContext().getCoreLibrary().typeErrorAllocatorUndefinedFor(rubyClass, this));
}

}

@RubiniusOnly
@NodeChild(value = "self")
public abstract static class RubiniusSourceNode extends RubyNode {
Original file line number Diff line number Diff line change
@@ -37,6 +37,7 @@
import org.jruby.truffle.nodes.objects.ClassNodeGen;
import org.jruby.truffle.runtime.RubyArguments;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.StringOperations;
import org.jruby.truffle.runtime.layouts.Layouts;
import org.jruby.truffle.runtime.methods.InternalMethod;
@@ -296,4 +297,19 @@ public Object execute(VirtualFrame frame) {

}

@CoreMethod(names = "allocate", constructor = true)
public abstract static class AllocateNode extends UnaryCoreMethodNode {

public AllocateNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public DynamicObject allocate(DynamicObject rubyClass) {
throw new RaiseException(getContext().getCoreLibrary().typeErrorAllocatorUndefinedFor(rubyClass, this));
}

}

}
Original file line number Diff line number Diff line change
@@ -975,8 +975,9 @@ public RubyNode coerceToString(RubyNode name) {
return NameToJavaStringNodeGen.create(getContext(), getSourceSection(), name);
}

@TruffleBoundary
@Specialization
public Object methodMissing(DynamicObject module, String name) {
public Object constMissing(DynamicObject module, String name) {
throw new RaiseException(getContext().getCoreLibrary().nameErrorUninitializedConstant(module, name, this));
}

@@ -1306,10 +1307,9 @@ public NameNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public Object name(DynamicObject module) {
CompilerDirectives.transferToInterpreter();

if (!Layouts.MODULE.getFields(module).hasPartialName()) {
return nil();
}
Original file line number Diff line number Diff line change
@@ -85,7 +85,7 @@ public enum Type {
}

@CoreMethod(names = "allocate", constructor = true)
public abstract static class AllocateNode extends CoreMethodArrayArgumentsNode {
public abstract static class AllocateNode extends UnaryCoreMethodNode {

public AllocateNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ public class StringGuards {

public static boolean isSingleByteOptimizable(DynamicObject string) {
assert RubyGuards.isRubyString(string);
return StringSupport.isSingleByteOptimizable(StringOperations.getCodeRangeable(string), StringOperations.getByteList(string).getEncoding());
return Layouts.STRING.getCodeRange(string) == StringSupport.CR_7BIT || StringOperations.getByteList(string).getEncoding().maxLength() == 1;
}

public static boolean isAsciiCompatible(DynamicObject string) {
Original file line number Diff line number Diff line change
@@ -111,7 +111,8 @@ public AddNode(RubyContext context, SourceSection sourceSection) {
@Specialization(guards = "isRubyString(other)")
public DynamicObject add(DynamicObject string, DynamicObject other) {
final Encoding enc = StringOperations.checkEncoding(getContext(), string, StringOperations.getCodeRangeable(other), this);
final DynamicObject ret = createString(StringSupport.addByteLists(StringOperations.getByteList(string), StringOperations.getByteList(other)));
final int codeRange = StringOperations.commonCodeRange(Layouts.STRING.getCodeRange(string), Layouts.STRING.getCodeRange(other));
final DynamicObject ret = Layouts.STRING.createString(getContext().getCoreLibrary().getStringFactory(), StringSupport.addByteLists(StringOperations.getByteList(string), StringOperations.getByteList(other)), codeRange, null);

if (taintResultNode == null) {
CompilerDirectives.transferToInterpreter();
@@ -1179,7 +1180,7 @@ public Object getByte(DynamicObject string, int index) {
return nil();
}

return StringOperations.getByteList(string).get(index) & 0xff;
return bytes.get(index) & 0xff;
}
}

Original file line number Diff line number Diff line change
@@ -19,13 +19,15 @@
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.nodes.RubyRootNode;
import org.jruby.truffle.nodes.arguments.CheckArityNode;
import org.jruby.truffle.nodes.control.SequenceNode;
import org.jruby.truffle.nodes.methods.SymbolProcNode;
import org.jruby.truffle.runtime.RubyArguments;
import org.jruby.truffle.runtime.RubyCallStack;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.SymbolCodeRangeableWrapper;
import org.jruby.truffle.runtime.layouts.Layouts;
import org.jruby.truffle.runtime.methods.Arity;
@@ -181,4 +183,19 @@ public DynamicObject toS(DynamicObject symbol) {

}

@CoreMethod(names = "allocate", constructor = true)
public abstract static class AllocateNode extends UnaryCoreMethodNode {

public AllocateNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public DynamicObject allocate(DynamicObject rubyClass) {
throw new RaiseException(getContext().getCoreLibrary().typeErrorAllocatorUndefinedFor(rubyClass, this));
}

}

}
Original file line number Diff line number Diff line change
@@ -127,10 +127,15 @@ public static void cleanup(RubyContext context, DynamicObject thread) {
Layouts.THREAD.getFinishedLatch(thread).countDown();
}

public static void shutdown(DynamicObject thread) {
public static void shutdown(RubyContext context, DynamicObject thread, Node currentNode) {
assert RubyGuards.isRubyThread(thread);
Layouts.THREAD.getFiberManager(thread).shutdown();
throw new ThreadExitException();

if (thread == context.getThreadManager().getRootThread()) {
throw new RaiseException(context.getCoreLibrary().systemExit(0, currentNode));
} else {
throw new ThreadExitException();
}
}

@CoreMethod(names = "alive?")
@@ -179,7 +184,7 @@ public DynamicObject kill(final DynamicObject rubyThread) {
getContext().getSafepointManager().pauseThreadAndExecuteLater(toKill, this, new SafepointAction() {
@Override
public void run(DynamicObject currentThread, Node currentNode) {
shutdown(currentThread);
shutdown(getContext(), currentThread, currentNode);
}
});

@@ -464,6 +469,7 @@ public AllocateNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

// TODO (eregon, 13/10/2015): Thread is not allocatable in MRI
@TruffleBoundary
@Specialization
public DynamicObject allocate(DynamicObject rubyClass) {
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;

import org.jcodings.specific.UTF8Encoding;
import org.jruby.runtime.ArgumentDescriptor;
import org.jruby.runtime.Helpers;
@@ -187,4 +188,19 @@ public Object sourceLocation(DynamicObject unboundMethod) {

}

@CoreMethod(names = "allocate", constructor = true)
public abstract static class AllocateNode extends UnaryCoreMethodNode {

public AllocateNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public DynamicObject allocate(DynamicObject rubyClass) {
throw new RaiseException(getContext().getCoreLibrary().typeErrorAllocatorUndefinedFor(rubyClass, this));
}

}

}
Original file line number Diff line number Diff line change
@@ -54,34 +54,23 @@ protected InternalMethod lookup(
Object receiver,
String name,
boolean ignoreVisibility) {
assert callerClass == null || RubyGuards.isRubyClass(callerClass);
assert ignoreVisibility || RubyGuards.isRubyClass(callerClass);

InternalMethod method = ModuleOperations.lookupMethod(getContext().getCoreLibrary().getMetaClass(receiver), name);
final InternalMethod method = ModuleOperations.lookupMethod(getContext().getCoreLibrary().getMetaClass(receiver), name);

// If no method was found, use #method_missing

if (method == null) {
return null;
}

// Check for methods that are explicitly undefined

if (method.isUndefined()) {
return null;
}

// Check visibility

if (!ignoreVisibility && !method.isVisibleTo(this, callerClass)) {
final DispatchAction dispatchAction = getHeadNode().getDispatchAction();

if (dispatchAction == DispatchAction.CALL_METHOD) {
throw new RaiseException(getContext().getCoreLibrary().privateMethodError(name, getContext().getCoreLibrary().getLogicalClass(receiver), this));
} else if (dispatchAction == DispatchAction.RESPOND_TO_METHOD) {
return null;
} else {
throw new UnsupportedOperationException();
}
return null;
}

return method;
Original file line number Diff line number Diff line change
@@ -34,8 +34,6 @@ public final class UnresolvedDispatchNode extends DispatchNode {
private final boolean ignoreVisibility;
private final MissingBehavior missingBehavior;

@Child private SingletonClassNode singletonClassNode;

public UnresolvedDispatchNode(
RubyContext context,
boolean ignoreVisibility,
Original file line number Diff line number Diff line change
@@ -10,7 +10,6 @@
package org.jruby.truffle.nodes.exceptions;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
@@ -19,10 +18,9 @@
import org.jruby.truffle.nodes.cast.IntegerCastNode;
import org.jruby.truffle.nodes.cast.IntegerCastNodeGen;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.backtrace.BacktraceFormatter;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.control.ThreadExitException;
import org.jruby.truffle.runtime.layouts.Layouts;
import org.jruby.truffle.runtime.subsystems.AtExitManager;

public class TopLevelRaiseHandler extends RubyNode {

@@ -36,32 +34,35 @@ public TopLevelRaiseHandler(RubyContext context, SourceSection sourceSection, Ru

@Override
public Object execute(VirtualFrame frame) {
DynamicObject lastException = null;

try {
return body.execute(frame);
body.execute(frame);
} catch (RaiseException e) {
handleException(e);
} catch (ThreadExitException e) {
// Ignore
lastException = AtExitManager.handleAtExitException(getContext(), e);
} finally {
final DynamicObject atExitException = getContext().runAtExitHooks();
if (atExitException != null) {
lastException = atExitException;
}

getContext().shutdown();
final int status = statusFromException(lastException);
System.exit(status);
}

// unreachable
return nil();
}

@TruffleBoundary
private void handleException(RaiseException e) {
final DynamicObject rubyException = e.getRubyException();
final int status;

if (Layouts.BASIC_OBJECT.getLogicalClass(rubyException) == getContext().getCoreLibrary().getSystemExitClass()) {
status = castToInt(rubyException.get("@status", null));
private int statusFromException(DynamicObject exception) {
if (exception == null) {
return 0;
} else if (Layouts.BASIC_OBJECT.getLogicalClass(exception) == getContext().getCoreLibrary().getSystemExitClass()) {
return castToInt(exception.get("@status", null));
} else {
status = 1;
BacktraceFormatter.createDefaultFormatter(getContext()).printBacktrace((DynamicObject) rubyException, Layouts.EXCEPTION.getBacktrace((DynamicObject) rubyException));
return 1;
}

getContext().shutdown();

System.exit(status);
}

private int castToInt(Object value) {
Original file line number Diff line number Diff line change
@@ -10,12 +10,15 @@
package org.jruby.truffle.nodes.rubinius;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;

import org.jruby.truffle.nodes.core.CoreClass;
import org.jruby.truffle.nodes.core.CoreMethod;
import org.jruby.truffle.nodes.core.CoreMethodArrayArgumentsNode;
import org.jruby.truffle.nodes.core.UnaryCoreMethodNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.StringOperations;
@@ -117,4 +120,19 @@ public Object getByte(DynamicObject bytes, DynamicObject pattern, int start, int

}

@CoreMethod(names = "allocate", constructor = true)
public abstract static class AllocateNode extends UnaryCoreMethodNode {

public AllocateNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public DynamicObject allocate(DynamicObject rubyClass) {
throw new RaiseException(getContext().getCoreLibrary().typeErrorAllocatorUndefinedFor(rubyClass, this));
}

}

}
Original file line number Diff line number Diff line change
@@ -1188,20 +1188,23 @@ public DynamicObject stringByteAppend(DynamicObject string, DynamicObject other)
@ImportStatic(StringGuards.class)
public static abstract class StringSubstringPrimitiveNode extends RubiniusPrimitiveNode {

@Child private AllocateObjectNode allocateNode;
@Child private TaintResultNode taintResultNode;
private final ConditionProfile negativeLengthProfile = ConditionProfile.createBinaryProfile();
private final ConditionProfile tooLargeBeginProfile = ConditionProfile.createBinaryProfile();
private final ConditionProfile negativeBeginProfile = ConditionProfile.createBinaryProfile();

public StringSubstringPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public abstract Object execute(VirtualFrame frame, DynamicObject string, int beg, int len);

@TruffleBoundary
@Specialization(guards = "isSingleByteOptimizable(string)")
public Object stringSubstringSingleByteOptimizable(DynamicObject string, int beg, int len) {
// Taken from org.jruby.RubyString#substr19.

if (len < 0) {
if (negativeLengthProfile.profile(len < 0)) {
return nil();
}

@@ -1210,14 +1213,14 @@ public Object stringSubstringSingleByteOptimizable(DynamicObject string, int beg
len = 0;
}

if (beg > length) {
if (tooLargeBeginProfile.profile(beg > length)) {
return nil();
}

if (beg < 0) {
beg += length;

if (beg < 0) {
if (negativeBeginProfile.profile(beg < 0)) {
return nil();
}
}
@@ -1310,13 +1313,22 @@ public Object stringSubstring(DynamicObject string, int beg, int len) {
private DynamicObject makeSubstring(DynamicObject string, int beg, int len) {
assert RubyGuards.isRubyString(string);

if (allocateNode == null) {
CompilerDirectives.transferToInterpreter();
allocateNode = insert(AllocateObjectNodeGen.create(getContext(), getSourceSection(), null, null));
}

if (taintResultNode == null) {
CompilerDirectives.transferToInterpreter();
taintResultNode = insert(new TaintResultNode(getContext(), getSourceSection()));
}

final DynamicObject ret = Layouts.STRING.createString(Layouts.CLASS.getInstanceFactory(Layouts.BASIC_OBJECT.getLogicalClass(string)), new ByteList(StringOperations.getByteList(string), beg, len), StringSupport.CR_UNKNOWN, null);
StringOperations.getByteList(ret).setEncoding(StringOperations.getByteList(string).getEncoding());
final DynamicObject ret = allocateNode.allocate(
Layouts.BASIC_OBJECT.getLogicalClass(string),
new ByteList(StringOperations.getByteList(string), beg, len),
StringSupport.CR_UNKNOWN,
null);

taintResultNode.maybeTaint(string, ret);

return ret;
Original file line number Diff line number Diff line change
@@ -154,8 +154,7 @@ public VMExitPrimitiveNode(RubyContext context, SourceSection sourceSection) {

@Specialization
public Object vmExit(int status) {
getContext().innerShutdown(false);

getContext().shutdown();
System.exit(status);
return nil();
}
36 changes: 18 additions & 18 deletions truffle/src/main/java/org/jruby/truffle/runtime/RubyContext.java
Original file line number Diff line number Diff line change
@@ -268,7 +268,7 @@ private void initialize() {
for (IRubyObject arg : ((org.jruby.RubyArray) runtime.getObject().getConstant("ARGV")).toJavaArray()) {
assert arg != null;

ArrayOperations.append(coreLibrary.getArgv(), Layouts.STRING.createString(Layouts.CLASS.getInstanceFactory(coreLibrary.getStringClass()), StringOperations.encodeByteList(arg.toString(), UTF8Encoding.INSTANCE), StringSupport.CR_UNKNOWN, null));
ArrayOperations.append(coreLibrary.getArgv(), StringOperations.createString(this, StringOperations.encodeByteList(arg.toString(), UTF8Encoding.INSTANCE)));
}

// Set the load path
@@ -287,7 +287,7 @@ private void initialize() {
pathString = SourceLoader.JRUBY_SCHEME + pathString.substring("uri:classloader:".length());
}

ArrayOperations.append(loadPath, Layouts.STRING.createString(coreLibrary.getStringFactory(), StringOperations.encodeByteList(pathString, UTF8Encoding.INSTANCE), StringSupport.CR_UNKNOWN, null));
ArrayOperations.append(loadPath, StringOperations.createString(this, StringOperations.encodeByteList(pathString, UTF8Encoding.INSTANCE)));
}
}

@@ -308,21 +308,21 @@ private void initialize() {
home = home + "/";

// Libraries copied unmodified from MRI
ArrayOperations.append(loadPath, Layouts.STRING.createString(coreLibrary.getStringFactory(), StringOperations.encodeByteList(home + "lib/ruby/truffle/mri", UTF8Encoding.INSTANCE), StringSupport.CR_UNKNOWN, null));
ArrayOperations.append(loadPath, StringOperations.createString(this, StringOperations.encodeByteList(home + "lib/ruby/truffle/mri", UTF8Encoding.INSTANCE)));

// Our own implementations
ArrayOperations.append(loadPath, Layouts.STRING.createString(coreLibrary.getStringFactory(), StringOperations.encodeByteList(home + "lib/ruby/truffle/truffle", UTF8Encoding.INSTANCE), StringSupport.CR_UNKNOWN, null));
ArrayOperations.append(loadPath, StringOperations.createString(this, StringOperations.encodeByteList(home + "lib/ruby/truffle/truffle", UTF8Encoding.INSTANCE)));

// Libraries from RubySL
for (String lib : Arrays.asList("rubysl-strscan", "rubysl-stringio",
"rubysl-complex", "rubysl-date", "rubysl-pathname",
"rubysl-tempfile", "rubysl-socket", "rubysl-securerandom",
"rubysl-timeout", "rubysl-webrick")) {
ArrayOperations.append(loadPath, Layouts.STRING.createString(coreLibrary.getStringFactory(), StringOperations.encodeByteList(home + "lib/ruby/truffle/rubysl/" + lib + "/lib", UTF8Encoding.INSTANCE), StringSupport.CR_UNKNOWN, null));
ArrayOperations.append(loadPath, StringOperations.createString(this, StringOperations.encodeByteList(home + "lib/ruby/truffle/rubysl/" + lib + "/lib", UTF8Encoding.INSTANCE)));
}

// Shims
ArrayOperations.append(loadPath, Layouts.STRING.createString(coreLibrary.getStringFactory(), StringOperations.encodeByteList(home + "lib/ruby/truffle/shims", UTF8Encoding.INSTANCE), StringSupport.CR_UNKNOWN, null));
ArrayOperations.append(loadPath, StringOperations.createString(this, StringOperations.encodeByteList(home + "lib/ruby/truffle/shims", UTF8Encoding.INSTANCE)));
}

// TODO (eregon, 10/10/2015): this check could be done when a Symbol is created to be much cheaper
@@ -438,16 +438,6 @@ public long getNextObjectID() {
return id;
}

public void innerShutdown(boolean normalExit) {
atExitManager.run(normalExit);

if (instrumentationServerManager != null) {
instrumentationServerManager.shutdown();
}

threadManager.shutdown();
}

public Object makeTuple(VirtualFrame frame, CallDispatchHeadNode newTupleNode, Object... values) {
return newTupleNode.call(frame, getCoreLibrary().getTupleClass(), "create", null, values);
}
@@ -521,7 +511,7 @@ public DynamicObject toTruffle(org.jruby.RubyArray array) {
}

public DynamicObject toTruffle(org.jruby.RubyString jrubyString) {
final DynamicObject truffleString = Layouts.STRING.createString(coreLibrary.getStringFactory(), jrubyString.getByteList().dup(), StringSupport.CR_UNKNOWN, null);
final DynamicObject truffleString = StringOperations.createString(this, jrubyString.getByteList().dup());

if (jrubyString.isTaint()) {
truffleString.define(Layouts.TAINTED_IDENTIFIER, true, 0);
@@ -656,8 +646,18 @@ public Object execute(final org.jruby.ast.RootNode rootNode) {
return execute(ParserContext.TOP_LEVEL, DeclarationContext.TOP_LEVEL, newRootNode, null, coreLibrary.getMainObject());
}

public DynamicObject runAtExitHooks() {
return atExitManager.runAtExitHooks();
}

public void shutdown() {
innerShutdown(true);
atExitManager.runSystemExitHooks();

if (instrumentationServerManager != null) {
instrumentationServerManager.shutdown();
}

threadManager.shutdown();
}

public PrintStream getDebugStandardOut() {
Original file line number Diff line number Diff line change
@@ -67,9 +67,7 @@ public BacktraceFormatter(RubyContext context, EnumSet<FormattingFlags> flags) {
}

public void printBacktrace(DynamicObject exception, Backtrace backtrace) {
try (PrintWriter writer = new PrintWriter(System.err)) {
printBacktrace(exception, backtrace, writer);
}
printBacktrace(exception, backtrace, new PrintWriter(System.err, true));
}

public void printBacktrace(DynamicObject exception, Backtrace backtrace, PrintWriter writer) {

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -189,5 +189,21 @@ public static ByteList encodeByteList(CharSequence value, Encoding encoding) {
public static ByteList getByteList(DynamicObject object) {
return Layouts.STRING.getByteList(object);
}


public static int commonCodeRange(int first, int second) {
if (first == second) {
return first;
}

if ((first == StringSupport.CR_UNKNOWN) || (second == StringSupport.CR_UNKNOWN)) {
return StringSupport.CR_UNKNOWN;
}

if ((first == StringSupport.CR_BROKEN) || (second == StringSupport.CR_BROKEN)) {
return StringSupport.CR_BROKEN;
}

// If we get this far, one must be CR_7BIT and the other must be CR_VALID, so promote to the more general code range.
return StringSupport.CR_VALID;
}
}
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
package org.jruby.truffle.runtime.subsystems;

import com.oracle.truffle.api.object.DynamicObject;

import org.jruby.truffle.nodes.RubyGuards;
import org.jruby.truffle.nodes.core.ProcNodes;
import org.jruby.truffle.runtime.RubyContext;
@@ -27,8 +28,8 @@ public class AtExitManager {

private final RubyContext context;

private final Deque<DynamicObject> runOnExit = new ConcurrentLinkedDeque<>();
private final Deque<DynamicObject> runOnExitAlways = new ConcurrentLinkedDeque<>();
private final Deque<DynamicObject> atExitHooks = new ConcurrentLinkedDeque<>();
private final Deque<DynamicObject> systemExitHooks = new ConcurrentLinkedDeque<>();

public AtExitManager(RubyContext context) {
this.context = context;
@@ -38,36 +39,35 @@ public void add(DynamicObject block, boolean always) {
assert RubyGuards.isRubyProc(block);

if (always) {
runOnExitAlways.push(block);
systemExitHooks.push(block);
} else {
runOnExit.push(block);
atExitHooks.push(block);
}
}

public void run(boolean normalExit) {
try {
if (normalExit) {
runExitHooks(runOnExit);
}
} finally {
runExitHooks(runOnExitAlways);
}
public DynamicObject runAtExitHooks() {
return runExitHooks(atExitHooks);
}

public void runSystemExitHooks() {
runExitHooks(systemExitHooks);
}

private void runExitHooks(Deque<DynamicObject> stack) {
private DynamicObject runExitHooks(Deque<DynamicObject> stack) {
DynamicObject lastException = null;

while (true) {
DynamicObject block;
try {
block = stack.pop();
} catch (NoSuchElementException e) {
break;
return lastException;
}

try {
ProcNodes.rootCall(block);
} catch (RaiseException e) {
final Object rubyException = e.getRubyException();
BacktraceFormatter.createDefaultFormatter(context).printBacktrace((DynamicObject) rubyException, Layouts.EXCEPTION.getBacktrace((DynamicObject) rubyException));
lastException = handleAtExitException(context, e);
} catch (Exception e) {
e.printStackTrace();
}
@@ -76,9 +76,19 @@ private void runExitHooks(Deque<DynamicObject> stack) {

public List<DynamicObject> getHandlers() {
final List<DynamicObject> handlers = new ArrayList<>();
handlers.addAll(runOnExit);
handlers.addAll(runOnExitAlways);
handlers.addAll(atExitHooks);
handlers.addAll(systemExitHooks);
return handlers;
}

public static DynamicObject handleAtExitException(RubyContext context, RaiseException raiseException) {
final DynamicObject rubyException = raiseException.getRubyException();
if (Layouts.BASIC_OBJECT.getLogicalClass(rubyException) == context.getCoreLibrary().getSystemExitClass()) {
// Do not show SystemExit errors, just track them for the exit status
} else {
BacktraceFormatter.createDefaultFormatter(context).printBacktrace(rubyException, Layouts.EXCEPTION.getBacktrace(rubyException));
}
return rubyException;
}

}
Original file line number Diff line number Diff line change
@@ -135,7 +135,7 @@ private void killOtherThreads() {
@Override
public synchronized void run(DynamicObject thread, Node currentNode) {
if (thread != rootThread && Thread.currentThread() == Layouts.THREAD.getThread(thread)) {
ThreadNodes.shutdown(thread);
ThreadNodes.shutdown(context, thread, currentNode);
}
}
});
3 changes: 3 additions & 0 deletions truffle/src/main/ruby/core/float.rb
Original file line number Diff line number Diff line change
@@ -34,6 +34,9 @@

class Float

# Floats are also immediate values for us, they are primitive double
include ImmediateValue

NAN = 0.0 / 0.0
INFINITY = 1.0 / 0.0
EPSILON = 2.2204460492503131e-16
6 changes: 5 additions & 1 deletion truffle/src/main/ruby/core/string.rb
Original file line number Diff line number Diff line change
@@ -9,7 +9,11 @@
class String

def %(args)
sprintf(self, *args)
if args.is_a? Hash
sprintf(self, args)
else
sprintf(self, *args)
end
end

def downcase