Mercurial > hg > graal-compiler
diff graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FixnumNodes.java @ 13514:0fbee3eb71f0
Ruby: import project.
author | Chris Seaton <chris.seaton@oracle.com> |
---|---|
date | Mon, 06 Jan 2014 17:12:09 +0000 |
parents | |
children | 44288fe54352 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FixnumNodes.java Mon Jan 06 17:12:09 2014 +0000 @@ -0,0 +1,853 @@ +/* + * Copyright (c) 2013 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 com.oracle.truffle.ruby.nodes.core; + +import java.math.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.ruby.runtime.*; +import com.oracle.truffle.ruby.runtime.core.*; +import com.oracle.truffle.ruby.runtime.core.array.*; + +@CoreClass(name = "Fixnum") +public abstract class FixnumNodes { + + @CoreMethod(names = "+@", maxArgs = 0) + public abstract static class PosNode extends CoreMethodNode { + + public PosNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public PosNode(PosNode prev) { + super(prev); + } + + @Specialization + public int pos(int value) { + return value; + } + + } + + @CoreMethod(names = "-@", maxArgs = 0) + public abstract static class NegNode extends CoreMethodNode { + + public NegNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public NegNode(NegNode prev) { + super(prev); + } + + @Specialization(rewriteOn = ArithmeticException.class) + public int neg(int value) { + return ExactMath.subtractExact(0, value); + } + + @Specialization + public BigInteger negWithOverflow(int value) { + return BigInteger.valueOf(value).negate(); + } + + } + + @CoreMethod(names = "+", minArgs = 1, maxArgs = 1) + public abstract static class AddNode extends CoreMethodNode { + + public AddNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public AddNode(AddNode prev) { + super(prev); + } + + @Specialization(rewriteOn = ArithmeticException.class) + public int add(int a, int b) { + return ExactMath.addExact(a, b); + } + + @Specialization + public Object addWithOverflow(int a, int b) { + return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).add(BigInteger.valueOf(b))); + } + + @Specialization + public double add(int a, double b) { + return a + b; + } + + @Specialization + public Object add(int a, BigInteger b) { + return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).add(b)); + } + + } + + @CoreMethod(names = "-", minArgs = 1, maxArgs = 1) + public abstract static class SubNode extends CoreMethodNode { + + public SubNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public SubNode(SubNode prev) { + super(prev); + } + + @Specialization(rewriteOn = ArithmeticException.class) + public int sub(int a, int b) { + return ExactMath.subtractExact(a, b); + } + + @Specialization + public Object subWithOverflow(int a, int b) { + return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).subtract(BigInteger.valueOf(b))); + } + + @Specialization + public double sub(int a, double b) { + return a - b; + } + + @Specialization + public Object sub(int a, BigInteger b) { + return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).subtract(b)); + } + + } + + @CoreMethod(names = "*", minArgs = 1, maxArgs = 1) + public abstract static class MulNode extends CoreMethodNode { + + public MulNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public MulNode(MulNode prev) { + super(prev); + } + + @Specialization(rewriteOn = ArithmeticException.class) + public int mul(int a, int b) { + return ExactMath.multiplyExact(a, b); + } + + @Specialization + public Object mulWithOverflow(int a, int b) { + return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).multiply(BigInteger.valueOf(b))); + } + + @Specialization + public double mul(int a, double b) { + return a * b; + } + + @Specialization + public Object mul(int a, BigInteger b) { + return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).multiply(b)); + } + + } + + @CoreMethod(names = "**", minArgs = 1, maxArgs = 1) + public abstract static class PowNode extends CoreMethodNode { + + public PowNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public PowNode(PowNode prev) { + super(prev); + } + + @Specialization + public Object pow(int a, int b) { + return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).pow(b)); + } + + @Specialization + public double pow(int a, double b) { + return Math.pow(a, b); + } + + @Specialization + public Object pow(int a, BigInteger b) { + final BigInteger bigA = BigInteger.valueOf(a); + + BigInteger result = BigInteger.ONE; + + for (BigInteger n = BigInteger.ZERO; b.compareTo(b) < 0; n = n.add(BigInteger.ONE)) { + result = result.multiply(bigA); + } + + return result; + } + + } + + @CoreMethod(names = "/", minArgs = 1, maxArgs = 1) + public abstract static class DivNode extends CoreMethodNode { + + public DivNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public DivNode(DivNode prev) { + super(prev); + } + + @Specialization + public int div(int a, int b) { + return a / b; + } + + @Specialization + public double div(int a, double b) { + return a / b; + } + + @Specialization + public int div(@SuppressWarnings("unused") int a, @SuppressWarnings("unused") BigInteger b) { + return 0; + } + } + + @CoreMethod(names = "%", minArgs = 1, maxArgs = 1) + public abstract static class ModNode extends CoreMethodNode { + + public ModNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public ModNode(ModNode prev) { + super(prev); + } + + @Specialization + public int mod(int a, int b) { + return a % b; + } + + @Specialization + public double mod(@SuppressWarnings("unused") int a, @SuppressWarnings("unused") double b) { + throw new UnsupportedOperationException(); + } + + @Specialization + public BigInteger mod(@SuppressWarnings("unused") int a, BigInteger b) { + return b; + } + } + + @CoreMethod(names = "divmod", minArgs = 1, maxArgs = 1) + public abstract static class DivModNode extends CoreMethodNode { + + public DivModNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public DivModNode(DivModNode prev) { + super(prev); + } + + @Specialization + public RubyArray divMod(int a, int b) { + int q; + + if (b < 0) { + if (a < 0) { + q = -a / -b; + } else { + q = -(a / -b); + } + } else { + if (a < 0) { + q = -(-a / b); + } else { + q = a / b; + } + } + + int r = a - q * b; + + if ((r < 0 && b > 0) || (r > 0 && b < 0)) { + r += b; + q -= 1; + } + + final FixnumImmutablePairArrayStore store = new FixnumImmutablePairArrayStore(q, r); + return new RubyArray(getContext().getCoreLibrary().getArrayClass(), store); + } + + @Specialization + public RubyArray divMod(@SuppressWarnings("unused") int a, @SuppressWarnings("unused") double b) { + throw new UnsupportedOperationException(); + } + + @Specialization + public RubyArray divMod(int a, BigInteger b) { + return RubyBignum.divMod(getContext(), BigInteger.valueOf(a), b); + } + } + + @CoreMethod(names = "<", minArgs = 1, maxArgs = 1) + public abstract static class LessNode extends CoreMethodNode { + + public LessNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public LessNode(LessNode prev) { + super(prev); + } + + @Specialization + public boolean less(int a, int b) { + return a < b; + } + + @Specialization + public boolean less(int a, double b) { + return a < b; + } + + @Specialization + public boolean less(int a, BigInteger b) { + return BigInteger.valueOf(a).compareTo(b) < 0; + } + } + + @CoreMethod(names = "<=", minArgs = 1, maxArgs = 1) + public abstract static class LessEqualNode extends CoreMethodNode { + + public LessEqualNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public LessEqualNode(LessEqualNode prev) { + super(prev); + } + + @Specialization + public boolean lessEqual(int a, int b) { + return a <= b; + } + + @Specialization + public boolean lessEqual(int a, double b) { + return a <= b; + } + + @Specialization + public boolean lessEqual(int a, BigInteger b) { + return BigInteger.valueOf(a).compareTo(b) <= 0; + } + } + + @CoreMethod(names = {"==", "==="}, minArgs = 1, maxArgs = 1) + public abstract static class EqualNode extends CoreMethodNode { + + public EqualNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public EqualNode(EqualNode prev) { + super(prev); + } + + @Specialization + public boolean equal(int a, int b) { + return a == b; + } + + @Specialization + public boolean equal(int a, double b) { + return a == b; + } + + @Specialization + public boolean equal(int a, BigInteger b) { + return BigInteger.valueOf(a).compareTo(b) == 0; + } + } + + @CoreMethod(names = "<=>", minArgs = 1, maxArgs = 1) + public abstract static class CompareNode extends CoreMethodNode { + + public CompareNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public CompareNode(CompareNode prev) { + super(prev); + } + + @Specialization + public int compare(int a, int b) { + return Integer.compare(a, b); + } + + @Specialization + public int compare(int a, double b) { + return Double.compare(a, b); + } + + @Specialization + public int compare(int a, BigInteger b) { + return BigInteger.valueOf(a).compareTo(b); + } + } + + @CoreMethod(names = "!=", minArgs = 1, maxArgs = 1) + public abstract static class NotEqualNode extends CoreMethodNode { + + public NotEqualNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public NotEqualNode(NotEqualNode prev) { + super(prev); + } + + @Specialization + public boolean notEqual(int a, int b) { + return a != b; + } + + @Specialization + public boolean notEqual(int a, double b) { + return a != b; + } + + @Specialization + public boolean notEqual(int a, BigInteger b) { + return BigInteger.valueOf(a).compareTo(b) != 0; + } + } + + @CoreMethod(names = ">=", minArgs = 1, maxArgs = 1) + public abstract static class GreaterEqualNode extends CoreMethodNode { + + public GreaterEqualNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public GreaterEqualNode(GreaterEqualNode prev) { + super(prev); + } + + @Specialization + public boolean greaterEqual(int a, int b) { + return a >= b; + } + + @Specialization + public boolean greaterEqual(int a, double b) { + return a >= b; + } + + @Specialization + public boolean greaterEqual(int a, BigInteger b) { + return BigInteger.valueOf(a).compareTo(b) >= 0; + } + } + + @CoreMethod(names = ">", minArgs = 1, maxArgs = 1) + public abstract static class GreaterNode extends CoreMethodNode { + + public GreaterNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public GreaterNode(GreaterNode prev) { + super(prev); + } + + @Specialization + public boolean equal(int a, int b) { + return a > b; + } + + @Specialization + public boolean equal(int a, double b) { + return a > b; + } + + @Specialization + public boolean equal(int a, BigInteger b) { + return BigInteger.valueOf(a).compareTo(b) > 0; + } + } + + @CoreMethod(names = "~", maxArgs = 0) + public abstract static class ComplementNode extends CoreMethodNode { + + public ComplementNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public ComplementNode(ComplementNode prev) { + super(prev); + } + + @Specialization + public int complement(int n) { + return ~n; + } + + } + + @CoreMethod(names = "&", minArgs = 1, maxArgs = 1) + public abstract static class BitAndNode extends CoreMethodNode { + + public BitAndNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public BitAndNode(BitAndNode prev) { + super(prev); + } + + @Specialization + public int bitAnd(int a, int b) { + return a & b; + } + + @Specialization + public Object bitAnd(int a, BigInteger b) { + return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).and(b)); + } + } + + @CoreMethod(names = "|", minArgs = 1, maxArgs = 1) + public abstract static class BitOrNode extends CoreMethodNode { + + public BitOrNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public BitOrNode(BitOrNode prev) { + super(prev); + } + + @Specialization + public int bitOr(int a, int b) { + return a | b; + } + + @Specialization + public Object bitOr(int a, BigInteger b) { + return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).or(b)); + } + } + + @CoreMethod(names = "^", minArgs = 1, maxArgs = 1) + public abstract static class BitXOrNode extends CoreMethodNode { + + public BitXOrNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public BitXOrNode(BitXOrNode prev) { + super(prev); + } + + @Specialization + public int bitXOr(int a, int b) { + return a ^ b; + } + + @Specialization + public Object bitXOr(int a, BigInteger b) { + return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).xor(b)); + } + } + + @CoreMethod(names = "<<", minArgs = 1, maxArgs = 1) + public abstract static class LeftShiftNode extends CoreMethodNode { + + public LeftShiftNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public LeftShiftNode(LeftShiftNode prev) { + super(prev); + } + + @Specialization + public Object leftShift(int a, int b) { + if (b > 0) { + if (RubyFixnum.SIZE - Integer.numberOfLeadingZeros(a) + b > RubyFixnum.SIZE - 1) { + return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).shiftLeft(b)); + } else { + return a << b; + } + } else { + if (-b >= Integer.SIZE) { + return 0; + } else { + return a >> -b; + } + } + } + + } + + @CoreMethod(names = ">>", minArgs = 1, maxArgs = 1) + public abstract static class RightShiftNode extends CoreMethodNode { + + public RightShiftNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public RightShiftNode(RightShiftNode prev) { + super(prev); + } + + @Specialization + public int rightShift(int a, int b) { + if (b > 0) { + return a >> b; + } else { + if (-b >= RubyFixnum.SIZE) { + return 0; + } else { + return a >> -b; + } + } + } + + } + + @CoreMethod(names = "[]", minArgs = 1, maxArgs = 1) + public abstract static class GetIndexNode extends CoreMethodNode { + + public GetIndexNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public GetIndexNode(GetIndexNode prev) { + super(prev); + } + + @Specialization + public int getIndex(int self, int index) { + if ((self & (1 << index)) == 0) { + return 0; + } else { + return 1; + } + } + + } + + @CoreMethod(names = "chr", maxArgs = 0) + public abstract static class ChrNode extends CoreMethodNode { + + public ChrNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public ChrNode(ChrNode prev) { + super(prev); + } + + @Specialization + public RubyString chr(int n) { + // TODO(CS): not sure about encoding here + return getContext().makeString((char) n); + } + + } + + @CoreMethod(names = "inspect", maxArgs = 0) + public abstract static class InpsectNode extends CoreMethodNode { + + public InpsectNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public InpsectNode(InpsectNode prev) { + super(prev); + } + + @Specialization + public RubyString inspect(int n) { + return getContext().makeString(Integer.toString(n)); + } + + } + + @CoreMethod(names = "nonzero?", maxArgs = 0) + public abstract static class NonZeroNode extends CoreMethodNode { + + public NonZeroNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public NonZeroNode(NonZeroNode prev) { + super(prev); + } + + @Specialization + public Object nonZero(int value) { + if (value == 0) { + return false; + } else { + return value; + } + } + + } + + @CoreMethod(names = "size", needsSelf = false, maxArgs = 0) + public abstract static class SizeNode extends CoreMethodNode { + + public SizeNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public SizeNode(SizeNode prev) { + super(prev); + } + + @Specialization + public int size() { + return Integer.SIZE / Byte.SIZE; + } + + } + + @CoreMethod(names = "step", needsBlock = true, minArgs = 2, maxArgs = 2) + public abstract static class StepNode extends YieldingCoreMethodNode { + + public StepNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public StepNode(StepNode prev) { + super(prev); + } + + @Specialization + public NilPlaceholder step(VirtualFrame frame, int from, int to, int step, RubyProc block) { + for (int i = from; i <= to; i += step) { + yield(frame, block, i); + } + + return NilPlaceholder.INSTANCE; + } + + } + + @CoreMethod(names = "times", needsBlock = true, maxArgs = 0) + public abstract static class TimesNode extends YieldingCoreMethodNode { + + public TimesNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public TimesNode(TimesNode prev) { + super(prev); + } + + @Specialization + public int times(VirtualFrame frame, int n, RubyProc block) { + for (int i = 0; i < n; i++) { + yield(frame, block, i); + } + + return n; + } + + } + + @CoreMethod(names = {"to_i", "to_int"}, maxArgs = 0) + public abstract static class ToINode extends CoreMethodNode { + + public ToINode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public ToINode(ToINode prev) { + super(prev); + } + + @Specialization + public int toI(int n) { + return n; + } + + } + + @CoreMethod(names = "to_f", maxArgs = 0) + public abstract static class ToFNode extends CoreMethodNode { + + public ToFNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public ToFNode(ToFNode prev) { + super(prev); + } + + @Specialization + public double toF(int n) { + return n; + } + + } + + @CoreMethod(names = "to_s", maxArgs = 0) + public abstract static class ToSNode extends CoreMethodNode { + + public ToSNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public ToSNode(ToSNode prev) { + super(prev); + } + + @Specialization + public RubyString toS(int n) { + return getContext().makeString(Integer.toString(n)); + } + + } + + @CoreMethod(names = "upto", needsBlock = true, minArgs = 1, maxArgs = 1) + public abstract static class UpToNode extends YieldingCoreMethodNode { + + public UpToNode(RubyContext context, SourceSection sourceSection) { + super(context, sourceSection); + } + + public UpToNode(UpToNode prev) { + super(prev); + } + + @Specialization + public NilPlaceholder upto(VirtualFrame frame, int from, int to, RubyProc block) { + for (int i = from; i <= to; i++) { + yield(frame, block, i); + } + + return NilPlaceholder.INSTANCE; + } + + } + +}