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: c97b0990a830
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 4593de4f4086
Choose a head ref
  • 3 commits
  • 9 files changed
  • 1 contributor

Commits on Feb 9, 2015

  1. [Truffle] The throw tags should be used as a stack.

    * Otherwise we might remove another tag than the one we pushed.
    eregon committed Feb 9, 2015
    Copy the full SHA
    55f307a View commit details
  2. Copy the full SHA
    8c6945f View commit details
  3. Copy the full SHA
    4593de4 View commit details
15 changes: 0 additions & 15 deletions spec/truffle/tags/core/kernel/catch_tags.txt

This file was deleted.

8 changes: 0 additions & 8 deletions spec/truffle/tags/core/kernel/throw_tags.txt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -208,7 +208,7 @@ public ReferenceEqualNode(ReferenceEqualNode prev) {
super(prev);
}

protected abstract boolean executeReferenceEqual(VirtualFrame frame, Object a, Object b);
public abstract boolean executeReferenceEqual(VirtualFrame frame, Object a, Object b);

@Specialization public boolean equal(boolean a, boolean b) { return a == b; }
@Specialization public boolean equal(int a, int b) { return a == b; }
Original file line number Diff line number Diff line change
@@ -397,40 +397,6 @@ public Object caller(int omit) {
}
}

@CoreMethod(names = "catch", isModuleFunction = true, needsBlock = true, required = 1)
public abstract static class CatchNode extends YieldingCoreMethodNode {

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

public CatchNode(CatchNode prev) {
super(prev);
}

@Specialization
public Object doCatch(VirtualFrame frame, Object tag, RubyProc block) {
notDesignedForCompilation();

try {
getContext().getThrowTags().add(tag);

return yield(frame, block);
} catch (ThrowException e) {
if (e.getTag().equals(tag)) {
// TODO(cs): unset rather than set to Nil?
notDesignedForCompilation();
getContext().getCoreLibrary().getGlobalVariablesObject().getOperations().setInstanceVariable(getContext().getCoreLibrary().getGlobalVariablesObject(), "$!", getContext().getCoreLibrary().getNilObject());
return e.getValue();
} else {
throw e;
}
} finally {
getContext().getThrowTags().remove();
}
}
}

