Skip to content

Commit d0c3803

Browse files
committed
[GR-24169] AST-inline Array#[], #[]= and #at
PullRequest: truffleruby/2002
2 parents ebf798a + 04b2b06 commit d0c3803

File tree

9 files changed

+263
-40
lines changed

9 files changed

+263
-40
lines changed

src/main/java/org/truffleruby/core/array/ArrayNodes.java

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -264,9 +264,10 @@ public abstract static class IndexNode extends ArrayCoreMethodNode {
264264
protected Object index(RubyArray array, int index, NotProvided length,
265265
@Cached ConditionProfile negativeIndexProfile,
266266
@Cached ReadNormalizedNode readNode) {
267-
final int normalizedIndex = ArrayOperations
268-
.normalizeIndex(array.size, index, negativeIndexProfile);
269-
return readNode.executeRead(array, normalizedIndex);
267+
if (negativeIndexProfile.profile(index < 0)) {
268+
index += array.size;
269+
}
270+
return readNode.executeRead(array, index);
270271
}
271272

272273
@Specialization
@@ -291,9 +292,10 @@ protected Object slice(RubyArray array, int start, int length,
291292
if (length < 0) {
292293
return nil;
293294
}
294-
final int normalizedStart = ArrayOperations
295-
.normalizeIndex(array.size, start, negativeIndexProfile);
296-
return readSliceNode.executeReadSlice(array, normalizedStart, length);
295+
if (negativeIndexProfile.profile(start < 0)) {
296+
start += array.size;
297+
}
298+
return readSliceNode.executeReadSlice(array, start, length);
297299
}
298300

299301
@Specialization(guards = { "wasProvided(length)", "!isInteger(start) || !isInteger(length)" })
@@ -428,7 +430,7 @@ protected Object fallbackTernary(RubyArray array, Object start, Object length, O
428430
protected int normalize(int arraySize, int index,
429431
ConditionProfile negativeDenormalizedIndex, BranchProfile negativeNormalizedIndex) {
430432
if (negativeDenormalizedIndex.profile(index < 0)) {
431-
index = arraySize + index;
433+
index += arraySize;
432434
if (index < 0) {
433435
negativeNormalizedIndex.enter();
434436
throw new RaiseException(
@@ -728,7 +730,10 @@ protected Object deleteAt(RubyArray array, int index,
728730
@Cached ConditionProfile negativeIndexProfile,
729731
@Cached ConditionProfile notInBoundsProfile) {
730732
final int size = array.size;
731-
final int i = ArrayOperations.normalizeIndex(size, index, negativeIndexProfile);
733+
int i = index;
734+
if (negativeIndexProfile.profile(index < 0)) {
735+
i += size;
736+
}
732737

733738
if (notInBoundsProfile.profile(i < 0 || i >= size)) {
734739
return nil;
@@ -751,7 +756,10 @@ protected Object deleteAtCopying(RubyArray array, int index,
751756
@Cached ConditionProfile negativeIndexProfile,
752757
@Cached ConditionProfile notInBoundsProfile) {
753758
final int size = array.size;
754-
final int i = ArrayOperations.normalizeIndex(size, index, negativeIndexProfile);
759+
int i = index;
760+
if (negativeIndexProfile.profile(index < 0)) {
761+
i += size;
762+
}
755763

756764
if (notInBoundsProfile.profile(i < 0 || i >= size)) {
757765
return nil;

src/main/java/org/truffleruby/core/array/ArrayOperations.java

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
import com.oracle.truffle.api.CompilerDirectives;
2121
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
22-
import com.oracle.truffle.api.profiles.ConditionProfile;
2322

2423
public abstract class ArrayOperations {
2524

@@ -69,22 +68,6 @@ public static boolean verifyStore(RubyArray array) {
6968
return true;
7069
}
7170

72-
public static int normalizeIndex(int length, int index, ConditionProfile negativeIndexProfile) {
73-
if (negativeIndexProfile.profile(index < 0)) {
74-
return length + index;
75-
} else {
76-
return index;
77-
}
78-
}
79-
80-
public static int normalizeIndex(int length, int index) {
81-
if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, index < 0)) {
82-
return length + index;
83-
} else {
84-
return index;
85-
}
86-
}
87-
8871
public static int clampExclusiveIndex(int length, int index) {
8972
if (CompilerDirectives.injectBranchProbability(CompilerDirectives.UNLIKELY_PROBABILITY, index < 0)) {
9073
return 0;

src/main/java/org/truffleruby/core/inlined/CoreMethods.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ public class CoreMethods {
8888
public final InternalMethod MODULE_CASE_EQUAL;
8989
public final InternalMethod STRING_EQUAL;
9090
public final InternalMethod SYMBOL_TO_PROC;
91+
public final InternalMethod ARRAY_AT;
92+
public final InternalMethod ARRAY_INDEX_GET;
93+
public final InternalMethod ARRAY_INDEX_SET;
9194

9295
public CoreMethods(RubyContext context) {
9396
this.context = context;
@@ -100,6 +103,7 @@ public CoreMethods(RubyContext context) {
100103
final RubyClass nilClass = context.getCoreLibrary().nilClass;
101104
final RubyClass stringClass = context.getCoreLibrary().stringClass;
102105
final RubyClass symbolClass = context.getCoreLibrary().symbolClass;
106+
final RubyClass arrayClass = context.getCoreLibrary().arrayClass;
103107

104108
integerNegAssumption = registerAssumption(integerClass, "-@");
105109
floatNegAssumption = registerAssumption(floatClass, "-@");
@@ -150,6 +154,9 @@ public CoreMethods(RubyContext context) {
150154
MODULE_CASE_EQUAL = getMethod(moduleClass, "===");
151155
STRING_EQUAL = getMethod(stringClass, "==");
152156
SYMBOL_TO_PROC = getMethod(symbolClass, "to_proc");
157+
ARRAY_AT = getMethod(arrayClass, "at");
158+
ARRAY_INDEX_GET = getMethod(arrayClass, "[]");
159+
ARRAY_INDEX_SET = getMethod(arrayClass, "[]=");
153160
}
154161

155162
private Assumption registerAssumption(RubyClass klass, String methodName) {
@@ -238,12 +245,22 @@ public RubyNode createCallNode(RubyCallNodeParameters callParameters, Translator
238245
return InlinedGreaterThanNodeGen.create(context, callParameters, self, args[0]);
239246
case ">=":
240247
return InlinedGreaterOrEqualNodeGen.create(context, callParameters, self, args[0]);
248+
case "[]":
249+
return InlinedIndexGetNodeGen.create(context, callParameters, self, args[0]);
250+
case "at":
251+
return InlinedAtNodeGen.create(context, callParameters, self, args[0]);
241252
case "is_a?":
242253
return InlinedIsANodeGen.create(context, callParameters, self, args[0]);
243254
case "kind_of?":
244255
return InlinedKindOfNodeGen.create(context, callParameters, self, args[0]);
245256
default:
246257
}
258+
} else if (n == 3) {
259+
switch (callParameters.getMethodName()) {
260+
case "[]=":
261+
return InlinedIndexSetNodeGen.create(context, callParameters, self, args[0], args[1]);
262+
default:
263+
}
247264
}
248265

249266
return new RubyCallNode(callParameters);
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. This
3+
* code is released under a tri EPL/GPL/LGPL license. You can use it,
4+
* redistribute it and/or modify it under the terms of the:
5+
*
6+
* Eclipse Public License version 2.0, or
7+
* GNU General Public License version 2, or
8+
* GNU Lesser General Public License version 2.1.
9+
*/
10+
package org.truffleruby.core.inlined;
11+
12+
import org.truffleruby.RubyContext;
13+
import org.truffleruby.core.array.ArrayIndexNodes;
14+
import org.truffleruby.core.array.RubyArray;
15+
import org.truffleruby.language.dispatch.RubyCallNodeParameters;
16+
import org.truffleruby.language.methods.LookupMethodOnSelfNode;
17+
18+
import com.oracle.truffle.api.dsl.Cached;
19+
import com.oracle.truffle.api.dsl.Specialization;
20+
import com.oracle.truffle.api.frame.VirtualFrame;
21+
import com.oracle.truffle.api.profiles.ConditionProfile;
22+
23+
public abstract class InlinedAtNode extends BinaryInlinedOperationNode {
24+
25+
protected static final String METHOD = "at";
26+
27+
public InlinedAtNode(RubyContext context, RubyCallNodeParameters callNodeParameters) {
28+
super(context, callNodeParameters);
29+
}
30+
31+
@Specialization(
32+
guards = "lookupNode.lookupProtected(frame, array, METHOD) == coreMethods().ARRAY_AT",
33+
assumptions = "assumptions",
34+
limit = "1")
35+
protected Object arrayAt(VirtualFrame frame, RubyArray array, int index,
36+
@Cached LookupMethodOnSelfNode lookupNode,
37+
@Cached ArrayIndexNodes.ReadNormalizedNode readNormalizedNode,
38+
@Cached ConditionProfile denormalized) {
39+
if (denormalized.profile(index < 0)) {
40+
index += array.size;
41+
}
42+
return readNormalizedNode.executeRead(array, index);
43+
}
44+
45+
@Specialization
46+
protected Object fallback(VirtualFrame frame, Object a, Object b) {
47+
return rewriteAndCall(frame, a, b);
48+
}
49+
50+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. This
3+
* code is released under a tri EPL/GPL/LGPL license. You can use it,
4+
* redistribute it and/or modify it under the terms of the:
5+
*
6+
* Eclipse Public License version 2.0, or
7+
* GNU General Public License version 2, or
8+
* GNU Lesser General Public License version 2.1.
9+
*/
10+
package org.truffleruby.core.inlined;
11+
12+
import com.oracle.truffle.api.profiles.ConditionProfile;
13+
import org.truffleruby.RubyContext;
14+
import org.truffleruby.core.array.ArrayIndexNodes;
15+
import org.truffleruby.core.array.RubyArray;
16+
import org.truffleruby.language.dispatch.RubyCallNodeParameters;
17+
import org.truffleruby.language.methods.LookupMethodOnSelfNode;
18+
19+
import com.oracle.truffle.api.dsl.Cached;
20+
import com.oracle.truffle.api.dsl.Specialization;
21+
import com.oracle.truffle.api.frame.VirtualFrame;
22+
23+
public abstract class InlinedIndexGetNode extends BinaryInlinedOperationNode {
24+
25+
protected static final String METHOD = "[]";
26+
27+
public InlinedIndexGetNode(RubyContext context, RubyCallNodeParameters callNodeParameters) {
28+
super(context, callNodeParameters);
29+
}
30+
31+
@Specialization(
32+
guards = "lookupNode.lookupProtected(frame, array, METHOD) == coreMethods().ARRAY_INDEX_GET",
33+
assumptions = "assumptions",
34+
limit = "1")
35+
protected Object arrayRead(VirtualFrame frame, RubyArray array, int index,
36+
@Cached LookupMethodOnSelfNode lookupNode,
37+
@Cached ArrayIndexNodes.ReadNormalizedNode readNormalizedNode,
38+
@Cached ConditionProfile denormalized) {
39+
if (denormalized.profile(index < 0)) {
40+
index += array.size;
41+
}
42+
return readNormalizedNode.executeRead(array, index);
43+
}
44+
45+
@Specialization
46+
protected Object fallback(VirtualFrame frame, Object a, Object b) {
47+
return rewriteAndCall(frame, a, b);
48+
}
49+
50+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. This
3+
* code is released under a tri EPL/GPL/LGPL license. You can use it,
4+
* redistribute it and/or modify it under the terms of the:
5+
*
6+
* Eclipse Public License version 2.0, or
7+
* GNU General Public License version 2, or
8+
* GNU Lesser General Public License version 2.1.
9+
*/
10+
package org.truffleruby.core.inlined;
11+
12+
import com.oracle.truffle.api.dsl.Bind;
13+
import org.truffleruby.RubyContext;
14+
import org.truffleruby.core.array.ArrayWriteNormalizedNode;
15+
import org.truffleruby.core.array.RubyArray;
16+
import org.truffleruby.language.dispatch.RubyCallNodeParameters;
17+
import org.truffleruby.language.methods.LookupMethodOnSelfNode;
18+
19+
import com.oracle.truffle.api.dsl.Cached;
20+
import com.oracle.truffle.api.dsl.Specialization;
21+
import com.oracle.truffle.api.frame.VirtualFrame;
22+
import com.oracle.truffle.api.profiles.ConditionProfile;
23+
24+
public abstract class InlinedIndexSetNode extends TernaryInlinedOperationNode {
25+
26+
protected static final String METHOD = "[]=";
27+
28+
public InlinedIndexSetNode(RubyContext context, RubyCallNodeParameters callNodeParameters) {
29+
super(context, callNodeParameters);
30+
}
31+
32+
@Specialization(
33+
guards = {
34+
"lookupNode.lookupProtected(frame, array, METHOD) == coreMethods().ARRAY_INDEX_SET",
35+
"normalizedIndex >= 0" },
36+
assumptions = "assumptions",
37+
limit = "1")
38+
protected Object arrayWrite(VirtualFrame frame, RubyArray array, int index, Object value,
39+
@Cached LookupMethodOnSelfNode lookupNode,
40+
@Cached ConditionProfile denormalized,
41+
@Bind("normalize(array, index, denormalized)") int normalizedIndex,
42+
@Cached ArrayWriteNormalizedNode writeNode) {
43+
return writeNode.executeWrite(array, normalizedIndex, value);
44+
}
45+
46+
@Specialization
47+
protected Object fallback(VirtualFrame frame, Object a, Object b, Object c) {
48+
return rewriteAndCall(frame, a, b, c);
49+
}
50+
51+
protected int normalize(RubyArray array, int index, ConditionProfile denormalized) {
52+
if (denormalized.profile(index < 0)) {
53+
index += array.size;
54+
}
55+
return index;
56+
}
57+
58+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. This
3+
* code is released under a tri EPL/GPL/LGPL license. You can use it,
4+
* redistribute it and/or modify it under the terms of the:
5+
*
6+
* Eclipse Public License version 2.0, or
7+
* GNU General Public License version 2, or
8+
* GNU Lesser General Public License version 2.1.
9+
*/
10+
package org.truffleruby.core.inlined;
11+
12+
import org.truffleruby.RubyContext;
13+
import org.truffleruby.language.RubyNode;
14+
import org.truffleruby.language.dispatch.RubyCallNodeParameters;
15+
16+
import com.oracle.truffle.api.Assumption;
17+
import com.oracle.truffle.api.dsl.NodeChild;
18+
19+
@NodeChild(value = "receiver", type = RubyNode.class)
20+
@NodeChild(value = "operand1", type = RubyNode.class)
21+
@NodeChild(value = "operand2", type = RubyNode.class)
22+
public abstract class TernaryInlinedOperationNode extends InlinedOperationNode {
23+
24+
public TernaryInlinedOperationNode(
25+
RubyContext context,
26+
RubyCallNodeParameters callNodeParameters,
27+
Assumption... assumptions) {
28+
super(context, callNodeParameters, assumptions);
29+
}
30+
31+
protected abstract RubyNode getReceiver();
32+
33+
protected abstract RubyNode getOperand1();
34+
35+
protected abstract RubyNode getOperand2();
36+
37+
@Override
38+
protected RubyNode getReceiverNode() {
39+
return getReceiver();
40+
}
41+
42+
@Override
43+
protected RubyNode[] getArgumentNodes() {
44+
return new RubyNode[]{ getOperand1(), getOperand2() };
45+
}
46+
47+
}

0 commit comments

Comments
 (0)