Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Utilize packed 1-2 elt arrays more places in the codebase.
Browse files Browse the repository at this point in the history
This commit includes a pass over our code to improve places where
we are creating one or two-element arrays via the IRubyObject[]
paths, so they will use packed arrays when possible. I did this
survey by applying the patch (below) and running ruby/spec,
various gem commands, and starting up and hitting a blank rails
application.

The pattern used for most of these changes is as follows:

* Allocate a new "blank" array with RubyArray.newBlankArray(size).
* Popululate at least the first 'size' elements. This is
  necessary since the packed arrays can only represent exactly
  one or two elements, and must be unpacked to represent other
  sizes.

Most cases found in the survey were updated to this new pattern
and now will create packed forms. Notable exceptions that I
skipped (usually due to algorithms that had unpredictable sizing)
were:

* RubyString.enumerate[chars,codepoints] - Because of the variable
  width of characters in multibyte, this logic was difficult to
  connect up to an "exactly this size" array. It should be
  possible to use packed arrays for 7-bit cases, or to be smarter
  about small strings with one or two codepoints, but I have not
  attempted that here.
* RubyArray.values_at - Because the incoming arguments may not
  represent exactly how many items will be pulled from the array
  (e.g if you pass in a Range).
* RubyStruct.values_at - Same reasons as for RubyArray.values_at.
* SelectExecutor's construction of result arrays - Because some
  or all of the expected channels may not be ready, it would
  require more logic to right-size the arrays. This is a heavily-
  hit piece of logic and such an improvement may be warranted,
  but there's significantly more overhead in SelectExecutor that
  needs a rewrite before packed arrays would show any significant
  improvement.

The patch mentioned above follows.

```diff
diff --git a/core/src/main/java/org/jruby/RubyArray.java b/core/src/main/java/org/jruby/RubyArray.java
index d2bc419..180af8f 100644
--- a/core/src/main/java/org/jruby/RubyArray.java
+++ b/core/src/main/java/org/jruby/RubyArray.java
@@ -160,26 +160,30 @@ public class RubyArray extends RubyObject implements List, RandomAccess {

     /** rb_ary_new2
      *
      */
     public static final RubyArray newArray(final Ruby runtime, final long len) {
+        if (len == 1 || len == 2) Thread.dumpStack();
         checkLength(runtime, len);
         return newArray(runtime, (int)len);
     }

     public static final RubyArray newArrayLight(final Ruby runtime, final long len) {
+        if (len == 1 || len == 2) Thread.dumpStack();
         checkLength(runtime, len);
         return newArrayLight(runtime, (int)len);
     }

     public static final RubyArray newArray(final Ruby runtime, final int len) {
+        if (len == 1 || len == 2) Thread.dumpStack();
         RubyArray array = new RubyArray(runtime, len);
         Helpers.fillNil(array.values, 0, len, runtime);
         return array;
     }

     public static final RubyArray newArrayLight(final Ruby runtime, final int len) {
+        if (len == 1 || len == 2) Thread.dumpStack();
         RubyArray array = new RubyArray(runtime, len, false);
         Helpers.fillNil(array.values, 0, len, runtime);
         return array;
     }

```
headius committed Jun 30, 2016
1 parent 468b4e3 commit fa6e09c
Showing 11 changed files with 189 additions and 107 deletions.
132 changes: 112 additions & 20 deletions core/src/main/java/org/jruby/RubyArray.java
Original file line number Diff line number Diff line change
@@ -272,12 +272,22 @@ public static RubyArray newArray(Ruby runtime, Collection<? extends IRubyObject>
// than the cost of constructing and walking an Iterator.
IRubyObject[] values = collection.toArray(new IRubyObject[collection.size()]);
switch (values.length) {
case 0: return newEmptyArray(runtime);
case 1: return new RubyArrayOneObject(runtime, values[0]);
case 2: return new RubyArrayTwoObject(runtime, values[0], values[1]);
}
return new RubyArray(runtime, values);
}

public static RubyArray newArray(Ruby runtime, List<? extends IRubyObject> list) {
switch (list.size()) {
case 0: return newEmptyArray(runtime);
case 1: return new RubyArrayOneObject(runtime, list.get(0));
case 2: return new RubyArrayTwoObject(runtime, list.get(0), list.get(1));
}
return new RubyArray(runtime, list.toArray(new IRubyObject[list.size()]));
}

