Skip to content

Commit

Permalink
Showing 9 changed files with 276 additions and 218 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* 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.array;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyArray;

@NodeChildren({
@NodeChild(value="array", type=RubyNode.class),
@NodeChild(value="index", type=RubyNode.class)
})
public abstract class ArrayReadDenormalizedNode extends RubyNode {

@Child private ArrayReadNormalizedNode readNode;

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

public ArrayReadDenormalizedNode(ArrayReadDenormalizedNode prev) {
super(prev);
readNode = prev.readNode;
}

public abstract Object executeRead(VirtualFrame frame, RubyArray array, int index);

@Specialization
public Object read(VirtualFrame frame, RubyArray array, int index) {
if (readNode == null) {
CompilerDirectives.transferToInterpreter();
readNode = insert(ArrayReadNormalizedNodeFactory.create(getContext(), getSourceSection(), null, null));
}

final int normalizedIndex = array.normaliseIndex(index);

return readNode.executeRead(frame, array, normalizedIndex);
}

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

import com.oracle.truffle.api.dsl.ImportGuards;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.core.ArrayGuards;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyArray;
import org.jruby.truffle.runtime.core.RubyNilClass;

@NodeChildren({
@NodeChild(value="array", type=RubyNode.class),
@NodeChild(value="index", type=RubyNode.class)
})
@ImportGuards(ArrayGuards.class)
public abstract class ArrayReadNormalizedNode extends RubyNode {

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

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

public abstract Object executeRead(VirtualFrame frame, RubyArray array, int index);

@Specialization(
guards="isNullArray"
)
public RubyNilClass readNull(RubyArray array, int index) {
return getContext().getCoreLibrary().getNilObject();
}

@Specialization(
guards={"isNormalisedInBounds", "isIntegerArray"}
)
public int readIntegerInBounds(RubyArray array, int index) {
return ((int[]) array.getStore())[index];
}

@Specialization(
guards={"isNormalisedInBounds", "isLongArray"}
)
public long readLongInBounds(RubyArray array, int index) {
return ((long[]) array.getStore())[index];
}

@Specialization(
guards={"isNormalisedInBounds", "isDoubleArray"}
)
public double readDoubleInBounds(RubyArray array, int index) {
return ((double[]) array.getStore())[index];
}

@Specialization(
guards={"isNormalisedInBounds", "isObjectArray"}
)
public Object readObjectInBounds(RubyArray array, int index) {
return ((Object[]) array.getStore())[index];
}

@Specialization(
guards="!isNormalisedInBounds"
)
public RubyNilClass readOutOfBounds(RubyArray array, int index) {
return getContext().getCoreLibrary().getNilObject();
}

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

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

/**
* Passes through {@code int} values unmodified, but will convert a {@code long} value to an {@code int}, if it fits
* within the range of an {@code int}. Leaves all other values unmodified. Used where a specialisation only accepts
* {@code int}, such as Java array indexing, but we would like to also handle {@code long} if they also fit within an
* {@code int}.
*/
@NodeChild(value="child", type=RubyNode.class)
public abstract class NewFixnumLowerNode extends RubyNode {

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

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

@Specialization
public int lower(int value) {
return value;
}

@Specialization(guards="canLower")
public int lower(long value) {
return (int) value;
}

@Specialization(guards="!canLower")
public long lowerFails(long value) {
return value;
}

protected static boolean canLower(long value) {
return CoreLibrary.fitsIntoInteger(value);
}

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

import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.literal.FixnumLiteralNode;
import org.jruby.truffle.runtime.RubyContext;

public abstract class PrimitiveArrayNodeFactory {

/**
* Create a node to read from an array with a constant denormalised index.
*/
public static RubyNode read(RubyContext context, SourceSection sourceSection, RubyNode array, int index) {
final RubyNode literalIndex = new FixnumLiteralNode.IntegerFixnumLiteralNode(context, sourceSection, index);

if (index > 0) {
return ArrayReadNormalizedNodeFactory.create(context, sourceSection, array, literalIndex);
} else {
return ArrayReadDenormalizedNodeFactory.create(context, sourceSection, array, literalIndex);
}
}

}
Original file line number Diff line number Diff line change
@@ -73,4 +73,30 @@ public static boolean areBothObject(RubyArray a, RubyArray b) {
return a.getStore() instanceof Object[] && b.getStore() instanceof Object[];
}

// New names

public static boolean isNullArray(RubyArray array) {
return array.getStore() == null;
}

public static boolean isIntegerArray(RubyArray array) {
return array.getStore() instanceof int[];
}

public static boolean isLongArray(RubyArray array) {
return array.getStore() instanceof long[];
}

public static boolean isDoubleArray(RubyArray array) {
return array.getStore() instanceof double[];
}

public static boolean isObjectArray(RubyArray array) {
return array.getStore() instanceof Object[];
}

public static boolean isNormalisedInBounds(RubyArray array, int index) {
return index >= 0 && index < array.getSize();
}

}
125 changes: 0 additions & 125 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/ArrayIndexNode.java

This file was deleted.

106 changes: 20 additions & 86 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/ArrayNodes.java
Original file line number Diff line number Diff line change
@@ -26,13 +26,14 @@
import org.jruby.truffle.nodes.CoreSourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.RubyRootNode;
import org.jruby.truffle.nodes.array.ArrayReadDenormalizedNode;
import org.jruby.truffle.nodes.array.ArrayReadDenormalizedNodeFactory;
import org.jruby.truffle.nodes.dispatch.*;
import org.jruby.truffle.nodes.methods.arguments.MissingArgumentBehaviour;
import org.jruby.truffle.nodes.methods.arguments.ReadPreArgumentNode;
import org.jruby.truffle.nodes.methods.locals.ReadLevelVariableNodeFactory;
import org.jruby.truffle.nodes.yield.YieldDispatchHeadNode;
import org.jruby.truffle.runtime.*;
import org.jruby.truffle.nodes.core.ArrayNodesFactory.AtNodeFactory;
import org.jruby.truffle.runtime.RubyArguments;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.UndefinedPlaceholder;
@@ -596,124 +597,57 @@ public boolean equal(VirtualFrame frame, RubyArray a, Object b) {
@CoreMethod(names = "at", required = 1, lowerFixnumParameters = 0)
public abstract static class AtNode extends ArrayCoreMethodNode {

@Child private ArrayReadDenormalizedNode readNode;

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

public AtNode(AtNode prev) {
super(prev);
readNode = prev.readNode;
}

public abstract Object executeAt(RubyArray array, int index);

@Specialization(guards = "isNull")
public RubyNilClass getNull(RubyArray array, int index) {
return getContext().getCoreLibrary().getNilObject();
}

@Specialization(guards = "isIntegerFixnum", rewriteOn = UnexpectedResultException.class)
public int getIntegerFixnumInBounds(RubyArray array, int index) throws UnexpectedResultException {
int normalisedIndex = array.normaliseIndex(index);

if (normalisedIndex < 0 || normalisedIndex >= array.getSize()) {
throw new UnexpectedResultException(getContext().getCoreLibrary().getNilObject());
} else {
return ((int[]) array.getStore())[normalisedIndex];
}
}

@Specialization(contains = "getIntegerFixnumInBounds", guards = "isIntegerFixnum")
public Object getIntegerFixnum(RubyArray array, int index) {
int normalisedIndex = array.normaliseIndex(index);

if (normalisedIndex < 0 || normalisedIndex >= array.getSize()) {
return getContext().getCoreLibrary().getNilObject();
} else {
return ((int[]) array.getStore())[normalisedIndex];
}
}

@Specialization(guards = "isLongFixnum", rewriteOn = UnexpectedResultException.class)
public long getLongFixnumInBounds(RubyArray array, int index) throws UnexpectedResultException {
int normalisedIndex = array.normaliseIndex(index);

if (normalisedIndex < 0 || normalisedIndex >= array.getSize()) {
throw new UnexpectedResultException(getContext().getCoreLibrary().getNilObject());
} else {
return ((long[]) array.getStore())[normalisedIndex];
}
}

@Specialization(contains = "getLongFixnumInBounds", guards = "isLongFixnum")
public Object getLongFixnum(RubyArray array, int index) {
int normalisedIndex = array.normaliseIndex(index);

if (normalisedIndex < 0 || normalisedIndex >= array.getSize()) {
return getContext().getCoreLibrary().getNilObject();
} else {
return ((long[]) array.getStore())[normalisedIndex];
}
}

@Specialization(guards = "isFloat", rewriteOn = UnexpectedResultException.class)
public double getFloatInBounds(RubyArray array, int index) throws UnexpectedResultException {
int normalisedIndex = array.normaliseIndex(index);

if (normalisedIndex < 0 || normalisedIndex >= array.getSize()) {
throw new UnexpectedResultException(getContext().getCoreLibrary().getNilObject());
} else {
return ((double[]) array.getStore())[normalisedIndex];
}
}

@Specialization(contains = "getFloatInBounds", guards = "isFloat")
public Object getFloat(RubyArray array, int index) {
int normalisedIndex = array.normaliseIndex(index);

if (normalisedIndex < 0 || normalisedIndex >= array.getSize()) {
return getContext().getCoreLibrary().getNilObject();
} else {
return ((double[]) array.getStore())[normalisedIndex];
@Specialization
public Object at(VirtualFrame frame, RubyArray array, int index) {
if (readNode == null) {
CompilerDirectives.transferToInterpreter();
readNode = insert(ArrayReadDenormalizedNodeFactory.create(getContext(), getSourceSection(), null, null));
}
}

@Specialization(guards = "isObject")
public Object getObject(RubyArray array, int index) {
int normalisedIndex = array.normaliseIndex(index);

if (normalisedIndex < 0 || normalisedIndex >= array.getSize()) {
return getContext().getCoreLibrary().getNilObject();
} else {
return ((Object[]) array.getStore())[normalisedIndex];
}
return readNode.executeRead(frame, array, index);
}

}

@CoreMethod(names = { "[]", "slice" }, required = 1, optional = 1, lowerFixnumParameters = { 0, 1 })
public abstract static class IndexNode extends ArrayCoreMethodNode {

@Child protected AtNode atNode;
@Child protected ArrayReadDenormalizedNode readNode;
@Child protected CallDispatchHeadNode fallbackNode;

private final BranchProfile outOfBounds = BranchProfile.create();

public IndexNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
atNode = AtNodeFactory.create(context, sourceSection, new RubyNode[] { null, null });
}

public IndexNode(IndexNode prev) {
super(prev);
atNode = prev.atNode;
readNode = prev.readNode;
fallbackNode = prev.fallbackNode;
}

// Simple indexing

@Specialization
public Object index(RubyArray array, int index, UndefinedPlaceholder undefined) {
return atNode.executeAt(array, index);
public Object index(VirtualFrame frame, RubyArray array, int index, UndefinedPlaceholder undefined) {
if (readNode == null) {
CompilerDirectives.transferToInterpreter();
readNode = insert(ArrayReadDenormalizedNodeFactory.create(getContext(), getSourceSection(), null, null));
}

return readNode.executeRead(frame, array, index);
}

// Slice with two fixnums
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@
import org.jruby.truffle.nodes.*;
import org.jruby.truffle.nodes.DefinedNode;
import org.jruby.truffle.nodes.ForNode;
import org.jruby.truffle.nodes.array.PrimitiveArrayNodeFactory;
import org.jruby.truffle.nodes.cast.*;
import org.jruby.truffle.nodes.cast.LambdaNode;
import org.jruby.truffle.nodes.control.AndNode;
@@ -38,7 +39,6 @@
import org.jruby.truffle.nodes.control.ReturnNode;
import org.jruby.truffle.nodes.control.WhileNode;
import org.jruby.truffle.nodes.core.*;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNodeFactory;
import org.jruby.truffle.nodes.globals.*;
import org.jruby.truffle.nodes.literal.*;
import org.jruby.truffle.nodes.methods.*;
@@ -1801,7 +1801,7 @@ public RubyNode visitMultipleAsgnNode(org.jruby.ast.MultipleAsgn19Node node) {
*/

for (int n = 0; n < preArray.size(); n++) {
final ArrayIndexNode assignedValue = ArrayIndexNodeFactory.create(context, sourceSection, n, environment.findLocalVarNode(tempName, sourceSection));
final RubyNode assignedValue = PrimitiveArrayNodeFactory.read(context, sourceSection, environment.findLocalVarNode(tempName, sourceSection), n);

sequence.add(translateDummyAssignment(preArray.get(n), assignedValue));
}
@@ -1920,7 +1920,7 @@ public RubyNode visitMultipleAsgnNode(org.jruby.ast.MultipleAsgn19Node node) {
}

for (int n = 0; n < postArray.size(); n++) {
final ArrayIndexNode assignedValue = ArrayIndexNodeFactory.create(context, sourceSection, -(postArray.size() - n), environment.findLocalVarNode(tempName, sourceSection));
final RubyNode assignedValue = PrimitiveArrayNodeFactory.read(context, sourceSection, environment.findLocalVarNode(tempName, sourceSection), -(postArray.size() - n));

sequence.add(translateDummyAssignment(postArray.get(n), assignedValue));
}
Original file line number Diff line number Diff line change
@@ -18,11 +18,10 @@
import org.jruby.lexer.yacc.ISourcePosition;
import org.jruby.truffle.nodes.ReadNode;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.array.PrimitiveArrayNodeFactory;
import org.jruby.truffle.nodes.cast.ArrayCastNodeFactory;
import org.jruby.truffle.nodes.cast.BooleanCastNodeFactory;
import org.jruby.truffle.nodes.control.IfNode;
import org.jruby.truffle.nodes.control.SequenceNode;
import org.jruby.truffle.nodes.core.ArrayIndexNodeFactory;
import org.jruby.truffle.nodes.core.ArraySliceNodeFactory;
import org.jruby.truffle.nodes.literal.ArrayLiteralNode;
import org.jruby.truffle.nodes.literal.NilLiteralNode;
@@ -209,7 +208,7 @@ public RubyNode visitArgumentNode(org.jruby.ast.ArgumentNode node) {

private RubyNode readArgument(SourceSection sourceSection) {
if (useArray()) {
return ArrayIndexNodeFactory.create(context, sourceSection, index, loadArray(sourceSection));
return PrimitiveArrayNodeFactory.read(context, sourceSection, loadArray(sourceSection), index);
} else {
if (state == State.PRE) {
return new ReadPreArgumentNode(context, sourceSection, index, isBlock ? MissingArgumentBehaviour.NIL : MissingArgumentBehaviour.RUNTIME_ERROR);
@@ -278,7 +277,7 @@ private RubyNode translateLocalAssignment(ISourcePosition sourcePosition, String
// Multiple assignment

if (useArray()) {
readNode = ArrayIndexNodeFactory.create(context, sourceSection, index, loadArray(sourceSection));
readNode = PrimitiveArrayNodeFactory.read(context, sourceSection, loadArray(sourceSection), index);
} else {
readNode = readArgument(sourceSection);
}

0 comments on commit 584ec92

Please sign in to comment.