@CoreMethod(names = "class")
public abstract static class KernelClassNode extends CoreMethodNode {

@@ -2151,38 +2117,6 @@ public boolean tainted(RubyBasicObject object) {

}

@CoreMethod(names = "throw", isModuleFunction = true, required = 1, optional = 1)
public abstract static class ThrowNode extends CoreMethodNode {

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

public ThrowNode(ThrowNode prev) {
super(prev);
}

@Specialization
public Object doThrow(Object tag, UndefinedPlaceholder value) {
return doThrow(tag, getContext().getCoreLibrary().getNilObject());
}

@Specialization(guards = "!isUndefinedPlaceholder(arguments[1])")
public Object doThrow(Object tag, Object value) {
notDesignedForCompilation();

if (!getContext().getThrowTags().contains(tag)) {
throw new RaiseException(new RubyException(
getContext().getCoreLibrary().getArgumentErrorClass(),
getContext().makeString(String.format("uncaught throw \"%s\"", tag)),
RubyCallStack.getBacktrace(this)));
}

throw new ThrowException(tag, value);
}

}

public abstract static class ToHexStringNode extends CoreMethodNode {

public ToHexStringNode(RubyContext context, SourceSection sourceSection) {
Original file line number Diff line number Diff line change
@@ -9,27 +9,81 @@
*/
package org.jruby.truffle.nodes.rubinius;

import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;

import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.core.BasicObjectNodes;
import org.jruby.truffle.nodes.core.BasicObjectNodesFactory;
import org.jruby.truffle.nodes.core.KernelNodes;
import org.jruby.truffle.nodes.core.KernelNodesFactory;
import org.jruby.truffle.nodes.objects.ClassNode;
import org.jruby.truffle.nodes.objects.ClassNodeFactory;
import org.jruby.truffle.nodes.yield.YieldDispatchHeadNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.*;
import org.jruby.truffle.runtime.control.ThrowException;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.core.RubyClass;
import org.jruby.truffle.runtime.core.RubyModule;
import org.jruby.truffle.runtime.core.RubyNilClass;
import org.jruby.truffle.runtime.core.RubyProc;
import org.jruby.truffle.runtime.core.RubyString;
import org.jruby.truffle.runtime.core.RubyThread;
import org.jruby.truffle.runtime.signal.ProcSignalHandler;
import org.jruby.truffle.runtime.signal.SignalOperations;

import sun.misc.Signal;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;

/**
* Rubinius primitives associated with the VM.
*/
public abstract class VMPrimitiveNodes {

@RubiniusPrimitive(name = "vm_catch", needsSelf = false)
public abstract static class CatchNode extends RubiniusPrimitiveNode {

@Child private YieldDispatchHeadNode dispatchNode;
@Child private BasicObjectNodes.ReferenceEqualNode referenceEqualNode;

public CatchNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
dispatchNode = new YieldDispatchHeadNode(context);
}

public CatchNode(CatchNode prev) {
super(prev);
dispatchNode = prev.dispatchNode;
}

private boolean areSame(VirtualFrame frame, Object left, Object right) {
if (referenceEqualNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
referenceEqualNode = insert(BasicObjectNodesFactory.ReferenceEqualNodeFactory.create(getContext(), getSourceSection(), null, null));
}
return referenceEqualNode.executeReferenceEqual(frame, left, right);
}

@Specialization
public Object doCatch(VirtualFrame frame, Object tag, RubyProc block) {
notDesignedForCompilation();

try {
return dispatchNode.dispatch(frame, block, tag);
} catch (ThrowException e) {
if (areSame(frame, e.getTag(), tag)) {
notDesignedForCompilation();
RubyBasicObject globals = getContext().getCoreLibrary().getGlobalVariablesObject();
globals.getOperations().setInstanceVariable(globals, "$!", getContext().getCoreLibrary().getNilObject());
return e.getValue();
} else {
throw e;
}
}
}
}

@RubiniusPrimitive(name = "vm_gc_start", needsSelf = false)
public static abstract class VMGCStartPrimitiveNode extends RubiniusPrimitiveNode {

@@ -238,6 +292,26 @@ public Object vmSingletonClassObject(Object object) {

}

@RubiniusPrimitive(name = "vm_throw", needsSelf = false)
public abstract static class ThrowNode extends RubiniusPrimitiveNode {

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

public ThrowNode(ThrowNode prev) {
super(prev);
}

@Specialization
public Object doThrow(Object tag, Object value) {
notDesignedForCompilation();

throw new ThrowException(tag, value);
}

}

@SuppressWarnings("restriction")
@RubiniusPrimitive(name = "vm_watch_signal", needsSelf = false)
public static abstract class VMWatchSignalPrimitiveNode extends RubiniusPrimitiveNode {
14 changes: 1 addition & 13 deletions truffle/src/main/java/org/jruby/truffle/runtime/RubyContext.java
Original file line number Diff line number Diff line change
@@ -40,6 +40,7 @@
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;
@@ -69,15 +70,6 @@ public class RubyContext extends ExecutionContext {

private final AtomicLong nextObjectID = new AtomicLong(ObjectIDOperations.FIRST_OBJECT_ID);

private final ThreadLocal<Queue<Object>> throwTags = new ThreadLocal<Queue<Object>>() {

@Override
protected Queue<Object> initialValue() {
return new ArrayDeque<>();
}

};

public RubyContext(Ruby runtime) {
assert runtime != null;

@@ -403,10 +395,6 @@ public Warnings getWarnings() {
return warnings;
}

public Queue<Object> getThrowTags() {
return throwTags.get();
}

public SafepointManager getSafepointManager() {
return safepointManager;
}
1 change: 1 addition & 0 deletions truffle/src/main/ruby/jruby/truffle/core.rb
Original file line number Diff line number Diff line change
@@ -60,6 +60,7 @@
require_relative 'core/rubinius/kernel/common/regexp'
require_relative 'core/rubinius/kernel/common/signal'
require_relative 'core/rubinius/kernel/common/mutex'
require_relative 'core/rubinius/kernel/common/throw_catch'
require_relative 'core/rubinius/kernel/common/time'
require_relative 'core/rubinius/kernel/common/true'

Original file line number Diff line number Diff line change
@@ -31,4 +31,14 @@ def self.watch_signal(sig, ignored)
Rubinius.primitive :vm_watch_signal
raise PrimitiveFailure, "Rubinius.vm_watch_signal primitive failed" # Truffle: simplified failure
end

def self.throw(dest, obj)
Rubinius.primitive :vm_throw
raise PrimitiveFailure, "Rubinius.throw primitive failed"
end

def self.catch(dest, obj)
Rubinius.primitive :vm_catch
raise PrimitiveFailure, "Rubinius.catch primitive failed"
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Copyright (c) 2007-2014, Evan Phoenix and contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Rubinius nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

module Rubinius
module ThrownValue
def self.register(obj)
cur = (Thread.current[:__catches__] ||= [])
cur << obj

begin
yield
ensure
cur.pop
end
end

def self.available?(obj)
cur = Thread.current[:__catches__]
return false unless cur
cur.each do |c|
return true if Rubinius::Type.object_equal(c, obj)
end
false
end
end
end

module Kernel
def catch(obj = Object.new, &block)
raise LocalJumpError unless block_given?

Rubinius::ThrownValue.register(obj) do
return Rubinius.catch(obj, block)
end
end
module_function :catch

def throw(obj, value=nil)
unless Rubinius::ThrownValue.available? obj
raise ArgumentError, "uncaught throw #{obj.inspect}"
end

Rubinius.throw obj, value
end
module_function :throw
end