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: 46c9f101855e
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 940601d1f106
Choose a head ref
  • 2 commits
  • 13 files changed
  • 1 contributor

Commits on Mar 1, 2015

  1. Copy the full SHA
    5946dc7 View commit details
  2. Copy the full SHA
    940601d View commit details
4 changes: 4 additions & 0 deletions core/src/main/java/org/jruby/RubyException.java
Original file line number Diff line number Diff line change
@@ -386,6 +386,10 @@ public IRubyObject to_s19(ThreadContext context) {
return message.asString();
}

public IRubyObject getMessage() {
return message;
}

private BacktraceData backtraceData;
private IRubyObject backtrace;
public IRubyObject message;
34 changes: 0 additions & 34 deletions spec/truffle/tags/core/array/pack/a_tags.txt

This file was deleted.

83 changes: 67 additions & 16 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/ArrayNodes.java
Original file line number Diff line number Diff line change
@@ -12,8 +12,7 @@
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.dsl.ImportGuards;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.dsl.*;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.FrameSlot;
import com.oracle.truffle.api.frame.VirtualFrame;
@@ -23,10 +22,12 @@
import com.oracle.truffle.api.utilities.BranchProfile;

import org.jruby.runtime.Visibility;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.truffle.nodes.CoreSourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.RubyRootNode;
import org.jruby.truffle.nodes.array.*;
import org.jruby.truffle.nodes.cast.ToSNodeFactory;
import org.jruby.truffle.nodes.dispatch.*;
import org.jruby.truffle.nodes.methods.arguments.MissingArgumentBehaviour;
import org.jruby.truffle.nodes.methods.arguments.ReadPreArgumentNode;
@@ -37,13 +38,7 @@
import org.jruby.truffle.runtime.control.NextException;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.control.RedoException;
import org.jruby.truffle.runtime.core.RubyArray;
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.RubyRange;
import org.jruby.truffle.runtime.core.RubyString;
import org.jruby.truffle.runtime.core.RubySymbol;
import org.jruby.truffle.runtime.core.*;
import org.jruby.truffle.runtime.methods.SharedMethodInfo;
import org.jruby.truffle.runtime.util.ArrayUtils;
import org.jruby.util.ByteList;
@@ -1934,12 +1929,15 @@ public CallTarget getCallTarget() {
@CoreMethod(names = "pack", required = 1)
public abstract static class PackNode extends ArrayCoreMethodNode {

@Child private CallDispatchHeadNode toStringNode;

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

public PackNode(PackNode prev) {
super(prev);
toStringNode = prev.toStringNode;
}

@Specialization(guards = {"arrayIsLongs", "formatIsLStar"})
@@ -1957,20 +1955,73 @@ public RubyString packLStar(RubyArray array, RubyString format) {
bytes[byteOffset + 0] = (byte) value;
}

// TODO CS 1-Mar-15 should be tainting here - but ideally have a pack node, and then taint on top of that

return new RubyString(getContext().getCoreLibrary().getStringClass(), new ByteList(bytes));
}

@CompilerDirectives.TruffleBoundary
@Specialization
public RubyString pack(RubyArray array, RubyString format) {
public RubyString pack(VirtualFrame frame, RubyArray array, RubyString format) {
notDesignedForCompilation();

return new RubyString(
getContext().getCoreLibrary().getStringClass(),
org.jruby.util.Pack.pack(
getContext().getRuntime(),
getContext().toJRuby(array),
getContext().toJRuby(format).getByteList()).getByteList());
final Object[] objects = array.slowToArray();
final IRubyObject[] jrubyObjects = new IRubyObject[objects.length];

for (int n = 0; n < objects.length; n++) {
if (objects[n] instanceof RubyNilClass || objects[n] instanceof Integer || objects[n] instanceof Long
|| objects[n] instanceof RubyBignum || objects[n] instanceof Double || objects[n] instanceof RubyString) {
jrubyObjects[n] = getContext().toJRuby(objects[n]);
} else {
if (toStringNode == null) {
CompilerDirectives.transferToInterpreter();
toStringNode = insert(DispatchHeadNodeFactory.createMethodCall(getContext(), MissingBehavior.RETURN_MISSING));
}

final Object result = toStringNode.call(frame, objects[n], "to_str", null);

if (result == DispatchNode.MISSING) {
throw new RaiseException(getContext().getCoreLibrary().typeErrorNoImplicitConversion(objects[n], "String", this));
} else if (result instanceof RubyString) {
jrubyObjects[n] = getContext().toJRuby((RubyString) result);
} else {
throw new UnsupportedOperationException();
}
}
}

try {
return getContext().toTruffle(
org.jruby.util.Pack.pack(
getContext().getRuntime().getCurrentContext(),
getContext().getRuntime(),
getContext().getRuntime().newArray(jrubyObjects),
getContext().toJRuby(format)));
} catch (org.jruby.exceptions.RaiseException e) {
throw new RaiseException(getContext().toTruffle(e.getException(), this));
}
}

@Specialization(guards = "!isRubyString(arguments[1])")
public RubyString pack(VirtualFrame frame, RubyArray array, Object format) {
// TODO CS 1-Mar-15 sloppy until I can get @CreateCast to work

if (toStringNode == null) {
CompilerDirectives.transferToInterpreter();
toStringNode = insert(DispatchHeadNodeFactory.createMethodCall(getContext(), MissingBehavior.RETURN_MISSING));
}

final Object result = toStringNode.call(frame, format, "to_str", null);

if (result == DispatchNode.MISSING) {
throw new RaiseException(getContext().getCoreLibrary().typeErrorNoImplicitConversion(format, "String", this));
}

if (result instanceof RubyString) {
return pack(frame, array, (RubyString) result);
}

throw new UnsupportedOperationException();
}

protected boolean arrayIsLongs(RubyArray array) {
Original file line number Diff line number Diff line change
@@ -16,6 +16,10 @@
import com.oracle.truffle.api.utilities.ConditionProfile;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.cast.ToSNode;
import org.jruby.truffle.nodes.objects.IsTaintedNode;
import org.jruby.truffle.nodes.objects.IsTaintedNodeFactory;
import org.jruby.truffle.nodes.objects.TaintNode;
import org.jruby.truffle.nodes.objects.TaintNodeFactory;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyString;
@@ -27,16 +31,16 @@ public final class InterpolatedStringNode extends RubyNode {

@Children private final ToSNode[] children;

@Child private KernelNodes.TaintedNode taintedNode;
@Child private KernelNodes.TaintNode taintNode;
@Child private IsTaintedNode isTaintedNode;
@Child private TaintNode taintNode;

private final ConditionProfile taintProfile = ConditionProfile.createCountingProfile();

public InterpolatedStringNode(RubyContext context, SourceSection sourceSection, ToSNode[] children) {
super(context, sourceSection);
this.children = children;
taintedNode = KernelNodesFactory.TaintedNodeFactory.create(context, sourceSection, new RubyNode[]{});
taintNode = KernelNodesFactory.TaintNodeFactory.create(context, sourceSection, new RubyNode[]{});
isTaintedNode = IsTaintedNodeFactory.create(context, sourceSection, null);
taintNode = TaintNodeFactory.create(context, sourceSection, null);
}

@ExplodeLoop
@@ -49,7 +53,7 @@ public Object execute(VirtualFrame frame) {
for (int n = 0; n < children.length; n++) {
final RubyString toInterpolate = children[n].executeRubyString(frame);
strings[n] = toInterpolate;
tainted |= taintedNode.tainted(toInterpolate);
tainted |= isTaintedNode.isTainted(toInterpolate);
}

final RubyString string = concat(strings);
91 changes: 21 additions & 70 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/KernelNodes.java
Original file line number Diff line number Diff line change
@@ -36,10 +36,7 @@
import org.jruby.truffle.nodes.dispatch.*;
import org.jruby.truffle.nodes.globals.WrapInThreadLocalNode;
import org.jruby.truffle.nodes.literal.BooleanLiteralNode;
import org.jruby.truffle.nodes.objects.ClassNode;
import org.jruby.truffle.nodes.objects.ClassNodeFactory;
import org.jruby.truffle.nodes.objects.SingletonClassNode;
import org.jruby.truffle.nodes.objects.SingletonClassNodeFactory;
import org.jruby.truffle.nodes.objects.*;
import org.jruby.truffle.nodes.objectstorage.ReadHeadObjectFieldNode;
import org.jruby.truffle.nodes.objectstorage.WriteHeadObjectFieldNode;
import org.jruby.truffle.nodes.rubinius.ObjectPrimitiveNodes;
@@ -1991,96 +1988,50 @@ public boolean system(RubyString command) {
}

@CoreMethod(names = "taint")
public abstract static class TaintNode extends CoreMethodNode {
public abstract static class KernelTaintNode extends CoreMethodNode {

@Child private WriteHeadObjectFieldNode writeTaintNode;
@Child private TaintNode taintNode;

public TaintNode(RubyContext context, SourceSection sourceSection) {
public KernelTaintNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
writeTaintNode = new WriteHeadObjectFieldNode(RubyBasicObject.TAINTED_IDENTIFIER);
}

public TaintNode(TaintNode prev) {
public KernelTaintNode(KernelTaintNode prev) {
super(prev);
writeTaintNode = prev.writeTaintNode;
}

@Specialization
public Object taint(boolean object) {
return frozen(object);
}

@Specialization
public Object taint(int object) {
return frozen(object);
}

@Specialization
public Object taint(long object) {
return frozen(object);
}

@Specialization
public Object taint(double object) {
return frozen(object);
}

private Object frozen(Object object) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().frozenError(getContext().getCoreLibrary().getLogicalClass(object).getName(), this));
}


@Specialization
public Object taint(RubyBasicObject object) {
writeTaintNode.execute(object, true);
return object;
public Object taint(Object object) {
if (taintNode == null) {
CompilerDirectives.transferToInterpreter();
taintNode = insert(TaintNodeFactory.create(getContext(), getEncapsulatingSourceSection(), null));
}
return taintNode.executeTaint(object);
}

}

@CoreMethod(names = "tainted?")
public abstract static class TaintedNode extends CoreMethodNode {
public abstract static class KernelIsTaintedNode extends CoreMethodNode {

@Child private ReadHeadObjectFieldNode readTaintNode;
@Child private IsTaintedNode isTaintedNode;

public TaintedNode(RubyContext context, SourceSection sourceSection) {
public KernelIsTaintedNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
readTaintNode = new ReadHeadObjectFieldNode(RubyBasicObject.TAINTED_IDENTIFIER);
}

public TaintedNode(TaintedNode prev) {
public KernelIsTaintedNode(KernelIsTaintedNode prev) {
super(prev);
readTaintNode = prev.readTaintNode;
isTaintedNode = prev.isTaintedNode;
}

@Specialization
public boolean tainted(boolean object) {
return false;
}

@Specialization
public boolean tainted(int object) {
return false;
}

@Specialization
public boolean tainted(long object) {
return false;
}

@Specialization
public boolean tainted(double object) {
return false;
}

@Specialization
public boolean tainted(RubyBasicObject object) {
try {
return readTaintNode.isSet(object) && readTaintNode.executeBoolean(object);
} catch (UnexpectedResultException e) {
throw new UnsupportedOperationException(readTaintNode.execute(object).toString());
public boolean isTainted(Object object) {
if (isTaintedNode == null) {
CompilerDirectives.transferToInterpreter();
isTaintedNode = insert(IsTaintedNodeFactory.create(getContext(), getEncapsulatingSourceSection(), null));
}
return isTaintedNode.executeIsTainted(object);
}

}
Original file line number Diff line number Diff line change
@@ -77,7 +77,7 @@ public DispatchAction getDispatchAction() {

public void forceUncached() {
adoptChildren();
first.replace(new UncachedDispatchNode(context, ignoreVisibility, dispatchAction));
first.replace(new UncachedDispatchNode(context, ignoreVisibility, dispatchAction, missingBehavior));
}

}
Original file line number Diff line number Diff line change
@@ -30,7 +30,10 @@ public abstract class DispatchNode extends RubyNode {

private final DispatchAction dispatchAction;

public static final Object MISSING = new Object();
private static final class Missing {
}

public static final Object MISSING = new Missing();

public DispatchNode(RubyContext context, DispatchAction dispatchAction) {
super(context, null);
Original file line number Diff line number Diff line change
@@ -31,6 +31,7 @@
public class UncachedDispatchNode extends DispatchNode {

private final boolean ignoreVisibility;
private final MissingBehavior missingBehavior;

@Child private IndirectCallNode callNode;
@Child private ToSymbolNode toSymbolNode;
@@ -39,9 +40,10 @@ public class UncachedDispatchNode extends DispatchNode {
private final BranchProfile constantMissingProfile = BranchProfile.create();
private final BranchProfile methodMissingProfile = BranchProfile.create();

public UncachedDispatchNode(RubyContext context, boolean ignoreVisibility, DispatchAction dispatchAction) {
public UncachedDispatchNode(RubyContext context, boolean ignoreVisibility, DispatchAction dispatchAction, MissingBehavior missingBehavior) {
super(context, dispatchAction);
this.ignoreVisibility = ignoreVisibility;
this.missingBehavior = missingBehavior;
callNode = Truffle.getRuntime().createIndirectCallNode();
toSymbolNode = ToSymbolNodeFactory.create(context, null, null);
toJavaStringNode = ToJavaStringNodeFactory.create(context, null, null);
@@ -109,6 +111,10 @@ public Object executeDispatch(
}
}

if (dispatchAction == DispatchAction.CALL_METHOD && missingBehavior == MissingBehavior.RETURN_MISSING) {
return DispatchNode.MISSING;
}

methodMissingProfile.enter();

final InternalMethod missingMethod = lookup(callerClass, receiverObject, "method_missing", true);
Original file line number Diff line number Diff line change
@@ -60,7 +60,7 @@ public Object executeDispatch(

if (depth == Options.TRUFFLE_DISPATCH_POLYMORPHIC_MAX.load()) {
return getHeadNode().getFirstDispatchNode()
.replace(new UncachedDispatchNode(getContext(), ignoreVisibility, getDispatchAction()))
.replace(new UncachedDispatchNode(getContext(), ignoreVisibility, getDispatchAction(), missingBehavior))
.executeDispatch(frame, receiverObject,
methodName, blockObject, argumentsObjects);
}
@@ -247,7 +247,7 @@ private DispatchNode createConstantMissingNode(
}

if (Options.TRUFFLE_DISPATCH_METAPROGRAMMING_ALWAYS_UNCACHED.load()) {
return first.replace(new UncachedDispatchNode(getContext(), ignoreVisibility, getDispatchAction()));
return first.replace(new UncachedDispatchNode(getContext(), ignoreVisibility, getDispatchAction(), missingBehavior));
}

return first.replace(new CachedBoxedMethodMissingDispatchNode(getContext(), methodName, first,
@@ -280,7 +280,7 @@ private DispatchNode createMethodMissingNode(
}

if (Options.TRUFFLE_DISPATCH_METAPROGRAMMING_ALWAYS_UNCACHED.load()) {
return first.replace(new UncachedDispatchNode(getContext(), ignoreVisibility, getDispatchAction()));
return first.replace(new UncachedDispatchNode(getContext(), ignoreVisibility, getDispatchAction(), missingBehavior));
}

return first.replace(new CachedBoxedMethodMissingDispatchNode(getContext(), methodName, first,
Original file line number Diff line number Diff line change
@@ -157,7 +157,11 @@ public RubyException translate(Throwable throwable) {
DebugOperations.panic(getContext(), this, throwable.toString());
}

return getContext().getCoreLibrary().internalError(String.format("%s %s %s", throwable.getClass().getSimpleName(), throwable.getMessage(), throwable.getStackTrace()[0].toString()), this);
if (throwable.getStackTrace().length > 0) {
return getContext().getCoreLibrary().internalError(String.format("%s %s %s", throwable.getClass().getSimpleName(), throwable.getMessage(), throwable.getStackTrace()[0].toString()), this);
} else {
return getContext().getCoreLibrary().internalError(String.format("%s %s ???", throwable.getClass().getSimpleName(), throwable.getMessage()), this);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* 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.nodes.objects;

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.nodes.UnexpectedResultException;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.objectstorage.ReadHeadObjectFieldNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyBasicObject;

@NodeChild(value = "child", type = RubyNode.class)
public abstract class IsTaintedNode extends RubyNode {

@Child private ReadHeadObjectFieldNode readTaintNode;

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

public IsTaintedNode(IsTaintedNode prev) {
super(prev);
readTaintNode = prev.readTaintNode;
}

public abstract boolean executeIsTainted(Object object);

@Specialization
public boolean isTainted(boolean object) {
return false;
}

@Specialization
public boolean isTainted(int object) {
return false;
}

@Specialization
public boolean isTainted(long object) {
return false;
}

@Specialization
public boolean isTainted(double object) {
return false;
}

@Specialization
public boolean isTainted(RubyBasicObject object) {
if (readTaintNode == null) {
CompilerDirectives.transferToInterpreter();
readTaintNode = insert(new ReadHeadObjectFieldNode(RubyBasicObject.TAINTED_IDENTIFIER));
}

try {
return readTaintNode.isSet(object) && readTaintNode.executeBoolean(object);
} catch (UnexpectedResultException e) {
throw new UnsupportedOperationException(readTaintNode.execute(object).toString());
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* 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.nodes.objects;

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.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.objectstorage.WriteHeadObjectFieldNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyBasicObject;

@NodeChild(value = "child", type = RubyNode.class)
public abstract class TaintNode extends RubyNode {

@Child private WriteHeadObjectFieldNode writeTaintNode;

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

public TaintNode(TaintNode prev) {
super(prev);
writeTaintNode = prev.writeTaintNode;
}

public abstract Object executeTaint(Object object);

@Specialization
public Object taint(boolean object) {
return frozen(object);
}

@Specialization
public Object taint(int object) {
return frozen(object);
}

@Specialization
public Object taint(long object) {
return frozen(object);
}

@Specialization
public Object taint(double object) {
return frozen(object);
}

@Specialization
public Object taint(RubyBasicObject object) {
if (writeTaintNode == null) {
CompilerDirectives.transferToInterpreter();
writeTaintNode = insert(new WriteHeadObjectFieldNode(RubyBasicObject.TAINTED_IDENTIFIER));
}
writeTaintNode.execute(object, true);
return object;
}

private Object frozen(Object object) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().frozenError(getContext().getCoreLibrary().getLogicalClass(object).getName(), this));
}

}
31 changes: 28 additions & 3 deletions truffle/src/main/java/org/jruby/truffle/runtime/RubyContext.java
Original file line number Diff line number Diff line change
@@ -333,7 +333,15 @@ public org.jruby.RubyArray toJRuby(RubyArray array) {
}

public org.jruby.RubyString toJRuby(RubyString string) {
return runtime.newString(string.getBytes().dup());
final org.jruby.RubyString jrubyString = runtime.newString(string.getBytes().dup());

final Object tainted = string.getOperations().getInstanceVariable(string, RubyBasicObject.TAINTED_IDENTIFIER);

if (tainted instanceof Boolean && (boolean) tainted) {
jrubyString.setTaint(true);
}

return jrubyString;
}

public Object toTruffle(IRubyObject object) {
@@ -373,13 +381,30 @@ public Object toTruffle(IRubyObject object) {
}

return new RubyArray(coreLibrary.getArrayClass(), truffleArray, truffleArray.length);
} else if (object instanceof org.jruby.RubyException) {
return toTruffle((org.jruby.RubyException) object, null);
} else {
throw object.getRuntime().newRuntimeError("cannot pass " + object.inspect() + " to Truffle");
}
}

public RubyString toTruffle(org.jruby.RubyString string) {
return new RubyString(getCoreLibrary().getStringClass(), string.getByteList().dup());
public RubyString toTruffle(org.jruby.RubyString jrubyString) {
final RubyString truffleString = new RubyString(getCoreLibrary().getStringClass(), jrubyString.getByteList().dup());

if (jrubyString.isTaint()) {
truffleString.getOperations().setInstanceVariable(truffleString, RubyBasicObject.TAINTED_IDENTIFIER, true);
}

return truffleString;
}

public RubyException toTruffle(org.jruby.RubyException jrubyException, RubyNode currentNode) {
switch (jrubyException.getMetaClass().getName()) {
case "ArgumentError":
return getCoreLibrary().argumentError(jrubyException.getMessage().toString(), currentNode);
}

throw new UnsupportedOperationException("Don't know how to translate " + jrubyException.getMetaClass().getName());
}

public Ruby getRuntime() {