Skip to content

Commit

Permalink
Showing 108 changed files with 2,700 additions and 580 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -94,11 +94,12 @@ nbproject/private
# Eclipse files
/.metadata
/.recommenders
core/.apt_generated
core/.classpath
core/.gitignore
core/.project
core/.settings
core/.apt_generated
core/build.eclipse

# Truffle findbugs
truffle-findbugs-report.html
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/RubyTime.java
Original file line number Diff line number Diff line change
@@ -151,7 +151,7 @@ public static DateTimeZone getLocalTimeZone(Ruby runtime) {
}
}

private static DateTimeZone getTimeZoneFromTZString(Ruby runtime, String zone) {
public static DateTimeZone getTimeZoneFromTZString(Ruby runtime, String zone) {
DateTimeZone cachedZone = runtime.getTimezoneCache().get(zone);
if (cachedZone != null) {
return cachedZone;
9 changes: 8 additions & 1 deletion core/src/main/java/org/jruby/ir/IRBuilder.java
Original file line number Diff line number Diff line change
@@ -1034,7 +1034,14 @@ public Operand buildCase(CaseNode caseNode, IRScope s) {
Variable eqqResult = s.createTemporaryVariable();
labels.add(bodyLabel);
Operand v1, v2;
if (whenNode.getExpressionNodes() instanceof ListNode) {
if (whenNode.getExpressionNodes() instanceof DNode) {
// DNode produces a proper result, so we don't want the special ListNode handling below
// FIXME: This is obviously gross, and we need a better way to filter out non-expression ListNode here
// See GH #2423
s.addInstr(new EQQInstr(eqqResult, build(whenNode.getExpressionNodes(), s), value));
v1 = eqqResult;
v2 = manager.getTrue();
} else if (whenNode.getExpressionNodes() instanceof ListNode) {
// Note about refactoring:
// - BEQInstr has a quick implementation when the second operand is a boolean literal
// If it can be fixed to do this even on the first operand, we can switch around
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/ir/IRClosure.java
Original file line number Diff line number Diff line change
@@ -195,7 +195,7 @@ public void addInstr(Instr i) {
// FIXME: This lost encoding information when name was converted to string earlier in IRBuilder
keywordArgs.add(new KeyValuePair<Operand, Operand>(new Symbol(rkai.argName, USASCIIEncoding.INSTANCE), rkai.getResult()));
} else if (i instanceof ReceiveRestArgInstr) {
blockArgs.add(new Splat(((ReceiveRestArgInstr)i).getResult()));
blockArgs.add(new Splat(((ReceiveRestArgInstr)i).getResult(), true));
} else if (i instanceof ReceiveArgBase) {
blockArgs.add(((ReceiveArgBase) i).getResult());
}
Original file line number Diff line number Diff line change
@@ -92,7 +92,6 @@ public void init() {
CoreMethodNodeManager.addCoreMethodNodes(rubyObjectClass, StringNodesFactory.getFactories());
CoreMethodNodeManager.addCoreMethodNodes(rubyObjectClass, SymbolNodesFactory.getFactories());
CoreMethodNodeManager.addCoreMethodNodes(rubyObjectClass, ThreadNodesFactory.getFactories());
CoreMethodNodeManager.addCoreMethodNodes(rubyObjectClass, TimeNodesFactory.getFactories());
CoreMethodNodeManager.addCoreMethodNodes(rubyObjectClass, TrueClassNodesFactory.getFactories());
CoreMethodNodeManager.addCoreMethodNodes(rubyObjectClass, TruffleDebugNodesFactory.getFactories());
CoreMethodNodeManager.addCoreMethodNodes(rubyObjectClass, TrufflePrimitiveNodesFactory.getFactories());
Original file line number Diff line number Diff line change
@@ -82,7 +82,7 @@ public RubyCallNode(RubyContext context, SourceSection section, String methodNam
this.isSplatted = isSplatted;
this.isVCall = isVCall;

dispatchHead = new DispatchHeadNode(context, ignoreVisibility, false, rubiniusPrimitive, Dispatch.MissingBehavior.CALL_METHOD_MISSING);
dispatchHead = new DispatchHeadNode(context, ignoreVisibility, false, Dispatch.MissingBehavior.CALL_METHOD_MISSING);
respondToMissing = new DispatchHeadNode(context, true, Dispatch.MissingBehavior.RETURN_MISSING);
respondToMissingCast = BooleanCastNodeFactory.create(context, section, null);

Original file line number Diff line number Diff line change
@@ -314,7 +314,7 @@ public abstract static class SendNode extends CoreMethodNode {
public SendNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);

dispatchNode = new DispatchHeadNode(context, true, Options.TRUFFLE_DISPATCH_METAPROGRAMMING_ALWAYS_INDIRECT.load(), false, Dispatch.MissingBehavior.CALL_METHOD_MISSING);
dispatchNode = new DispatchHeadNode(context, true, Options.TRUFFLE_DISPATCH_METAPROGRAMMING_ALWAYS_INDIRECT.load(), Dispatch.MissingBehavior.CALL_METHOD_MISSING);

if (Options.TRUFFLE_DISPATCH_METAPROGRAMMING_ALWAYS_UNCACHED.load()) {
dispatchNode.forceUncached();
104 changes: 73 additions & 31 deletions core/src/main/java/org/jruby/truffle/nodes/core/BignumNodes.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This
* Copyright (c) 2013, 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:
*
@@ -191,7 +191,7 @@ public RubyBignum pow(RubyBignum a, RubyBignum b) {

}

@CoreMethod(names = "/", required = 1)
@CoreMethod(names = {"/", "__slash__"}, required = 1)
public abstract static class DivNode extends BignumCoreMethodNode {

public DivNode(RubyContext context, SourceSection sourceSection) {
@@ -245,36 +245,9 @@ public Object mod(RubyBignum a, long b) {
return fixnumOrBignum(a.mod(b));
}

}

@CoreMethod(names = "divmod", required = 1)
public abstract static class DivModNode extends CoreMethodNode {

@Child protected GeneralDivModNode divModNode;

public DivModNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
divModNode = new GeneralDivModNode(context, sourceSection);
}

public DivModNode(DivModNode prev) {
super(prev);
divModNode = prev.divModNode;
}

@Specialization
public RubyArray divMod(RubyBignum a, int b) {
return divModNode.execute(a, b);
}

@Specialization
public RubyArray divMod(RubyBignum a, long b) {
return divModNode.execute(a, b);
}

@Specialization
public RubyArray divMod(RubyBignum a, RubyBignum b) {
return divModNode.execute(a, b);
public Object mod(RubyBignum a, RubyBignum b) {
return fixnumOrBignum(a.mod(b));
}

}
@@ -602,6 +575,75 @@ public Object leftShift(RubyBignum a, int b) {

}

@CoreMethod(names = "abs")
public abstract static class AbsNode extends BignumCoreMethodNode {

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

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

@Specialization
public RubyBignum abs(RubyBignum value) {
return value.abs();
}

}

@CoreMethod(names = "even?")
public abstract static class EvenNode extends BignumCoreMethodNode {

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

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

@CompilerDirectives.TruffleBoundary
@Specialization
public boolean even(RubyBignum value) {
return value.bigIntegerValue().getLowestSetBit() != 0;
}

}

@CoreMethod(names = "divmod", required = 1)
public abstract static class DivModNode extends CoreMethodNode {

@Child protected GeneralDivModNode divModNode;

public DivModNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
divModNode = new GeneralDivModNode(context, sourceSection);
}

public DivModNode(DivModNode prev) {
super(prev);
divModNode = prev.divModNode;
}

@Specialization
public RubyArray divMod(RubyBignum a, int b) {
return divModNode.execute(a, b);
}

@Specialization
public RubyArray divMod(RubyBignum a, long b) {
return divModNode.execute(a, b);
}

@Specialization
public RubyArray divMod(RubyBignum a, RubyBignum b) {
return divModNode.execute(a, b);
}

}

@CoreMethod(names = {"to_s", "inspect"})
public abstract static class ToSNode extends CoreMethodNode {

50 changes: 48 additions & 2 deletions core/src/main/java/org/jruby/truffle/nodes/core/FixnumNodes.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This
* Copyright (c) 2013, 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:
*
@@ -21,6 +21,8 @@
import org.jruby.truffle.runtime.core.RubyBignum;
import org.jruby.truffle.runtime.core.RubyString;

import java.math.BigInteger;

@CoreClass(name = "Fixnum")
public abstract class FixnumNodes {

@@ -319,7 +321,7 @@ protected static boolean canShiftIntoInt(int a, int b) {

}

@CoreMethod(names = "/", required = 1)
@CoreMethod(names = {"/", "__slash__"}, required = 1)
public abstract static class DivNode extends CoreMethodNode {

private final BranchProfile bGreaterZero = BranchProfile.create();
@@ -545,6 +547,27 @@ public long mod(long a, long b) {
return mod;
}

@Specialization
public Object mod(int a, RubyBignum b) {
return mod((long) a, b);
}

@Specialization
public Object mod(long a, RubyBignum b) {
notDesignedForCompilation();

// TODO(CS): why are we getting this case?

long mod = BigInteger.valueOf(a).mod(b.bigIntegerValue()).longValue();

if (mod < 0 && b.bigIntegerValue().compareTo(BigInteger.ZERO) > 0 || mod > 0 && b.bigIntegerValue().compareTo(BigInteger.ZERO) < 0) {
adjustProfile.enter();
return new RubyBignum(getContext().getCoreLibrary().getBignumClass(), BigInteger.valueOf(mod).add(b.bigIntegerValue()));
}

return mod;
}

}

@CoreMethod(names = "divmod", required = 1)
@@ -1231,6 +1254,29 @@ public long abs(long n) {

}

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

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

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

@Specialization
public int floor(int n) {
return n;
}

@Specialization
public long floor(long n) {
return n;
}

}

@CoreMethod(names = "size", needsSelf = false)
public abstract static class SizeNode extends CoreMethodNode {

44 changes: 42 additions & 2 deletions core/src/main/java/org/jruby/truffle/nodes/core/FloatNodes.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This
* Copyright (c) 2013, 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:
*
@@ -171,7 +171,7 @@ public double pow(double a, RubyBignum b) {

}

@CoreMethod(names = "/", required = 1)
@CoreMethod(names = {"/", "__slash__"}, required = 1)
public abstract static class DivNode extends CoreMethodNode {

public DivNode(RubyContext context, SourceSection sourceSection) {
@@ -507,6 +507,46 @@ public double abs(double n) {

}

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

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

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

@Specialization
public double ceil(double n) {
return Math.ceil(n);
}

}

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

@Child protected FixnumOrBignumNode fixnumOrBignum;

public FloorNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
fixnumOrBignum = new FixnumOrBignumNode(context, sourceSection);
}

public FloorNode(FloorNode prev) {
super(prev);
fixnumOrBignum = prev.fixnumOrBignum;
}

@Specialization
public Object floor(double n) {
return fixnumOrBignum.fixnumOrBignum(Math.floor(n));
}

}

@CoreMethod(names = "infinite?")
public abstract static class InfiniteNode extends CoreMethodNode {

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This
* Copyright (c) 2013, 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:
*
@@ -376,7 +376,7 @@ public ClassNode(ClassNode prev) {
super(prev);
}

public abstract RubyClass executeGetClass(VirtualFrame frame, Object value);
public abstract RubyClass executeGetClass(Object value);

@Specialization
public RubyClass getClass(boolean value) {
@@ -1673,6 +1673,8 @@ public RespondToNode(RespondToNode prev) {
dispatchIgnoreVisibility = prev.dispatchIgnoreVisibility;
}

public abstract boolean executeDoesRespondTo(VirtualFrame frame, Object object, Object name, boolean includePrivate);

@Specialization
public boolean doesRespondTo(VirtualFrame frame, Object object, RubyString name, UndefinedPlaceholder checkVisibility) {
return dispatch.doesRespondTo(frame, name, object);
@@ -1700,7 +1702,6 @@ public boolean doesRespondTo(VirtualFrame frame, Object object, RubySymbol name,
return dispatch.doesRespondTo(frame, name, object);
}
}

}

@CoreMethod(names = "respond_to_missing?", required = 1, optional = 1, visibility = Visibility.PRIVATE)
@@ -2154,7 +2155,7 @@ public ToSNode(RubyContext context, SourceSection sourceSection) {
public RubyString toS(VirtualFrame frame, Object self) {
notDesignedForCompilation();

String className = classNode.executeGetClass(frame, self).getName();
String className = classNode.executeGetClass(self).getName();

if (className == null) {
className = "Class";
12 changes: 9 additions & 3 deletions core/src/main/java/org/jruby/truffle/nodes/core/ModuleNodes.java
Original file line number Diff line number Diff line change
@@ -19,6 +19,8 @@
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;

import org.jcodings.Encoding;
import org.jruby.runtime.Visibility;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.RubyRootNode;
@@ -400,23 +402,27 @@ public Object classEval(VirtualFrame frame, RubyModule module, RubyString code,
notDesignedForCompilation();

final Source source = Source.fromText(code.getBytes(), "(eval)");
return getContext().execute(getContext(), source, code.getBytes().getEncoding(), TranslatorDriver.ParserContext.MODULE, module, frame.materialize(), this);
return classEvalSource(frame, module, source, code.getBytes().getEncoding());
}

@Specialization
public Object classEval(VirtualFrame frame, RubyModule module, RubyString code, RubyString file, @SuppressWarnings("unused") UndefinedPlaceholder line, @SuppressWarnings("unused") UndefinedPlaceholder block) {
notDesignedForCompilation();

final Source source = Source.asPseudoFile(code.getBytes(), file.toString());
return getContext().execute(getContext(), source, code.getBytes().getEncoding(), TranslatorDriver.ParserContext.MODULE, module, frame.materialize(), this);
return classEvalSource(frame, module, source, code.getBytes().getEncoding());
}

@Specialization
public Object classEval(VirtualFrame frame, RubyModule module, RubyString code, RubyString file, @SuppressWarnings("unused") int line, @SuppressWarnings("unused") UndefinedPlaceholder block) {
notDesignedForCompilation();

final Source source = Source.asPseudoFile(code.getBytes(), file.toString());
return getContext().execute(getContext(), source, code.getBytes().getEncoding(), TranslatorDriver.ParserContext.MODULE, module, frame.materialize(), this);
return classEvalSource(frame, module, source, code.getBytes().getEncoding());
}

private Object classEvalSource(VirtualFrame frame, RubyModule module, Source source, Encoding encoding) {
return getContext().execute(getContext(), source, encoding, TranslatorDriver.ParserContext.MODULE, module, frame.materialize(), this);
}

@Specialization
171 changes: 0 additions & 171 deletions core/src/main/java/org/jruby/truffle/nodes/core/TimeNodes.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -23,7 +23,6 @@ public class DispatchHeadNode extends Node {
private final RubyContext context;
private final boolean ignoreVisibility;
private final boolean indirect;
private final boolean rubiniusPrimitive;
private final Dispatch.MissingBehavior missingBehavior;

@Child protected DispatchNode first;
@@ -33,27 +32,26 @@ public static DispatchHeadNode onSelf(RubyContext context) {
}

public DispatchHeadNode(RubyContext context) {
this(context, false, false, false, Dispatch.MissingBehavior.CALL_METHOD_MISSING);
this(context, false, false, Dispatch.MissingBehavior.CALL_METHOD_MISSING);
}

public DispatchHeadNode(RubyContext context, boolean ignoreVisibility) {
this(context, ignoreVisibility, Dispatch.MissingBehavior.CALL_METHOD_MISSING);
}

public DispatchHeadNode(RubyContext context, Dispatch.MissingBehavior missingBehavior) {
this(context, false, false, false, missingBehavior);
this(context, false, false, missingBehavior);
}

public DispatchHeadNode(RubyContext context, boolean ignoreVisibility, Dispatch.MissingBehavior missingBehavior) {
this(context, ignoreVisibility, false, false, missingBehavior);
this(context, ignoreVisibility, false, missingBehavior);
}

public DispatchHeadNode(RubyContext context, boolean ignoreVisibility, boolean indirect, boolean rubiniusPrimitive, Dispatch.MissingBehavior missingBehavior) {
public DispatchHeadNode(RubyContext context, boolean ignoreVisibility, boolean indirect, Dispatch.MissingBehavior missingBehavior) {
this.context = context;
this.ignoreVisibility = ignoreVisibility;
this.indirect = indirect;
this.missingBehavior = missingBehavior;
this.rubiniusPrimitive = rubiniusPrimitive;
first = new UnresolvedDispatchNode(context, ignoreVisibility, indirect, missingBehavior);
}

@@ -147,6 +145,7 @@ public boolean doesRespondTo(
VirtualFrame frame,
Object methodName,
Object receiverObject) {
// It's ok to cast here as we control what RESPOND_TO_METHOD returns
return (boolean) dispatch(
frame,
null, // TODO(eregon): was RubyArguments.getSelf(frame.getArguments()),
@@ -165,25 +164,14 @@ public Object dispatch(
Object blockObject,
Object argumentsObjects,
Dispatch.DispatchAction dispatchAction) {
if (rubiniusPrimitive) {
return first.executeDispatch(
frame,
lexicalScope,
RubyArguments.getSelf(frame.getArguments()),
methodName,
blockObject,
RubyArguments.concatUserArguments(argumentsObjects, frame.getArguments()),
dispatchAction);
} else {
return first.executeDispatch(
frame,
lexicalScope,
receiverObject,
methodName,
blockObject,
argumentsObjects,
dispatchAction);
}
return first.executeDispatch(
frame,
lexicalScope,
receiverObject,
methodName,
blockObject,
argumentsObjects,
dispatchAction);
}

public void reset(String reason) {
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* 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.rubinius;

import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.utilities.ConditionProfile;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.ReturnException;

/**
* Node which wraps a {@link RubiniusPrimitiveNode}, providing the implicit control flow that you get with calls to
* Rubinius primitives.
*/
public class CallRubiniusPrimitiveNode extends RubyNode {

@Child protected RubyNode primitive;
private final long returnID;

private final ConditionProfile primitiveSucceededCondition = ConditionProfile.createBinaryProfile();

public CallRubiniusPrimitiveNode(RubyContext context, SourceSection sourceSection, RubyNode primitive, long returnID) {
super(context, sourceSection);
this.primitive = primitive;
this.returnID = returnID;
}

@Override
public void executeVoid(VirtualFrame frame) {
final Object value = primitive.execute(frame);

if (primitiveSucceededCondition.profile(value != null)) {
// If the primitive didn't fail its value is returned in the calling method

throw new ReturnException(returnID, value);
}

// Primitives may return null to indicate that they have failed, in which case we continue with the fallback
}

@Override
public Object execute(VirtualFrame frame) {
executeVoid(frame);
return getContext().getCoreLibrary().getNilObject();
}

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

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface RubiniusPrimitive {

String name();

boolean needsSelf() default true;

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

import com.oracle.truffle.api.dsl.NodeFactory;
import org.jruby.truffle.nodes.RubyNode;

/**
* Packages up the original {@link RubiniusPrimitive annotation} with the {@link NodeFactory}.
*/
public class RubiniusPrimitiveConstructor {

private final RubiniusPrimitive annotation;
private final NodeFactory<? extends RubyNode> factory;

public RubiniusPrimitiveConstructor(RubiniusPrimitive annotation, NodeFactory<? extends RubyNode> factory) {
this.annotation = annotation;
this.factory = factory;
}

public RubiniusPrimitive getAnnotation() {
return annotation;
}

public NodeFactory<? extends RubyNode> getFactory() {
return factory;
}

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

import com.oracle.truffle.api.dsl.GeneratedBy;
import com.oracle.truffle.api.dsl.NodeFactory;
import org.jruby.truffle.nodes.RubyNode;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* Manages the available Rubinius primitive calls.
*/
public class RubiniusPrimitiveManager {

private final Map<String, RubiniusPrimitiveConstructor> primitives;

private RubiniusPrimitiveManager(Map<String, RubiniusPrimitiveConstructor> primitives) {
this.primitives = primitives;
}

public RubiniusPrimitiveConstructor getPrimitive(String name) {
final RubiniusPrimitiveConstructor constructor = primitives.get(name);

if (constructor == null) {
throw new RuntimeException(String.format("Rubinius primitive %s not found", name));
}

return constructor;
}

public static RubiniusPrimitiveManager create() {
final List<NodeFactory<? extends RubyNode>> nodeFactories = new ArrayList<>();

nodeFactories.addAll(TimePrimitiveNodesFactory.getFactories());
nodeFactories.addAll(TypePrimitiveNodesFactory.getFactories());
nodeFactories.addAll(StringPrimitiveNodesFactory.getFactories());

final Map<String, RubiniusPrimitiveConstructor> primitives = new HashMap<>();

for (NodeFactory<? extends RubyNode> nodeFactory : nodeFactories) {
final GeneratedBy generatedBy = nodeFactory.getClass().getAnnotation(GeneratedBy.class);
final Class<?> nodeClass = generatedBy.value();
final RubiniusPrimitive annotation = nodeClass.getAnnotation(RubiniusPrimitive.class);
primitives.put(annotation.name(), new RubiniusPrimitiveConstructor(annotation, nodeFactory));
}

return new RubiniusPrimitiveManager(primitives);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2013, 2014 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.rubinius;

import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyContext;

@NodeChild(value = "arguments", type = RubyNode[].class)
public abstract class RubiniusPrimitiveNode extends RubyNode {

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

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

}
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.rubinius;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import com.oracle.truffle.api.source.SourceSection;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.jruby.truffle.nodes.cast.BooleanCastNode;
import org.jruby.truffle.nodes.cast.BooleanCastNodeFactory;
import org.jruby.truffle.nodes.objectstorage.ReadHeadObjectFieldNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyTime;
import org.jruby.truffle.runtime.core.TimeOperations;

/**
* Supports {@link TimePrimitiveNodes} by converting a {@link RubyTime} to a {@link DateTime}. We use a node because
* doing this requires accessing instance variables, which we want to use an inline cache for.
*/
class RubyTimeToDateTimeNode extends Node {

private final RubyContext context;

@Child protected ReadHeadObjectFieldNode readIsGMTNode = new ReadHeadObjectFieldNode("@is_gmt");
@Child protected ReadHeadObjectFieldNode readOffsetNode = new ReadHeadObjectFieldNode("@offset");

public RubyTimeToDateTimeNode(RubyContext context, SourceSection sourceSection) {
this.context = context;
}

public DateTime toDateTime(VirtualFrame frame, RubyTime time) {
final Object isGMTObject = readIsGMTNode.execute(time);

// The @is_gmt instance variable is only for internal use so we don't need a full cast here

final boolean isGMT;

if (isGMTObject instanceof Boolean && ((boolean) isGMTObject)) {
isGMT = true;
} else {
isGMT = false;
}

return toDateTime(time.getSeconds(),
time.getNanoseconds(),
isGMT,
readOffsetNode.execute(time));
}

@CompilerDirectives.TruffleBoundary
private DateTime toDateTime(long seconds, long nanoseconds, boolean isGMT, Object offset) {
final DateTimeZone dateTimeZone;

if (isGMT) {
dateTimeZone = DateTimeZone.UTC;
} else {
dateTimeZone = org.jruby.RubyTime.getLocalTimeZone(context.getRuntime());
}

return new DateTime(TimeOperations.secondsAndNanosecondsToMiliseconds(seconds, nanoseconds), dateTimeZone);
}

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

import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.utilities.ConditionProfile;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.*;

/**
* Rubinius primitives associated with the Ruby {@code String} class.
*/
public abstract class StringPrimitiveNodes {

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

private final ConditionProfile nullByteProfile = ConditionProfile.createBinaryProfile();

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

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

@Specialization
public boolean stringCheckNullSafe(RubyString string) {
for (byte b : string.getBytes().unsafeBytes()) {
if (nullByteProfile.profile(b == 0)) {
return false;
}
}

return true;
}

}

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

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

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

@Specialization
public RubyString stringToF(RubyString string) {
throw new UnsupportedOperationException("string_to_f");
}

}

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

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;
import org.joda.time.DateTime;
import org.jruby.truffle.nodes.objectstorage.ReadHeadObjectFieldNode;
import org.jruby.truffle.nodes.objectstorage.WriteHeadObjectFieldNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.*;
import org.jruby.util.ByteList;
import org.jruby.util.RubyDateFormatter;

/**
* Rubinius primitives associated with the Ruby {@code Time} class.
* <p>
* Also see {@link RubyTime}.
*/
public abstract class TimePrimitiveNodes {

@RubiniusPrimitive(name = "time_s_now")
public static abstract class TimeSNowPrimitiveNode extends RubiniusPrimitiveNode {

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

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

@Specialization
public RubyTime timeSNow(RubyClass timeClass) {
final long milliseconds = System.currentTimeMillis();
return new RubyTime(timeClass,
TimeOperations.millisecondsToSeconds(milliseconds),
TimeOperations.millisecondsToNanoseconds(TimeOperations.millisecondsInCurrentSecond(milliseconds)));
}

}

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

@Child protected ReadHeadObjectFieldNode readIsGMTNode = new ReadHeadObjectFieldNode("@is_gmt");
@Child protected ReadHeadObjectFieldNode readOffsetNode = new ReadHeadObjectFieldNode("@offset");

@Child protected WriteHeadObjectFieldNode writeIsGMTNode = new WriteHeadObjectFieldNode("@is_gmt");
@Child protected WriteHeadObjectFieldNode writeOffsetNode = new WriteHeadObjectFieldNode("@offset");

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

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

@Specialization
public RubyTime timeSDup(RubyTime other) {
final RubyTime time = new RubyTime(getContext().getCoreLibrary().getTimeClass(), other.getSeconds(), other.getNanoseconds());
writeIsGMTNode.execute(time, readIsGMTNode.execute(other));
writeOffsetNode.execute(time, readOffsetNode.execute(other));
return time;
}

}

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

@Child protected WriteHeadObjectFieldNode writeIsGMTNode = new WriteHeadObjectFieldNode("@is_gmt");
@Child protected WriteHeadObjectFieldNode writeOffsetNode = new WriteHeadObjectFieldNode("@offset");

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

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

@Specialization
public RubyTime timeSSpecific(int seconds, int nanoseconds, Object isGMT, Object offset) {
return timeSSpecific((long) seconds, (long) nanoseconds, isGMT, offset);
}

@Specialization
public RubyTime timeSSpecific(long seconds, int nanoseconds, Object isGMT, Object offset) {
return timeSSpecific(seconds, (long) nanoseconds, isGMT, offset);
}

@Specialization
public RubyTime timeSSpecific(int seconds, long nanoseconds, Object isGMT, Object offset) {
return timeSSpecific((long) seconds, nanoseconds, isGMT, offset);
}

@Specialization
public RubyTime timeSSpecific(long seconds, long nanoseconds, Object isGMT, Object offset) {
// TODO(CS): overflow checks here in Rbx
final RubyTime time = new RubyTime(getContext().getCoreLibrary().getTimeClass(), seconds, nanoseconds);
writeIsGMTNode.execute(time, isGMT);
writeOffsetNode.execute(time, offset);
return time;
}

}

@RubiniusPrimitive(name = "time_seconds")
public static abstract class TimeSecondsPrimitiveNode extends RubiniusPrimitiveNode {

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

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

@Specialization
public long timeSeconds(RubyTime time) {
return time.getSeconds();
}

}

@RubiniusPrimitive(name = "time_useconds")
public static abstract class TimeUSecondsPrimitiveNode extends RubiniusPrimitiveNode {

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

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

@Specialization
public long timeUSeconds(RubyTime time) {
return time.getNanoseconds();
}

}

@RubiniusPrimitive(name = "time_decompose")
public static abstract class TimeDecomposePrimitiveNode extends RubiniusPrimitiveNode {

@Child protected RubyTimeToDateTimeNode toDateTimeNode;

public TimeDecomposePrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
toDateTimeNode = new RubyTimeToDateTimeNode(context, sourceSection);
}

public TimeDecomposePrimitiveNode(TimeDecomposePrimitiveNode prev) {
super(prev);
toDateTimeNode = prev.toDateTimeNode;
}

@Specialization
public RubyArray timeDecompose(VirtualFrame frame, RubyTime time) {
final DateTime dateTime = toDateTimeNode.toDateTime(frame, time);
final Object[] decomposed = decompose(dateTime);
return new RubyArray(getContext().getCoreLibrary().getArrayClass(), decomposed, decomposed.length);
}

@CompilerDirectives.TruffleBoundary
public Object[] decompose(DateTime dateTime) {
final int sec = dateTime.getSecondOfMinute();
final int min = dateTime.getMinuteOfDay();
final int hour = dateTime.getHourOfDay();
final int day = dateTime.getDayOfMonth();
final int month = dateTime.getMonthOfYear();
final int year = dateTime.getYear();
final int wday = dateTime.getDayOfWeek();
final int yday = dateTime.getDayOfYear();
final Object isdst = getContext().getCoreLibrary().getNilObject();
final Object zone = getContext().getCoreLibrary().getNilObject();
return new Object[]{sec, min, hour, day, month, year, wday, yday, isdst, zone};
}

}

@RubiniusPrimitive(name = "time_strftime")
public static abstract class TimeStrftimePrimitiveNode extends RubiniusPrimitiveNode {

@Child protected RubyTimeToDateTimeNode toDateTimeNode;

public TimeStrftimePrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
toDateTimeNode = new RubyTimeToDateTimeNode(context, sourceSection);
}

public TimeStrftimePrimitiveNode(TimeStrftimePrimitiveNode prev) {
super(prev);
toDateTimeNode = prev.toDateTimeNode;
}

@Specialization
public RubyString timeStrftime(VirtualFrame frame, RubyTime time, RubyString format) {
return getContext().makeString(format(toDateTimeNode.toDateTime(frame, time), time.getNanoseconds(), format.getBytes()));
}


@CompilerDirectives.TruffleBoundary
public ByteList format(DateTime time, long nanoseconds, ByteList format) {
// TODO: converts everything to JRuby objects and back - should find a more direct way using ByteList
final RubyDateFormatter rdf = getContext().getRuntime().getCurrentContext().getRubyDateFormatter();
return rdf.compileAndFormat(org.jruby.RubyString.newString(getContext().getRuntime(), format), false, time, nanoseconds, null).getByteList();
}

}

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

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

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

@Specialization
public RubyTime timeSFromArray(Object sec, Object min, Object hour, Object mday, Object month, Object year,
Object nsec, Object isdst, Object fromgmt, Object utcoffset) {
throw new UnsupportedOperationException("time_s_from_array");
}

}

@RubiniusPrimitive(name = "time_nseconds")
public static abstract class TimeNSecondsPrimitiveNode extends RubiniusPrimitiveNode {

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

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

@Specialization
public long timeNSeconds(RubyTime time) {
return time.getNanoseconds();
}

}

@RubiniusPrimitive(name = "time_set_nseconds")
public static abstract class TimeSetNSecondsPrimitiveNode extends RubiniusPrimitiveNode {

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

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

@Specialization
public long timeSetNSeconds(RubyTime time, long nanoseconds) {
time.setNanoseconds(nanoseconds);
return nanoseconds;
}

}

@RubiniusPrimitive(name = "time_env_zone")
public static abstract class TimeEnvZonePrimitiveNode extends RubiniusPrimitiveNode {

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

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

@Specialization
public Object timeEnvZone(RubyTime time) {
throw new UnsupportedOperationException("time_env_zone");
}

}

@RubiniusPrimitive(name = "time_utc_offset")
public static abstract class TimeUTCOffsetPrimitiveNode extends RubiniusPrimitiveNode {

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

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

@Specialization
public Object timeUTCOffset(RubyTime time) {
throw new UnsupportedOperationException("time_utc_offset");
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
/*
* 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.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.KernelNodes;
import org.jruby.truffle.nodes.core.KernelNodesFactory;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.*;

/**
* Rubinius primitives associated with types and objects.
*/
public abstract class TypePrimitiveNodes {

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

@Child protected KernelNodes.IsANode isANode;

public VMObjectKindOfPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
isANode = KernelNodesFactory.IsANodeFactory.create(context, sourceSection, new RubyNode[]{null, null});
}

public VMObjectKindOfPrimitiveNode(VMObjectKindOfPrimitiveNode prev) {
super(prev);
isANode = prev.isANode;
}

@Specialization
public boolean vmObjectKindOf(Object object, RubyClass rubyClass) {
return isANode.executeBoolean(object, rubyClass);
}

}

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

@Child protected KernelNodes.ClassNode classNode;

public VMObjectClassPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
classNode = KernelNodesFactory.ClassNodeFactory.create(context, sourceSection, new RubyNode[]{null});
}

public VMObjectClassPrimitiveNode(VMObjectClassPrimitiveNode prev) {
super(prev);
classNode = prev.classNode;
}

@Specialization
public RubyClass vmObjectClass(Object object) {
return classNode.executeGetClass(object);
}

}

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

@Child protected KernelNodes.SingletonClassMethodNode singletonClassNode;

public VMObjectSingletonClassPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
singletonClassNode = KernelNodesFactory.SingletonClassMethodNodeFactory.create(context, sourceSection, new RubyNode[]{null});
}

public VMObjectSingletonClassPrimitiveNode(VMObjectSingletonClassPrimitiveNode prev) {
super(prev);
singletonClassNode = prev.singletonClassNode;
}

@Specialization
public Object vmObjectClass(Object object) {
return singletonClassNode.singletonClass(object);
}

}

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

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

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

@Specialization
public Object vmSingletonClassObject(Object object) {
throw new UnsupportedOperationException("vm_singleton_class_object");
}

}

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

@Child protected KernelNodes.RespondToNode respondToNode;

public VMObjectRespondToPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
respondToNode = KernelNodesFactory.RespondToNodeFactory.create(context, sourceSection, new RubyNode[]{null, null, null});
}

public VMObjectRespondToPrimitiveNode(VMObjectRespondToPrimitiveNode prev) {
super(prev);
respondToNode = prev.respondToNode;
}

@Specialization
public boolean vmObjectRespondTo(VirtualFrame frame, Object object, Object name, boolean includePrivate) {
return respondToNode.executeDoesRespondTo(frame, object, name, includePrivate);
}

}

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

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

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

@Specialization
public Object vmObjectEqual(Object a, Object b) {
throw new UnsupportedOperationException("vm_object_equal");
}

}

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

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

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

@Specialization
public Object vmGetModuleName(Object object) {
throw new UnsupportedOperationException("vm_get_module_name");
}

}

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

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

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

@Specialization
public Object vmSetModuleName(Object object) {
throw new UnsupportedOperationException("vm_set_module_name");
}

}

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

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

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

@Specialization
public Object encodingGetObjectEncoding(Object object) {
throw new UnsupportedOperationException("encoding_get_object_encoding");
}

}

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

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

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

@Specialization
public Object objectInfect(Object object) {
throw new UnsupportedOperationException("object_infect");
}

}

}
10 changes: 9 additions & 1 deletion core/src/main/java/org/jruby/truffle/runtime/RubyContext.java
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.RubyRootNode;
import org.jruby.truffle.nodes.methods.SetFrameVisibilityNode;
import org.jruby.truffle.nodes.rubinius.RubiniusPrimitiveManager;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.*;
import org.jruby.truffle.runtime.subsystems.*;
@@ -60,6 +61,7 @@ public class RubyContext extends ExecutionContext {
private final Random random = new Random();
private final LexicalScope rootLexicalScope;
private final CompilerOptions compilerOptions;
private final RubiniusPrimitiveManager rubiniusPrimitiveManager;

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

@@ -111,6 +113,8 @@ public RubyContext(Ruby runtime) {
fiberManager = new FiberManager(this);

rootLexicalScope = new LexicalScope(null, coreLibrary.getObjectClass());

rubiniusPrimitiveManager = RubiniusPrimitiveManager.create();
}

public Shape getEmptyShape() {
@@ -404,4 +408,8 @@ public CompilerOptions getCompilerOptions() {
return compilerOptions;
}

}
public RubiniusPrimitiveManager getRubiniusPrimitiveManager() {
return rubiniusPrimitiveManager;
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. This
* Copyright (c) 2014, 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:
*
@@ -22,6 +22,8 @@ public class RubyBignum extends RubyBasicObject {

public RubyBignum(RubyClass rubyClass, BigInteger value) {
super(rubyClass);
// TODO(CS): we fail this but we shouldn't
//assert value.bitLength() < 64;
this.value = value;
}

@@ -35,6 +37,11 @@ public RubyBignum negate() {
return create(value.negate());
}

@CompilerDirectives.TruffleBoundary
public RubyBignum abs() {
return create(value.abs());
}

@CompilerDirectives.TruffleBoundary
public RubyBignum create(BigInteger value) {
return new RubyBignum(getContext().getCoreLibrary().getBignumClass(), value);
@@ -116,6 +123,11 @@ public RubyBignum mod(long other) {
return create(value.mod(BigInteger.valueOf(other)));
}

@CompilerDirectives.TruffleBoundary
public RubyBignum mod(RubyBignum other) {
return create(value.mod(other.bigIntegerValue()));
}

@CompilerDirectives.TruffleBoundary
public int compareTo(int other) {
return value.compareTo(BigInteger.valueOf(other));
68 changes: 13 additions & 55 deletions core/src/main/java/org/jruby/truffle/runtime/core/RubyTime.java
Original file line number Diff line number Diff line change
@@ -13,13 +13,6 @@
import org.jruby.truffle.nodes.objects.Allocator;
import org.jruby.truffle.runtime.RubyContext;

import java.util.Date;

/**
* Represents the Ruby {@code Time} class. This is a very rough implementation and is only really
* enough to run benchmark harnesses.
*/

public class RubyTime extends RubyBasicObject {

private long seconds;
@@ -31,64 +24,29 @@ public RubyTime(RubyClass timeClass, long seconds, long nanoseconds) {
this.nanoseconds = nanoseconds;
}

public long getWholeSeconds() {
return seconds;
}

public double getRealSeconds() {
return seconds + nanosecondsToSecond(nanoseconds);
}

public static RubyTime fromDate(RubyClass timeClass, long timeMiliseconds) {
return new RubyTime(timeClass, milisecondsToSeconds(timeMiliseconds), milisecondsToNanoseconds(timeMiliseconds));
}

public static RubyTime fromArray(RubyClass timeClass,
int second,
int minute,
int hour,
int dayOfMonth,
int month,
int year,
int nanoOfSecond,
boolean isdst,
RubyString zone) {
throw new UnsupportedOperationException();
//ZonedDateTime zdt = ZonedDateTime.of(year, month, dayOfMonth, hour, minute, second, nanoOfSecond, ZoneId.of(zone.toString()));
//return new RubyTime(timeClass, zdt.toEpochSecond(), nanoOfSecond);
}

public Date toDate() {
return new Date(secondsToMiliseconds(seconds) + nanosecondsToMiliseconds(nanoseconds));
}
public static class TimeAllocator implements Allocator {

private static long milisecondsToSeconds(long miliseconds) {
return miliseconds / 1000;
}
@Override
public RubyBasicObject allocate(RubyContext context, RubyClass rubyClass, RubyNode currentNode) {
return new RubyTime(rubyClass, 0, 0);
}

private static long milisecondsToNanoseconds(long miliseconds) {
return (miliseconds % 1000) * 1000000;
}

private static long nanosecondsToMiliseconds(long nanoseconds) {
return nanoseconds / 1000000;
public long getSeconds() {
return seconds;
}

public static double nanosecondsToSecond(long nanoseconds) {
return nanoseconds / 1e9;
public void setSeconds(long seconds) {
this.seconds = seconds;
}

public static long secondsToMiliseconds(long seconds) {
return seconds * 1000;
public long getNanoseconds() {
return nanoseconds;
}

public static class TimeAllocator implements Allocator {

@Override
public RubyBasicObject allocate(RubyContext context, RubyClass rubyClass, RubyNode currentNode) {
return new RubyTime(rubyClass, milisecondsToSeconds(System.currentTimeMillis()), milisecondsToNanoseconds(System.currentTimeMillis()));
}

public void setNanoseconds(long nanoseconds) {
this.nanoseconds = nanoseconds;
}

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

public abstract class TimeOperations {

public static long secondsAndNanosecondsToMiliseconds(long seconds, long nanoseconds) {
return secondsToMiliseconds(seconds) + nanosecondsToMilliseconds(nanoseconds);
}

public static long secondsToMiliseconds(long seconds) {
return seconds * 1_000;
}

public static long nanosecondsToMilliseconds(long nanoseconds) {
return nanoseconds * 1_000_000;
}

public static long millisecondsToSeconds(long milliseconds) {
return milliseconds / 1_000;
}

public static long millisecondsInCurrentSecond(long milliseconds) {
return milliseconds % 1_000;
}

public static long millisecondsToNanoseconds(long milliseconds) {
return milliseconds * 1_000_000;
}

}
168 changes: 156 additions & 12 deletions core/src/main/java/org/jruby/truffle/translator/BodyTranslator.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This
* Copyright (c) 2013, 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:
*
@@ -41,9 +41,13 @@
import org.jruby.truffle.nodes.literal.*;
import org.jruby.truffle.nodes.methods.*;
import org.jruby.truffle.nodes.methods.UndefNode;
import org.jruby.truffle.nodes.methods.arguments.MissingArgumentBehaviour;
import org.jruby.truffle.nodes.methods.arguments.ReadPreArgumentNode;
import org.jruby.truffle.nodes.methods.locals.*;
import org.jruby.truffle.nodes.objects.*;
import org.jruby.truffle.nodes.objects.SelfNode;
import org.jruby.truffle.nodes.rubinius.CallRubiniusPrimitiveNode;
import org.jruby.truffle.nodes.rubinius.RubiniusPrimitiveConstructor;
import org.jruby.truffle.nodes.yield.YieldNode;
import org.jruby.truffle.runtime.LexicalScope;
import org.jruby.truffle.runtime.RubyContext;
@@ -69,6 +73,8 @@ public class BodyTranslator extends Translator {
private boolean translatingNextExpression = false;
private String currentCallMethodName = null;

private boolean privately = false;

private static final Set<String> debugIgnoredCalls = new HashSet<>();

static {
@@ -346,9 +352,144 @@ public RubyNode visitBreakNode(org.jruby.ast.BreakNode node) {

@Override
public RubyNode visitCallNode(CallNode node) {
final SourceSection sourceSection = translate(node.getPosition());

if (node.getReceiverNode() instanceof org.jruby.ast.ConstNode
&& ((ConstNode) node.getReceiverNode()).getName() == "Rubinius") {
if (node.getName().equals("primitive")) {
return translateRubiniusPrimitive(sourceSection, node);
} else if (node.getName().equals("invoke_primitive")) {
return translateRubiniusInvokePrimitive(sourceSection, node);
} else if (node.getName().equals("privately")) {
return translateRubiniusPrivately(sourceSection, node);
}
}

return visitCallNodeExtraArgument(node, null, false, false);
}

private RubyNode translateRubiniusPrimitive(SourceSection sourceSection, CallNode node) {
/*
* Translates something that looks like
*
* Rubinius.primitive :foo
*
* into
*
* CallRubiniusPrimitiveNode(FooNode(arg1, arg2, ..., argN))
*
* Where the arguments are the same arguments as the method. It looks like this is only exercised with simple
* arguments so we're not worrying too much about what happens when they're more complicated (rest,
* keywords etc).
*/

if (node.getArgsNode().childNodes().size() != 1 || !(node.getArgsNode().childNodes().get(0) instanceof org.jruby.ast.SymbolNode)) {
throw new UnsupportedOperationException("Rubinius.primitive must have a single literal symbol argument");
}

final String primitiveName = ((org.jruby.ast.SymbolNode) node.getArgsNode().childNodes().get(0)).getName();

final RubiniusPrimitiveConstructor primitive = context.getRubiniusPrimitiveManager().getPrimitive(primitiveName);

final List<RubyNode> arguments = new ArrayList<>();

int argumentsCount = primitive.getFactory().getExecutionSignature().size();

if (primitive.getAnnotation().needsSelf()) {
arguments.add(new SelfNode(context, sourceSection));
argumentsCount--;
}

for (int n = 0; n < argumentsCount; n++) {
arguments.add(new ReadPreArgumentNode(context, sourceSection, n, MissingArgumentBehaviour.UNDEFINED));
}

return new CallRubiniusPrimitiveNode(context, sourceSection,
primitive.getFactory().createNode(context, sourceSection, arguments.toArray(new RubyNode[arguments.size()])),
environment.getReturnID());
}

private RubyNode translateRubiniusInvokePrimitive(SourceSection sourceSection, CallNode node) {
/*
* Translates something that looks like
*
* Rubinius.invoke_primitive :foo, arg1, arg2, argN
*
* into
*
* CallRubiniusPrimitiveNode(FooNode(arg1, arg2, ..., argN))
*/

if (node.getArgsNode().childNodes().size() < 1 || !(node.getArgsNode().childNodes().get(0) instanceof org.jruby.ast.SymbolNode)) {
throw new UnsupportedOperationException("Rubinius.invoke_primitive must have at least an initial literal symbol argument");
}

final String primitiveName = ((org.jruby.ast.SymbolNode) node.getArgsNode().childNodes().get(0)).getName();

final RubiniusPrimitiveConstructor primitive = context.getRubiniusPrimitiveManager().getPrimitive(primitiveName);

final List<RubyNode> arguments = new ArrayList<>();

final Iterator<Node> childIterator = node.getArgsNode().childNodes().iterator();

// The first argument was the symbol, so skip it when gathering arguments to pass to the primitive
childIterator.next();

while (childIterator.hasNext()) {
arguments.add(childIterator.next().accept(this));
}

return new CallRubiniusPrimitiveNode(context, sourceSection,
primitive.getFactory().createNode(context, sourceSection, arguments.toArray(new RubyNode[arguments.size()])),
environment.getReturnID());
}

private RubyNode translateRubiniusPrivately(SourceSection sourceSection, CallNode node) {
/*
* Translates something that looks like
*
* Rubinius.privately { foo }
*
* into just
*
* foo
*
* While we translate foo we'll mark all call sites as ignoring visbility.
*/

if (!(node.getIterNode() instanceof org.jruby.ast.IterNode)) {
throw new UnsupportedOperationException("Rubinius.privately needs a literal block");
}

if (node.getArgsNode() != null && node.getArgsNode().childNodes().size() > 0) {
throw new UnsupportedOperationException("Rubinius.privately should not have any arguments");
}

/*
* Normally when you visit an 'iter' (block) node it will set the method name for you, so that we can name the
* block something like 'times-block'. Here we bypass the iter node and translate its child. So we set the
* name here.
*/

currentCallMethodName = "privately";

/*
* While we translate the body of the iter we want to create all call nodes with the ignore-visbility flag.
* This flag is checked in visitCallNodeExtraArgument.
*/

final boolean previousPrivately = privately;
privately = true;

try {
return (((org.jruby.ast.IterNode) node.getIterNode()).getBodyNode()).accept(this);
} finally {
// Restore the previous value of the privately flag - allowing for nesting

privately = previousPrivately;
}
}

/**
* See translateDummyAssignment to understand what this is for.
*/
@@ -368,15 +509,7 @@ public RubyNode visitCallNodeExtraArgument(CallNode node, RubyNode extraArgument

final ArgumentsAndBlockTranslation argumentsAndBlock = translateArgumentsAndBlock(sourceSection, block, args, extraArgument, node.getName());

RubyNode translated;
if (node.getName().equals("primitive") && receiverTranslated instanceof ReadConstantNode && ((ReadConstantNode) receiverTranslated).getName().equals("Rubinius")) {
RubyNode callNode = new RubyCallNode(context, sourceSection, "send", receiverTranslated, argumentsAndBlock.getBlock(), argumentsAndBlock.isSplatted(), false, true, argumentsAndBlock.getArguments());
translated = new TryNode(context, sourceSection, new ExceptionTranslatingNode(context, sourceSection, new ReturnNode(context, sourceSection, environment.getReturnID(), callNode)),
new RescueNode[] {new RescueAnyNode(context, sourceSection, new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getNilObject()))},
new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getNilObject()));
} else {
translated = new RubyCallNode(context, sourceSection, node.getName(), receiverTranslated, argumentsAndBlock.getBlock(), argumentsAndBlock.isSplatted(), isVCall, ignoreVisibility, false, argumentsAndBlock.getArguments());
}
RubyNode translated = new RubyCallNode(context, sourceSection, node.getName(), receiverTranslated, argumentsAndBlock.getBlock(), argumentsAndBlock.isSplatted(), isVCall, privately || ignoreVisibility, false, argumentsAndBlock.getArguments());

// return instrumenter.instrumentAsCall(translated, node.getName());
return translated;
@@ -2036,8 +2169,19 @@ public RubyNode visitPostExeNode(PostExeNode node) {
public RubyNode visitRationalNode(RationalNode node) {
final SourceSection sourceSection = translate(node.getPosition());

// TODO: implement Rational
return new FixnumLiteralNode.LongFixnumLiteralNode(context, sourceSection, node.getNumerator());
// Translate as Rubinius.privately { Rubinius.convert(a, b) }

// TODO(CS): use IntFixnumLiteralNode where possible

final LexicalScope lexicalScope = environment.getLexicalScope();
final RubyNode moduleNode = new LexicalScopeNode(context, sourceSection, lexicalScope);
return new RubyCallNode(
context, sourceSection, "convert",
new ReadConstantNode(context, sourceSection, "Rational", moduleNode, lexicalScope),
null, false, true, false,
new RubyNode[]{
new FixnumLiteralNode.LongFixnumLiteralNode(context, sourceSection, node.getNumerator()),
new FixnumLiteralNode.LongFixnumLiteralNode(context, sourceSection, node.getDenominator())});
}

@Override
8 changes: 7 additions & 1 deletion core/src/main/ruby/jruby/truffle/core.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. This
# Copyright (c) 2014, 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:
#
@@ -27,12 +27,18 @@
require_relative 'core/rubinius/api/shims/undefined'

require_relative 'core/rubinius/kernel/bootstrap/time'
require_relative 'core/rubinius/kernel/bootstrap/type'

require_relative 'core/rubinius/kernel/common/kernel'
require_relative 'core/rubinius/kernel/common/array'
require_relative 'core/rubinius/kernel/common/rational'
require_relative 'core/rubinius/kernel/common/struct'
require_relative 'core/rubinius/kernel/common/enumerable'
require_relative 'core/rubinius/kernel/common/undefined'
require_relative 'core/rubinius/kernel/common/time'
require_relative 'core/rubinius/kernel/common/type'
require_relative 'core/rubinius/kernel/common/integer'
require_relative 'core/rubinius/kernel/common/float'
require_relative 'core/rubinius/kernel/common/numeric'

require_relative 'core/shims'
16 changes: 13 additions & 3 deletions core/src/main/ruby/jruby/truffle/core/float.rb
Original file line number Diff line number Diff line change
@@ -8,8 +8,18 @@

class Float

NAN = 0.0 / 0.0
INFINITY = 1.0 / 0.0
EPSILON = 2.2204460492503131e-16
NAN = 0.0 / 0.0
INFINITY = 1.0 / 0.0
EPSILON = 2.2204460492503131e-16
RADIX = 2
ROUNDS = 1
MIN = 2.2250738585072014e-308
MAX = 1.7976931348623157e+308
MIN_EXP = -1021
MAX_EXP = 1024
MIN_10_EXP = -307
MAX_10_EXP = 308
DIG = 15
MANT_DIG = 53

end
Original file line number Diff line number Diff line change
@@ -8,4 +8,5 @@

# TODO(CS): isn't this vulnerable to naming conflicts?

LookupTable = Hash
class LookupTable < Hash
end
Original file line number Diff line number Diff line change
@@ -12,6 +12,11 @@ def self.single_block_arg
raise "not implemented"
end

def self.mathn_loaded?
false
end

end

PrimitiveFailures = StandardError
class PrimitiveFailure < StandardError
end
25 changes: 0 additions & 25 deletions core/src/main/ruby/jruby/truffle/core/rubinius/api/shims/type.rb

This file was deleted.

Original file line number Diff line number Diff line change
@@ -25,11 +25,10 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

class Time
# TODO(CS)
#def self.now
# Rubinius.primitive :time_s_now
# raise PrimitiveFailure, "Time.now primitive failed"
#end
def self.now
Rubinius.primitive :time_s_now
raise PrimitiveFailure, "Time.now primitive failed"
end

def self.duplicate(other)
Rubinius.primitive :time_s_dup
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# 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.

# The Type module provides facilities for accessing various "type" related
# data about an object, as well as providing type coercion methods. These
# facilities are independent of the object and thus are more robust in the
# face of ad hoc monkeypatching.
module Rubinius
module Type
# Performs a direct kind_of? check on the object bypassing any method
# overrides.
def self.object_kind_of?(obj, cls)
Rubinius.primitive :vm_object_kind_of
raise PrimitiveFailure, "Rubinius::Type.object_kind_of? primitive failed"
end

def self.object_class(obj)
Rubinius.primitive :vm_object_class
raise PrimitiveFailure, "Rubinius::Type.object_class primitive failed"
end

def self.object_singleton_class(obj)
Rubinius.primitive :vm_object_singleton_class
raise TypeError, "no singleton class available for a #{Type.object_class(obj)}"
end

def self.singleton_class_object(mod)
Rubinius.primitive :vm_singleton_class_object
raise PrimitiveFailure, "Rubinius::Type.singleton_class_object primitive failed"
end

def self.object_instance_of?(obj, cls)
object_class(obj) == cls
end

def self.object_respond_to?(obj, name, include_private = false)
Rubinius.invoke_primitive :vm_object_respond_to, obj, name, include_private
end

def self.object_equal(a, b)
Rubinius.primitive :vm_object_equal
raise PrimitiveFailure, "Rubinius::Type.object_equal primitive failed"
end

def self.module_name(mod)
Rubinius.primitive :vm_get_module_name
raise PrimitiveFailure, "Rubinius::Type.module_name primitive failed"
end

def self.module_inspect(mod)
sc = singleton_class_object mod

if sc
case sc
when Class, Module
name = "#<Class:#{module_inspect(sc)}>"
else
cls = object_class sc
name = "#<Class:#<#{module_name(cls)}:0x#{sc.object_id.to_s(16)}>>"
end
else
name = module_name mod
if !name or name == ""
name = "#<#{object_class(mod)}:0x#{mod.object_id.to_s(16)}>"
end
end

name
end

def self.set_module_name(mod, name, under)
Rubinius.primitive :vm_set_module_name
raise PrimitiveFailure, "Rubinius::Type.set_module_name primitive failed"
end

def self.coerce_string_to_float(string, strict)
value = Rubinius.invoke_primitive :string_to_f, string, strict
raise ArgumentError, "invalid string for Float" if value.nil?
value
end

def self.coerce_to_array(obj)
return [obj] unless obj

return Rubinius.privately { obj.to_a } if object_respond_to?(obj, :to_a, true)
return obj.to_ary if obj.respond_to?(:to_ary)

# On 1.9, #to_a is not defined on all objects, so wrap the object in a
# literal array.
return [obj]
end

def self.coerce_to_float(obj, strict=true, must_be_numeric=true)
if !must_be_numeric && object_kind_of?(obj, String)
return coerce_string_to_float(obj, strict)
end

case obj
when Float
obj
when Numeric
coerce_to obj, Float, :to_f
when nil, true, false
raise TypeError, "can't convert #{obj.inspect} into Float"
else
raise TypeError, "can't convert #{obj.class} into Float"
end
end

def self.coerce_object_to_float(obj)
case obj
when Float
obj
when nil
raise TypeError, "can't convert nil into Float"
when Complex
if obj.respond_to?(:imag) && obj.imag.equal?(0)
coerce_to obj, Float, :to_f
else
raise RangeError, "can't convert #{obj} into Float"
end
else
coerce_to obj, Float, :to_f
end
end

def self.object_encoding(obj)
Rubinius.primitive :encoding_get_object_encoding
raise PrimitiveFailure, "Rubinius::Type.object_encoding primitive failed"
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# 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.

# Only part of Rubinius' kernel.rb

class Float < Numeric

def to_r
f, e = Math.frexp self
f = Math.ldexp(f, MANT_DIG).to_i
e -= MANT_DIG

(f * (RADIX ** e)).to_r
end

end
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# 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.

# Only part of Rubinius' kernel.rb

class Integer < Numeric

def gcd(other)
raise TypeError, "Expected Integer but got #{other.class}" unless other.kind_of?(Integer)
min = self.abs
max = other.abs
while min > 0
tmp = min
min = max % min
max = tmp
end
max
end

def to_r
Rational(self, 1)
end

end
Original file line number Diff line number Diff line change
@@ -24,8 +24,17 @@
# 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.

# Only part of Rubinius' kernel.rb

module Kernel

def Rational(a, b = 1)
Rubinius.privately do
Rational.convert a, b
end
end
module_function :Rational

##
# MRI uses a macro named StringValue which has essentially the same
# semantics as obj.coerce_to(String, :to_str), but rather than using that
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# 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.

# Only part of Rubinius' numeric.rb

class Numeric

def zero?
self == 0
end

def nonzero?
zero? ? nil : self
end

def div(other)
raise ZeroDivisionError, "divided by 0" if other == 0
self.__slash__(other).floor
end

end

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -107,16 +107,15 @@ def self.new(year=undefined, month=nil, day=nil, hour=nil, minute=nil, second=ni
end
end

# TODO(CS)
#def inspect
# if @is_gmt
# str = strftime("%Y-%m-%d %H:%M:%S UTC")
# else
# str = strftime("%Y-%m-%d %H:%M:%S %z")
# end
#
# str.force_encoding Encoding::US_ASCII
#end
def inspect
if @is_gmt
str = strftime("%Y-%m-%d %H:%M:%S UTC")
else
str = strftime("%Y-%m-%d %H:%M:%S %z")
end

str.force_encoding Encoding::US_ASCII
end

alias_method :to_s, :inspect

@@ -173,46 +172,43 @@ def to_r
(seconds + subsec).to_r
end

# TODO(CS)
#def to_f
# to_r.to_f
#end
def to_f
to_r.to_f
end

# TODO(CS)
#def +(other)
# raise TypeError, 'time + time?' if other.kind_of?(Time)
#
# case other = Rubinius::Type.coerce_to_exact_num(other)
# when Integer
# other_sec = other
# other_nsec = 0
# else
# other_sec, nsec_frac = other.divmod(1)
# other_nsec = (nsec_frac * 1_000_000_000).to_i
# end
#
# # Don't use self.class, MRI doesn't honor subclasses here
# Time.specific(seconds + other_sec, nsec + other_nsec, @is_gmt, @offset)
#end

# TODO(CS)
#def -(other)
# if other.kind_of?(Time)
# return (seconds - other.seconds) + ((nsec - other.nsec) * 0.000000001)
# end
#
# case other = Rubinius::Type.coerce_to_exact_num(other)
# when Integer
# other_sec = other
# other_nsec = 0
# else
# other_sec, nsec_frac = other.divmod(1)
# other_nsec = (nsec_frac * 1_000_000_000 + 0.5).to_i
# end
#
# # Don't use self.class, MRI doesn't honor subclasses here
# Time.specific(seconds - other_sec, nsec - other_nsec, @is_gmt, @offset)
#end
def +(other)
raise TypeError, 'time + time?' if other.kind_of?(Time)

case other = Rubinius::Type.coerce_to_exact_num(other)
when Integer
other_sec = other
other_nsec = 0
else
other_sec, nsec_frac = other.divmod(1)
other_nsec = (nsec_frac * 1_000_000_000).to_i
end

# Don't use self.class, MRI doesn't honor subclasses here
Time.specific(seconds + other_sec, nsec + other_nsec, @is_gmt, @offset)
end

def -(other)
if other.kind_of?(Time)
return (seconds - other.seconds) + ((nsec - other.nsec) * 0.000000001)
end

case other = Rubinius::Type.coerce_to_exact_num(other)
when Integer
other_sec = other
other_nsec = 0
else
other_sec, nsec_frac = other.divmod(1)
other_nsec = (nsec_frac * 1_000_000_000 + 0.5).to_i
end

# Don't use self.class, MRI doesn't honor subclasses here
Time.specific(seconds - other_sec, nsec - other_nsec, @is_gmt, @offset)
end

def localtime(offset=nil)
@is_gmt = false
594 changes: 594 additions & 0 deletions core/src/main/ruby/jruby/truffle/core/rubinius/kernel/common/type.rb

Large diffs are not rendered by default.

15 changes: 11 additions & 4 deletions core/src/main/ruby/jruby/truffle/core/shims.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. This
# Copyright (c) 2014, 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:
#
@@ -9,12 +9,19 @@
# These are implemented just to get other stuff working - we'll go back and
# implement these properly later.

module Kernel
class Numeric

def Rational(numerator, denominator)
numerator
def eql?(other)
self == other
end

end

class Complex
end

module Kernel

def Complex(real, imaginary)
imaginary
end
8 changes: 4 additions & 4 deletions spec/ruby/language/numbers_spec.rb
Original file line number Diff line number Diff line change
@@ -56,13 +56,13 @@
end

it "can be an octal literal with trailing 'r' to represent a Rational" do
042.should == Rational(34, 1)
-042.should == Rational(-34, 1)
042r.should == Rational(34, 1)
-042r.should == Rational(-34, 1)
end

it "can be a binary literal with trailing 'r' to represent a Rational" do
0b1111.should == Rational(15, 1)
-0b1111.should == Rational(-15, 1)
0b1111r.should == Rational(15, 1)
-0b1111r.should == Rational(-15, 1)
end

it "can be an integer literal with trailing 'i' to represent a Complex" do
8 changes: 0 additions & 8 deletions spec/truffle/tags/core/kernel/Rational_tags.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
fails:Kernel.Rational passed Integer returns a new Rational number with 1 as the denominator
fails:Kernel.Rational passed two integers returns a new Rational number
fails:Kernel.Rational passed two integers reduces the Rational
fails:Kernel.Rational when passed a String converts the String to a Rational using the same method as String#to_r
fails:Kernel.Rational when passed a String scales the Rational value of the first argument by the Rational value of the second
fails:Kernel.Rational when passed a String does not use the same method as Float#to_r
fails:Kernel.Rational when passed a String raises a TypeError if the first argument is nil
fails:Kernel.Rational when passed a String raises a TypeError if the second argument is nil
fails:Kernel.Rational when passed a String raises a TypeError if the first argument is a Symbol
fails:Kernel.Rational when passed a String raises a TypeError if the second argument is a Symbol
fails:Kernel.Rational when passed a String when passed a Numeric calls #to_r to convert the first argument to a Rational
fails:Kernel.Rational when passed a String when passed a Complex returns a Rational from the real part if the imaginary part is 0
fails:Kernel.Rational when passed a String when passed a Complex raises a RangeError if the imaginary part is not 0
1 change: 0 additions & 1 deletion spec/truffle/tags/core/rational/abs_tags.txt

This file was deleted.

4 changes: 0 additions & 4 deletions spec/truffle/tags/core/rational/ceil_tags.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,2 @@
fails:Rational#ceil with no arguments (precision = 0) returns an Integer
fails:Rational#ceil with no arguments (precision = 0) returns the truncated value toward positive infinity
fails:Rational#ceil with a precision < 0 returns an Integer
fails:Rational#ceil with a precision < 0 moves the truncation point n decimal places left
fails:Rational#ceil with precision > 0 returns a Rational
fails:Rational#ceil with precision > 0 moves the truncation point n decimal places right
1 change: 0 additions & 1 deletion spec/truffle/tags/core/rational/coerce_tags.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
fails:Rational#coerce returns the passed argument, self as Float, when given a Float
fails:Rational#coerce returns the passed argument, self as Rational, when given an Integer
fails:Rational#coerce returns [argument, self] when given a Rational
12 changes: 0 additions & 12 deletions spec/truffle/tags/core/rational/comparison_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/rational/denominator_tags.txt

This file was deleted.

5 changes: 0 additions & 5 deletions spec/truffle/tags/core/rational/div_tags.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
fails:Rational#div returns an Integer
fails:Rational#div raises an ArgumentError if passed more than one argument
fails:Rational#div raises a TypeError if passed a non-numeric argument
fails:Rational#div passed a Rational performs integer division and returns the result
fails:Rational#div passed a Rational raises a ZeroDivisionError when the argument has a numerator of 0
fails:Rational#div passed a Rational raises a ZeroDivisionError when the argument has a numerator of 0.0
fails:Rational#div passed an Integer performs integer division and returns the result
fails:Rational#div passed an Integer raises a ZeroDivisionError when the argument is 0
fails:Rational#div passed a Float performs integer division and returns the result
fails:Rational#div passed a Float raises a ZeroDivisionError when the argument is 0.0
6 changes: 0 additions & 6 deletions spec/truffle/tags/core/rational/divide_tags.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,2 @@
fails:Rational#/ calls #coerce on the passed argument with self
fails:Rational#/ calls #/ on the coerced Rational with the coerced Object
fails:Rational#/ when passed an Integer returns self divided by other as a Rational
fails:Rational#/ when passed an Integer raises a ZeroDivisionError when passed 0
fails:Rational#/ when passed a Rational returns self divided by other as a Rational
fails:Rational#/ when passed a Rational raises a ZeroDivisionError when passed a Rational with a numerator of 0
fails:Rational#/ when passed a Float returns self divided by other as a Float
fails:Rational#/ when passed a Float returns infinity when passed 0
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/rational/divmod_tags.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
fails:Rational#divmod when passed a Rational returns the quotient as Integer and the remainder as Rational
fails:Rational#divmod when passed a Rational raises a ZeroDivisonError when passed a Rational with a numerator of 0
fails:Rational#divmod when passed an Integer returns the quotient as Integer and the remainder as Rational
fails:Rational#divmod when passed an Integer raises a ZeroDivisionError when passed 0
fails:Rational#divmod when passed a Float returns the quotient as Integer and the remainder as Float
fails:Rational#divmod when passed a Float raises a ZeroDivisionError when passed 0
4 changes: 0 additions & 4 deletions spec/truffle/tags/core/rational/equal_value_tags.txt

This file was deleted.

20 changes: 0 additions & 20 deletions spec/truffle/tags/core/rational/exponent_tags.txt
Original file line number Diff line number Diff line change
@@ -1,24 +1,4 @@
fails:Rational#** calls #coerce on the passed argument with self
fails:Rational#** calls #** on the coerced Rational with the coerced Object
fails:Rational#** raises ZeroDivisionError for Rational(0, 1) passed a negative Integer
fails:Rational#** raises ZeroDivisionError for Rational(0, 1) passed a negative Rational with denominator 1
fails:Rational#** raises ZeroDivisionError for Rational(0, 1) passed a negative Rational
fails:Rational#** returns Infinity for Rational(0, 1) passed a negative Float
fails:Rational#** when passed Rational returns Rational(1) if the exponent is Rational(0)
fails:Rational#** when passed Rational returns self raised to the argument as a Rational if the exponent's denominator is 1
fails:Rational#** when passed Rational returns self raised to the argument as a Float if the exponent's denominator is not 1
fails:Rational#** when passed Rational returns a complex number when self is negative and the passed argument is not 0
fails:Rational#** when passed Integer returns the Rational value of self raised to the passed argument
fails:Rational#** when passed Integer returns Rational(1, 1) when the passed argument is 0
fails:Rational#** when passed Bignum returns Rational(0) when self is Rational(0) and the exponent is positive
fails:Rational#** when passed Bignum raises ZeroDivisionError when self is Rational(0) and the exponent is negative
fails:Rational#** when passed Bignum returns Rational(1) when self is Rational(1)
fails:Rational#** when passed Bignum returns Rational(1) when self is Rational(-1) and the exponent is positive and even
fails:Rational#** when passed Bignum returns Rational(-1) when self is Rational(-1) and the exponent is positive and odd
fails:Rational#** when passed Bignum returns positive Infinity when self is > 1
fails:Rational#** when passed Bignum returns 0.0 when self is > 1 and the exponent is negative
fails:Rational#** when passed Bignum returns positive Infinity when self < -1
fails:Rational#** when passed Bignum returns 0.0 when self is < -1 and the exponent is negative
fails:Rational#** when passed Float returns self converted to Float and raised to the passed argument
fails:Rational#** when passed Float returns a complex number if self is negative and the passed argument is not 0
fails:Rational#** when passed Float returns Complex(1.0) when the passed argument is 0.0
1 change: 0 additions & 1 deletion spec/truffle/tags/core/rational/fdiv_tags.txt

This file was deleted.

4 changes: 0 additions & 4 deletions spec/truffle/tags/core/rational/floor_tags.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,2 @@
fails:Rational#floor with no arguments (precision = 0) returns an integer
fails:Rational#floor with no arguments (precision = 0) returns the truncated value toward negative infinity
fails:Rational#floor with a precision < 0 returns an integer
fails:Rational#floor with a precision < 0 moves the truncation point n decimal places left
fails:Rational#floor with a precision > 0 returns a Rational
fails:Rational#floor with a precision > 0 moves the truncation point n decimal places right
1 change: 0 additions & 1 deletion spec/truffle/tags/core/rational/hash_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/rational/inspect_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/rational/marshal_dump_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/rational/minus_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/rational/modulo_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
fails:Rational#% returns the remainder when this value is divided by other
fails:Rational#% returns a Float value when the argument is Float
fails:Rational#% raises ZeroDivisionError on zero denominator
fails:Rational#% raises a ZeroDivisionError when the argument is 0.0
5 changes: 0 additions & 5 deletions spec/truffle/tags/core/rational/multiply_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/rational/numerator_tags.txt

This file was deleted.

5 changes: 0 additions & 5 deletions spec/truffle/tags/core/rational/plus_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/rational/rational_tags.txt

This file was deleted.

3 changes: 0 additions & 3 deletions spec/truffle/tags/core/rational/rationalize_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
fails:Rational#rationalize returns self with no argument
fails:Rational#rationalize simplifies self to the degree specified by a Rational argument
fails:Rational#rationalize simplifies self to the degree specified by a Float argument
fails:Rational#rationalize raises ArgumentError when passed more than one argument
1 change: 0 additions & 1 deletion spec/truffle/tags/core/rational/remainder_tags.txt

This file was deleted.

5 changes: 0 additions & 5 deletions spec/truffle/tags/core/rational/round_tags.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
fails:Rational#round with no arguments (precision = 0) returns an integer
fails:Rational#round with no arguments (precision = 0) returns the truncated value toward the nearest integer
fails:Rational#round with a precision < 0 returns an integer
fails:Rational#round with a precision < 0 moves the truncation point n decimal places left
fails:Rational#round with a precision > 0 returns a Rational
fails:Rational#round with a precision > 0 moves the truncation point n decimal places right
fails:Rational#round with a precision > 0 doesn't alter the value if the precision is too great
fails:Rational#round with a precision > 0 doesn't fail when rounding to an absurdly large positive precision
1 change: 0 additions & 1 deletion spec/truffle/tags/core/rational/to_f_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/rational/to_i_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/rational/to_r_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/rational/to_s_tags.txt

This file was deleted.

4 changes: 0 additions & 4 deletions spec/truffle/tags/core/rational/truncate_tags.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,2 @@
fails:Rational#truncate with no arguments (precision = 0) returns an integer
fails:Rational#truncate with no arguments (precision = 0) returns the truncated value toward 0
fails:Rational#truncate with a precision < 0 returns an integer
fails:Rational#truncate with a precision < 0 moves the truncation point n decimal places left
fails:Rational#truncate with a precision > 0 returns a Rational
fails:Rational#truncate with a precision > 0 moves the truncation point n decimal places right
3 changes: 0 additions & 3 deletions spec/truffle/tags/core/rational/zero_tags.txt

This file was deleted.

1 change: 1 addition & 0 deletions spec/truffle/tags/core/struct/eql_tags.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fails:Struct#eql? returns false if any corresponding elements are not #eql?
1 change: 0 additions & 1 deletion spec/truffle/tags/core/time/_dump_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
fails:Time#_dump is a private method
fails:Time#_dump preserves the GMT flag
fails:Time#_dump dumps a Time object to a bytestring
fails:Time#_dump dumps an array with a date as first element
1 change: 0 additions & 1 deletion spec/truffle/tags/core/time/_load_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
fails:Time._load is a private method
fails:Time._load loads a time object in the new format
fails:Time._load loads a time object in the old UNIX timestamp based format
fails:Time._load loads MRI's marshaled time format
1 change: 0 additions & 1 deletion spec/truffle/tags/core/time/asctime_tags.txt

This file was deleted.

10 changes: 0 additions & 10 deletions spec/truffle/tags/core/time/at_tags.txt
Original file line number Diff line number Diff line change
@@ -1,20 +1,10 @@
fails:Time.at passed Numeric returns a Time object representing the given number of Integer seconds since 1970-01-01 00:00:00 UTC
fails:Time.at passed Numeric returns a Time object representing the given number of Float seconds since 1970-01-01 00:00:00 UTC
fails:Time.at passed Numeric returns a non-UTC Time
fails:Time.at passed Numeric returns a subclass instance on a Time subclass
fails:Time.at passed Time creates a new time object with the value given by time
fails:Time.at passed Time creates a dup time object with the value given by time
fails:Time.at passed Time returns a UTC time if the argument is UTC
fails:Time.at passed Time returns a non-UTC time if the argument is non-UTC
fails:Time.at passed Time returns a subclass instance
fails:Time.at passed non-Time, non-Numeric raises a TypeError with a String argument
fails:Time.at passed non-Time, non-Numeric raises a TypeError with a nil argument
fails:Time.at passed non-Time, non-Numeric with an argument that responds to #to_int coerces using #to_int
fails:Time.at passed non-Time, non-Numeric with an argument that responds to #to_r coerces using #to_r
fails:Time.at passed [Integer, Numeric] returns a Time object representing the given number of seconds and Integer microseconds since 1970-01-01 00:00:00 UTC
fails:Time.at passed [Integer, Numeric] returns a Time object representing the given number of seconds and Float microseconds since 1970-01-01 00:00:00 UTC
fails:Time.at with a second argument that responds to #to_int coerces using #to_int
fails:Time.at with a second argument that responds to #to_r coerces using #to_r
fails:Time.at passed [Integer, nil] raises a TypeError
fails:Time.at passed [Integer, String] raises a TypeError
fails:Time.at passed [Time, Integer] raises a TypeError
5 changes: 0 additions & 5 deletions spec/truffle/tags/core/time/comparison_tags.txt
Original file line number Diff line number Diff line change
@@ -4,8 +4,3 @@ fails:Time#<=> returns -1 if the first argument is a point in time before the se
fails:Time#<=> returns 1 if the first argument is a fraction of a microsecond after the second argument
fails:Time#<=> returns 0 if time is the same as other, including fractional microseconds
fails:Time#<=> returns -1 if the first argument is a fraction of a microsecond before the second argument
fails:Time#<=> given a non-Time argument returns nil if argument <=> self returns nil
fails:Time#<=> given a non-Time argument returns -1 if argument <=> self is greater than 0
fails:Time#<=> given a non-Time argument returns 1 if argument <=> self is not greater than 0 and is less than 0
fails:Time#<=> given a non-Time argument returns 0 if argument <=> self is neither greater than 0 nor less than 0
fails:Time#<=> given a non-Time argument returns nil if argument also uses an inverse comparison for <=>
1 change: 0 additions & 1 deletion spec/truffle/tags/core/time/ctime_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/time/dup_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
fails:Time#dup returns a Time object that represents the same time
fails:Time#dup copies the gmt state flag
fails:Time#dup returns an independent Time object
fails:Time#dup returns a subclass instance
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/time/eql_tags.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
fails:Time#eql? returns true if self and other have the same whole number of seconds
fails:Time#eql? returns false if self and other have differing whole numbers of seconds
fails:Time#eql? returns true if self and other have the same number of microseconds
fails:Time#eql? returns false if self and other have differing numbers of microseconds
fails:Time#eql? returns false if self and other have differing fractional microseconds
3 changes: 0 additions & 3 deletions spec/truffle/tags/core/time/gm_tags.txt
Original file line number Diff line number Diff line change
@@ -8,7 +8,6 @@ fails:Time.gm accepts 2 arguments (year, month)
fails:Time.gm accepts 3 arguments (year, month, day)
fails:Time.gm accepts 4 arguments (year, month, day, hour)
fails:Time.gm accepts 5 arguments (year, month, day, hour, minute)
fails:Time.gm raises a TypeError if the year is nil
fails:Time.gm accepts nil month, day, hour, minute, and second
fails:Time.gm handles a String year
fails:Time.gm coerces the year with #to_int
@@ -34,8 +33,6 @@ fails:Time.gm raises an ArgumentError for out of range day
fails:Time.gm raises an ArgumentError for out of range hour
fails:Time.gm raises an ArgumentError for out of range minute
fails:Time.gm raises an ArgumentError for out of range second
fails:Time.gm raises ArgumentError when given 9 arguments
fails:Time.gm raises ArgumentError when given 11 arguments
fails:Time.gm returns subclass instances
fails:Time.gm handles string arguments
fails:Time.gm handles float arguments
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/time/hash_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/time/inspect_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
fails:Time#inspect formats the local time following the pattern 'yyyy-MM-dd HH:mm:ss Z'
fails:Time#inspect formats the UTC time following the pattern 'yyyy-MM-dd HH:mm:ss UTC'
fails:Time#inspect formats the fixed offset time following the pattern 'yyyy-MM-dd HH:mm:ss +/-HHMM'
fails:Time#inspect returns a US-ASCII encoded string
1 change: 0 additions & 1 deletion spec/truffle/tags/core/time/local_tags.txt
Original file line number Diff line number Diff line change
@@ -8,7 +8,6 @@ fails:Time.local accepts 2 arguments (year, month)
fails:Time.local accepts 3 arguments (year, month, day)
fails:Time.local accepts 4 arguments (year, month, day, hour)
fails:Time.local accepts 5 arguments (year, month, day, hour, minute)
fails:Time.local raises a TypeError if the year is nil
fails:Time.local accepts nil month, day, hour, minute, and second
fails:Time.local handles a String year
fails:Time.local coerces the year with #to_int
6 changes: 1 addition & 5 deletions spec/truffle/tags/core/time/minus_tags.txt
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
fails:Time#- decrements the time by the specified amount
fails:Time#- understands negative subtractions
fails:Time#- accepts arguments that can be coerced into Rational
fails:Time#- raises a TypeError if given argument is a coercible String
fails:Time#- raises TypeError on argument that can't be coerced
fails:Time#- raises TypeError on nil argument
fails:Time#- tracks microseconds
fails:Time#- tracks nanoseconds
fails:Time#- maintains precision
fails:Time#- maintains microseconds precision
fails:Time#- maintains nanoseconds precision
fails:Time#- maintains subseconds precision
fails:Time#- returns a UTC time if self is UTC
fails:Time#- returns a non-UTC time if self is non-UTC
fails:Time#- returns a time with the same fixed offset as self
fails:Time#- does not return a subclass instance
fails:Time#- returns a time with nanoseconds precision between two time objects
fails:Time#- maintains precision
1 change: 0 additions & 1 deletion spec/truffle/tags/core/time/mktime_tags.txt
Original file line number Diff line number Diff line change
@@ -8,7 +8,6 @@ fails:Time.mktime accepts 2 arguments (year, month)
fails:Time.mktime accepts 3 arguments (year, month, day)
fails:Time.mktime accepts 4 arguments (year, month, day, hour)
fails:Time.mktime accepts 5 arguments (year, month, day, hour, minute)
fails:Time.mktime raises a TypeError if the year is nil
fails:Time.mktime accepts nil month, day, hour, minute, and second
fails:Time.mktime handles a String year
fails:Time.mktime coerces the year with #to_int
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/time/new_tags.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
fails:Time.new creates a subclass instance if called on a subclass
fails:Time.new creates a time based on given values, interpreted in the local time zone
fails:Time.new respects rare old timezones
fails:Time.new accepts 1 argument (year)
fails:Time.new accepts 2 arguments (year, month)
fails:Time.new accepts 3 arguments (year, month, day)
fails:Time.new accepts 4 arguments (year, month, day, hour)
fails:Time.new accepts 5 arguments (year, month, day, hour, minute)
fails:Time.new raises a TypeError if the year is nil
fails:Time.new accepts nil month, day, hour, minute, and second
fails:Time.new handles a String year
fails:Time.new coerces the year with #to_int
1 change: 0 additions & 1 deletion spec/truffle/tags/core/time/now_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/time/nsec_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
fails:Time#nsec returns 0 for a Time constructed with a whole number of seconds
fails:Time#nsec returns the nanoseconds part of a Time constructed with a Float number of seconds
fails:Time#nsec returns the nanoseconds part of a Time constructed with an Integer number of microseconds
fails:Time#nsec returns the nanoseconds part of a Time constructed with an Float number of microseconds
Loading

0 comments on commit 672834f

Please sign in to comment.