public static final int ARRAY_DEFAULT_SIZE = 16;

// volatile to ensure that initial nil-fill is visible to other threads
@@ -1048,9 +1058,9 @@ public RubyArray transpose() {
tmp = elt(i).convertToArray();
if (elen < 0) {
elen = tmp.realLength;
result = newArray(runtime, elen);
result = newBlankArray(runtime, elen);
for (int j = 0; j < elen; j++) {
result.store(j, newArray(runtime, alen));
result.store(j, newBlankArray(runtime, alen));
}
} else if (elen != tmp.realLength) {
throw runtime.newIndexError("element size differs (" + tmp.realLength
@@ -2437,6 +2447,29 @@ public IRubyObject map_bang(ThreadContext context, Block block) {
*/
public IRubyObject selectCommon(ThreadContext context, Block block) {
final Ruby runtime = context.runtime;

// Packed array logic
switch (realLength) {
case 1: {
IRubyObject value = eltOk(0);
if (block.yield(context, value).isTrue()) return new RubyArrayOneObject(runtime, value);
return newEmptyArray(runtime);
}
case 2: {
IRubyObject value = eltOk(0);
boolean first = block.yield(context, value).isTrue();
IRubyObject value2 = eltOk(1);
boolean second = block.yield(context, value2).isTrue();
if (first) {
if (second) return new RubyArrayTwoObject(runtime, value, value2);
return new RubyArrayOneObject(runtime, value);
} else if (second) {
return new RubyArrayOneObject(runtime, value2);
}
return newEmptyArray(runtime);
}
}

RubyArray result = newArray(runtime, realLength);

for (int i = 0; i < realLength; i++) {
@@ -3066,9 +3099,25 @@ public IRubyObject nitems() {
*/
@JRubyMethod(name = "+", required = 1)
public IRubyObject op_plus(IRubyObject obj) {
Ruby runtime = getRuntime();
RubyArray y = obj.convertToArray();
int len = realLength + y.realLength;
RubyArray z = newArray(getRuntime(), len);

switch (len) {
case 1:
return new RubyArrayOneObject(runtime, realLength == 1 ? eltInternal(0) : y.eltInternal(0));
case 2:
switch (realLength) {
case 0:
return new RubyArrayTwoObject(runtime, y.eltInternal(0), y.eltInternal(1));
case 1:
return new RubyArrayTwoObject(runtime, eltInternal(0), y.eltInternal(0));
case 2:
return new RubyArrayTwoObject(runtime, eltInternal(0), eltInternal(1));
}
}

RubyArray z = newArray(runtime, len);
try {
copyInto(z.values, 0);
y.copyInto(z.values, realLength);
@@ -3184,7 +3233,7 @@ public IRubyObject uniq_bang19(ThreadContext context, Block block) {

realLength = 0;

hash.visitAll(context, RubyHash.AppendValueVisitor, this);
hash.visitAll(context, RubyHash.StoreValueVisitor, this);
return this;
}

@@ -3216,7 +3265,7 @@ public IRubyObject uniq19(ThreadContext context, Block block) {
RubyHash hash = makeHash(context, block);

RubyArray result = new RubyArray(context.runtime, getMetaClass(), hash.size());
hash.visitAll(context, RubyHash.AppendValueVisitor, result);
hash.visitAll(context, RubyHash.StoreValueVisitor, result);
return result;
}

@@ -3247,16 +3296,25 @@ public IRubyObject op_diff(IRubyObject other) {
*/
@JRubyMethod(name = "&", required = 1)
public IRubyObject op_and(IRubyObject other) {
Ruby runtime = getRuntime();
RubyArray ary2 = other.convertToArray();
RubyHash hash = ary2.makeHash();
RubyArray ary3 = newArray(getRuntime(), realLength < ary2.realLength ? realLength : ary2.realLength);

int maxSize = realLength < ary2.realLength ? realLength : ary2.realLength;

if (maxSize == 0) return newEmptyArray(runtime);

RubyArray ary3 = newBlankArray(runtime, maxSize);

int index = 0;
for (int i = 0; i < realLength; i++) {
IRubyObject v = elt(i);
if (hash.fastDelete(v)) ary3.append(v);
if (hash.fastDelete(v)) ary3.store(index++, v);
}

Helpers.fillNil(ary3.values, ary3.realLength, ary3.values.length, getRuntime());
// if index is 1 and we made a size 2 array, repack
if (index == 0) return newEmptyArray(runtime);
if (index == 1 && maxSize == 2) return newArray(runtime, ary3.eltInternal(0));

return ary3;
}
@@ -3266,21 +3324,28 @@ public IRubyObject op_and(IRubyObject other) {
*/
@JRubyMethod(name = "|", required = 1)
public IRubyObject op_or(IRubyObject other) {
Ruby runtime = getRuntime();
RubyArray ary2 = other.convertToArray();
RubyHash set = makeHash(ary2);

RubyArray ary3 = newArray(getRuntime(), realLength + ary2.realLength);
int maxSize = realLength + ary2.realLength;

if (maxSize == 0) return newEmptyArray(runtime);

RubyArray ary3 = newBlankArray(runtime, maxSize);

int index = 0;
for (int i = 0; i < realLength; i++) {
IRubyObject v = elt(i);
if (set.fastDelete(v)) ary3.append(v);
if (set.fastDelete(v)) ary3.store(index++, v);
}
for (int i = 0; i < ary2.realLength; i++) {
IRubyObject v = ary2.elt(i);
if (set.fastDelete(v)) ary3.append(v);
if (set.fastDelete(v)) ary3.store(index++, v);
}

Helpers.fillNil(ary3.values, ary3.realLength, ary3.values.length, getRuntime());
// if index is 1 and we made a size 2 array, repack
if (index == 1 && maxSize == 2) return newArray(runtime, ary3.eltInternal(0));

return ary3;
}
@@ -3543,16 +3608,16 @@ public IRubyObject product(ThreadContext context, IRubyObject[] args, Block bloc
}
}

RubyArray result = useBlock ? null : newArray(runtime, resultLen);
RubyArray result = useBlock ? null : newBlankArray(runtime, resultLen);

for (int i = 0; i < resultLen; i++) {
RubyArray sub = newArray(runtime, n);
for (int j = 0; j < n; j++) sub.append(arrays[j].entry(counters[j]));
RubyArray sub = newBlankArray(runtime, n);
for (int j = 0; j < n; j++) sub.store(j, arrays[j].entry(counters[j]));

if (useBlock) {
block.yieldSpecific(context, sub);
} else {
result.append(sub);
result.store(i, sub);
}
int m = n - 1;
counters[m]++;
@@ -3735,10 +3800,10 @@ private static void permute(ThreadContext context, int n, int r, int[] p, boolea
}

private static void yieldValues(ThreadContext context, int r, int[] p, int pStart, RubyArray values, Block block) {
RubyArray result = newArray(context.runtime, r);
RubyArray result = newBlankArray(context.runtime, r);

for (int j = 0; j < r; j++) {
result.eltInternalSet(j, values.eltInternal(p[j + pStart]));
result.store(j, values.eltInternal(p[j + pStart]));
}

result.realLength = r;
@@ -4206,20 +4271,47 @@ public static void marshalTo(RubyArray array, MarshalStream output) throws IOExc
}

public static RubyArray unmarshalFrom(UnmarshalStream input) throws IOException {
Ruby runtime = input.getRuntime();
int size = input.unmarshalInt();

// we create this now with an empty, nulled array so it's available for links in the marshal data
RubyArray result = input.getRuntime().newArray(size);
RubyArray result = newBlankArray(runtime, size);

input.registerLinkTarget(result);

for (int i = 0; i < size; i++) {
result.append(input.unmarshalObject());
result.store(i, input.unmarshalObject());
}

return result;
}

/**
* Construct the most efficient array shape for the given size. This should only be used when you
* intend to populate all elements, since the packed arrays will be born with a nonzero size and
* would have to be unpacked to partially populate.
*
* We nil-fill all cases, to ensure nulls will never leak out if there's an unpopulated element
* or an index accessed before assignment.
*
* @param runtime the runtime
* @param size the size
* @return a RubyArray shaped for the given size
*/
public static RubyArray newBlankArray(Ruby runtime, int size) {
RubyArray result;
switch (size) {
case 0:
return newEmptyArray(runtime);
case 1:
return new RubyArrayOneObject(runtime, runtime.getNil());
case 2:
return new RubyArrayTwoObject(runtime, runtime.getNil(), runtime.getNil());
default:
return newArray(runtime, size);
}
}

@JRubyMethod(name = "try_convert", meta = true)
public static IRubyObject try_convert(ThreadContext context, IRubyObject self, IRubyObject arg) {
return arg.checkArrayType();
14 changes: 9 additions & 5 deletions core/src/main/java/org/jruby/RubyBasicObject.java
Original file line number Diff line number Diff line change
@@ -2777,11 +2777,13 @@ public IRubyObject remove_instance_variable(ThreadContext context, IRubyObject n
public RubyArray instance_variables(ThreadContext context) {
Ruby runtime = context.runtime;
List<String> nameList = getInstanceVariableNameList();
int size = nameList.size();

RubyArray array = runtime.newArray(nameList.size());

for (String name : nameList) {
array.append(runtime.newString(name));
for (int i = 0; i < size; i++) {
String name = nameList.get(i);
array.store(i, runtime.newString(name));
}

return array;
@@ -2791,11 +2793,13 @@ public RubyArray instance_variables(ThreadContext context) {
public RubyArray instance_variables19(ThreadContext context) {
Ruby runtime = context.runtime;
List<String> nameList = getInstanceVariableNameList();
int size = nameList.size();

RubyArray array = runtime.newArray(nameList.size());
RubyArray array = RubyArray.newBlankArray(runtime, nameList.size());

for (String name : nameList) {
array.append(runtime.newSymbol(name));
for (int i = 0; i < size; i++) {
String name = nameList.get(i);
array.store(i, runtime.newSymbol(name));
}

return array;
34 changes: 16 additions & 18 deletions core/src/main/java/org/jruby/RubyEnumerable.java
Original file line number Diff line number Diff line change
@@ -1717,11 +1717,12 @@ public static IRubyObject zipCommonAry(ThreadContext context, IRubyObject self,

public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
IRubyObject larg = packEnumValues(ctx, largs);
RubyArray array = runtime.newArray(len);
RubyArray array = RubyArray.newBlankArray(runtime, len);
int myIx = ix.getAndIncrement();
array.append(larg);
int index = 0;
array.store(index++, larg);
for (int i = 0, j = args.length; i < j; i++) {
array.append(((RubyArray) args[i]).entry(myIx));
array.store(index++, ((RubyArray) args[i]).entry(myIx));
}
block.yield(ctx, array);
return runtime.getNil();
@@ -1735,11 +1736,12 @@ public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {

public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
IRubyObject larg = packEnumValues(ctx, largs);
RubyArray array = runtime.newArray(len);
array.append(larg);
RubyArray array = RubyArray.newBlankArray(runtime, len);
int index = 0;
array.store(index++, larg);
int myIx = ix.getAndIncrement();
for (int i = 0, j = args.length; i < j; i++) {
array.append(((RubyArray) args[i]).entry(myIx));
array.store(index++, ((RubyArray) args[i]).entry(myIx));
}
synchronized (zip) {
zip.append(array);
@@ -1760,15 +1762,13 @@ public static IRubyObject zipCommonEnum(ThreadContext context, IRubyObject self,

if (block.isGiven()) {
callEach(runtime, context, self, block.getSignature(), new BlockCallback() {
AtomicInteger ix = new AtomicInteger(0);

public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
IRubyObject larg = packEnumValues(ctx, largs);
RubyArray array = runtime.newArray(len);
int myIx = ix.getAndIncrement();
array.append(larg);
RubyArray array = RubyArray.newBlankArray(runtime, len);
int index = 0;
array.store(index++, larg);
for (int i = 0, j = args.length; i < j; i++) {
array.append(zipEnumNext(ctx, args[i]));
array.store(index++, zipEnumNext(ctx, args[i]));
}
block.yield(ctx, array);
return runtime.getNil();
@@ -1778,15 +1778,13 @@ public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
} else {
final RubyArray zip = runtime.newArray();
callEach(runtime, context, self, Signature.ONE_REQUIRED, new BlockCallback() {
AtomicInteger ix = new AtomicInteger(0);

public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
IRubyObject larg = packEnumValues(ctx, largs);
RubyArray array = runtime.newArray(len);
array.append(larg);
int myIx = ix.getAndIncrement();
RubyArray array = RubyArray.newBlankArray(runtime, len);
int index = 0;
array.store(index++, larg);
for (int i = 0, j = args.length; i < j; i++) {
array.append(zipEnumNext(ctx, args[i]));
array.store(index++, zipEnumNext(ctx, args[i]));
}
synchronized (zip) {
zip.append(array);
42 changes: 16 additions & 26 deletions core/src/main/java/org/jruby/RubyHash.java
Original file line number Diff line number Diff line change
@@ -57,8 +57,6 @@
import org.jruby.runtime.invokedynamic.MethodNames;
import org.jruby.runtime.marshal.MarshalStream;
import org.jruby.runtime.marshal.UnmarshalStream;
import org.jruby.specialized.RubyArrayOneObject;
import org.jruby.specialized.RubyArrayTwoObject;
import org.jruby.util.RecursiveComparator;
import org.jruby.util.TypeConverter;

@@ -880,9 +878,9 @@ public RubyBoolean empty_p() {
public RubyArray to_a() {
final Ruby runtime = getRuntime();
try {
final RubyArray result = RubyArray.newArray(runtime, size);
final RubyArray result = RubyArray.newBlankArray(runtime, size);

visitAll(runtime.getCurrentContext(), RubyHash.AppendKeyValueVisitor, result);
visitAll(runtime.getCurrentContext(), RubyHash.StoreKeyValueVisitor, result);

result.setTaint(isTaint());
return result;
@@ -891,10 +889,10 @@ public RubyArray to_a() {
}
}

private static final VisitorWithState<RubyArray> AppendKeyValueVisitor = new VisitorWithState<RubyArray>() {
private static final VisitorWithState<RubyArray> StoreKeyValueVisitor = new VisitorWithState<RubyArray>() {
@Override
public void visit(ThreadContext context, RubyHash self, IRubyObject key, IRubyObject value, int index, RubyArray result) {
result.append(RubyArray.newArray(context.runtime, key, value));
result.store(index, RubyArray.newArray(context.runtime, key, value));
}
};

@@ -1615,20 +1613,20 @@ public void visit(ThreadContext context, RubyHash self, IRubyObject key, IRubyOb
public RubyArray keys() {
Ruby runtime = getRuntime();
try {
RubyArray keys = RubyArray.newArray(runtime, size);
RubyArray keys = RubyArray.newBlankArray(runtime, size);

visitAll(runtime.getCurrentContext(), AppendKeyVisitor, keys);
visitAll(runtime.getCurrentContext(), StoreKeyVisitor, keys);

return keys;
} catch (NegativeArraySizeException nase) {
throw concurrentModification();
}
}

private static final VisitorWithState<RubyArray> AppendKeyVisitor = new VisitorWithState<RubyArray>() {
private static final VisitorWithState<RubyArray> StoreKeyVisitor = new VisitorWithState<RubyArray>() {
@Override
public void visit(ThreadContext context, RubyHash self, IRubyObject key, IRubyObject value, int index, RubyArray keys) {
keys.append(key);
keys.store(index, key);
}
};

@@ -1639,28 +1637,20 @@ public void visit(ThreadContext context, RubyHash self, IRubyObject key, IRubyOb
public RubyArray rb_values() {
Ruby runtime = getRuntime();
try {
final RubyArray values;
if (size == 1) {
values = new RubyArrayOneObject(runtime, head.nextAdded.value);
} else if (size == 2) {
RubyHashEntry nextAdded = head.nextAdded;
values = new RubyArrayTwoObject(runtime, nextAdded.value, nextAdded.nextAdded.value);
} else {
values = RubyArray.newArray(getRuntime(), size);
RubyArray values = RubyArray.newBlankArray(runtime, size);

visitAll(runtime.getCurrentContext(), AppendValueVisitor, values);
}
visitAll(runtime.getCurrentContext(), StoreValueVisitor, values);

return values;
} catch (NegativeArraySizeException nase) {
throw concurrentModification();
}
}

public static final VisitorWithState<RubyArray> AppendValueVisitor = new VisitorWithState<RubyArray>() {
public static final VisitorWithState<RubyArray> StoreValueVisitor = new VisitorWithState<RubyArray>() {
@Override
public void visit(ThreadContext context, RubyHash self, IRubyObject key, IRubyObject value, int index, RubyArray values) {
values.append(value);
values.store(index, value);
}
};

@@ -1929,19 +1919,19 @@ public void visit(ThreadContext context, RubyHash self, IRubyObject key, IRubyOb
*/
@JRubyMethod(name = "values_at", rest = true)
public RubyArray values_at(ThreadContext context, IRubyObject[] args) {
RubyArray result = RubyArray.newArray(context.runtime, args.length);
RubyArray result = RubyArray.newBlankArray(context.runtime, args.length);
for (int i = 0; i < args.length; i++) {
result.append(op_aref(context, args[i]));
result.store(i, op_aref(context, args[i]));
}
return result;
}

@JRubyMethod(name = "fetch_values", rest = true)
public RubyArray fetch_values(ThreadContext context, IRubyObject[] args, Block block) {
RubyArray result = RubyArray.newArray(context.runtime, args.length);
RubyArray result = RubyArray.newBlankArray(context.runtime, args.length);

for (int i = 0; i < args.length; i++) {
result.append(fetch(context, args[i], block));
result.store(i, fetch(context, args[i], block));
}
return result;
}
12 changes: 7 additions & 5 deletions core/src/main/java/org/jruby/RubyMatchData.java
Original file line number Diff line number Diff line change
@@ -314,22 +314,24 @@ private static RubyString makeShared(Ruby runtime, RubyString str, int index, in

private RubyArray match_array(Ruby runtime, int start) {
check();
IRubyObject nil = runtime.getNil();
if (regs == null) {
if (start != 0) return runtime.newEmptyArray();
if (begin == -1) {
return runtime.newArray(runtime.getNil());
return runtime.newArray(nil);
} else {
RubyString ss = makeShared(runtime, str, begin, end - begin);
return runtime.newArray( ss.infectBy(this) );
}
} else {
RubyArray arr = runtime.newArray(regs.numRegs - start);
for (int i=start; i<regs.numRegs; i++) {
RubyArray arr = RubyArray.newBlankArray(runtime, regs.numRegs - start);
int index = 0;
for (int i=start; i < regs.numRegs; i++) {
if (regs.beg[i] == -1) {
arr.append(runtime.getNil());
arr.store(index++, nil);
} else {
RubyString ss = makeShared(runtime, str, regs.beg[i], regs.end[i] - regs.beg[i]);
arr.append( ss.infectBy(this) );
arr.store(index++, ss.infectBy(this));
}
}
return arr;
1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/RubyRange.java
Original file line number Diff line number Diff line change
@@ -710,6 +710,7 @@ public IRubyObject first(ThreadContext context, IRubyObject arg) {
if (num < 0) {
throw context.runtime.newArgumentError("negative array size (or size too big)");
}
// TODO (CON): this could be packed if we know there are at least num elements in range
final RubyArray result = runtime.newArray(num);
try {
RubyEnumerable.callEach(runtime, context, this, Signature.ONE_ARGUMENT, new BlockCallback() {
10 changes: 6 additions & 4 deletions core/src/main/java/org/jruby/RubyRegexp.java
Original file line number Diff line number Diff line change
@@ -1431,11 +1431,12 @@ public IRubyObject names(ThreadContext context) {
final Ruby runtime = context.runtime;
if (pattern.numberOfNames() == 0) return runtime.newEmptyArray();

RubyArray ary = runtime.newArray(pattern.numberOfNames());
RubyArray ary = RubyArray.newBlankArray(runtime, pattern.numberOfNames());
int index = 0;
for (Iterator<NameEntry> i = pattern.namedBackrefIterator(); i.hasNext();) {
NameEntry e = i.next();
RubyString name = RubyString.newStringShared(runtime, e.name, e.nameP, e.nameEnd - e.nameP, pattern.getEncoding());
ary.append(name);
ary.store(index++, name);
}
return ary;
}
@@ -1453,10 +1454,11 @@ public IRubyObject named_captures(ThreadContext context) {
for (Iterator<NameEntry> i = pattern.namedBackrefIterator(); i.hasNext();) {
NameEntry e = i.next();
int[] backrefs = e.getBackRefs();
RubyArray ary = runtime.newArray(backrefs.length);
RubyArray ary = RubyArray.newBlankArray(runtime, backrefs.length);

int index = 0;
for (int backref : backrefs) {
ary.append(RubyFixnum.newFixnum(runtime, backref));
ary.store(index++, RubyFixnum.newFixnum(runtime, backref));
}
RubyString name = RubyString.newStringShared(runtime, e.name, e.nameP, e.nameEnd - e.nameP);
hash.fastASet(name.freeze(context), ary);
14 changes: 8 additions & 6 deletions core/src/main/java/org/jruby/RubyString.java
Original file line number Diff line number Diff line change
@@ -3807,9 +3807,11 @@ private static IRubyObject scanOnce(ThreadContext context, RubyString str, IRuby
if (match.numRegs() == 1) {
return RubyRegexp.nth_match(0, match);
}
RubyArray result = context.runtime.newArray(match.numRegs());
for (int i = 1; i < match.numRegs(); i++) {
result.push(RubyRegexp.nth_match(i, match));
int size = match.numRegs();
RubyArray result = RubyArray.newBlankArray(context.runtime, size - 1);
int index = 0;
for (int i = 1; i < size; i++) {
result.store(index++, RubyRegexp.nth_match(i, match));
}

return result;
@@ -5135,15 +5137,15 @@ private IRubyObject enumerateBytes(ThreadContext context, String name, Block blo
}
else {
if (wantarray)
ary = RubyArray.newArray(runtime, str.size());
ary = RubyArray.newBlankArray(runtime, str.size());
else
return enumeratorizeWithSize(context, str, name, eachByteSizeFn());
}

for (i=0; i<str.size(); i++) {
for (i=0; i < str.size(); i++) {
RubyFixnum bite = RubyFixnum.newFixnum(runtime, str.getByteList().get(i) & 0xff);
if (wantarray)
ary.push(bite);
ary.store(i, bite);
else
block.yield(context, bite);
}
24 changes: 7 additions & 17 deletions core/src/main/java/org/jruby/RubyStruct.java
Original file line number Diff line number Diff line change
@@ -390,25 +390,10 @@ public static RubyArray members(IRubyObject recv, Block block) {

final RubyArray member = __member__((RubyClass) recv);
final int len = member.getLength();
RubyArray result = runtime.newArray(len);
RubyArray result = RubyArray.newBlankArray(runtime, len);

for ( int i = 0; i < len; i++ ) {
// this looks weird, but it's because they're RubySymbol and that's java.lang.String internally
result.append( runtime.newString(member.eltInternal(i).asJavaString()) );
}

return result;
}

public static RubyArray members19(IRubyObject recv, Block block) {
final Ruby runtime = recv.getRuntime();

final RubyArray member = __member__((RubyClass) recv);
final int len = member.getLength();
RubyArray result = runtime.newArray(len);

for ( int i = 0; i < len; i++ ) {
result.append( member.eltInternal(i) );
result.store(i, member.eltInternal(i));
}

return result;
@@ -865,4 +850,9 @@ public DynamicMethod dup() {
return new Accessor((RubyClass) getImplementationClass(), index);
}
}

@Deprecated
public static RubyArray members19(IRubyObject recv, Block block) {
return members(recv, block);
}
}
6 changes: 3 additions & 3 deletions core/src/main/java/org/jruby/RubyThread.java
Original file line number Diff line number Diff line change
@@ -488,9 +488,9 @@ public static RubyArray newLocationArray(Ruby runtime, RubyStackTraceElement[] e
final int offset, final int length) {
final RubyClass locationClass = runtime.getLocation();

RubyArray ary = runtime.newArray(length);
for ( int i = offset; i < offset + length; i++ ) {
ary.append(new RubyThread.Location(runtime, locationClass, elements[i]));
RubyArray ary = RubyArray.newBlankArray(runtime, length);
for ( int i = 0; i < length; i++ ) {
ary.store(i, new RubyThread.Location(runtime, locationClass, elements[i + offset]));
}

return ary;
7 changes: 4 additions & 3 deletions core/src/main/java/org/jruby/runtime/Helpers.java
Original file line number Diff line number Diff line change
@@ -2401,10 +2401,11 @@ public static ArgumentDescriptor[] parameterListToArgumentDescriptors(String[] p
public static RubyArray argumentDescriptorsToParameters(Ruby runtime, ArgumentDescriptor[] argsDesc, boolean isLambda) {
if (argsDesc == null) Thread.dumpStack();

final RubyArray params = RubyArray.newArray(runtime, argsDesc.length);
final RubyArray params = RubyArray.newBlankArray(runtime, argsDesc.length);

for (ArgumentDescriptor param : argsDesc) {
params.append( param.toArrayForm(runtime, isLambda) );
for (int i = 0; i < argsDesc.length; i++) {
ArgumentDescriptor param = argsDesc[i];
params.store(i, param.toArrayForm(runtime, isLambda));
}

return params;

0 comments on commit fa6e09c

Please sign in to comment.