Skip to content

Commit

Permalink
Various optimizations for array creation
Browse files Browse the repository at this point in the history
* Use more newRawArray where appropriate
* Use newEmptyArray for more arrays intended to be empty
* Provide "each" logic for global names
* More efficient iteration of Java methods in JavaLang Class ext
  • Loading branch information
headius committed Dec 4, 2024
1 parent dd6068f commit bfb53c8
Show file tree
Hide file tree
Showing 13 changed files with 102 additions and 56 deletions.
33 changes: 19 additions & 14 deletions core/src/main/java/org/jruby/RubyArray.java
Original file line number Diff line number Diff line change
Expand Up @@ -1035,9 +1035,9 @@ public IRubyObject fetch_values(ThreadContext context, IRubyObject[] args, Block
// FIXME: lookup the bounds part of this in error message??
if (index >= arraySize) {
if (!block.isGiven()) throw context.runtime.newIndexError("index " + index + " outside of array bounds: 0...0");
result.append(block.yield(context, asFixnum(context, index)));
result.append(context, block.yield(context, asFixnum(context, index)));
} else {
result.append(eltOk(index));
result.append(context, eltOk(index));
}
}

Expand Down Expand Up @@ -1357,7 +1357,7 @@ public IRubyObject values_at(ThreadContext context, IRubyObject[] args) {
for (int i = 0; i < args.length; i++) {
final IRubyObject arg = args[i];
if (arg instanceof RubyFixnum fix) {
result.append(entry(fix.value));
result.append(context, entry(fix.value));
continue;
}

Expand All @@ -1370,11 +1370,11 @@ public IRubyObject values_at(ThreadContext context, IRubyObject[] args) {
final int beg = begLen[0];
final int len = begLen[1];
for (int j = 0; j < len; j++) {
result.append( entry(j + beg) );
result.append(context, entry(j + beg));
}
continue;
}
result.append(entry(numericToLong(context, arg)));
result.append(context, entry(numericToLong(context, arg)));
}

return result.finishRawArray(context);
Expand Down Expand Up @@ -1463,7 +1463,7 @@ public IRubyObject subseq_step(ThreadContext context, RubyArithmeticSequence arg
RubyArray result = result1;

for(long i = 0; i < len; ++i) {
result.append(eltOk(j));
result.append(context, eltOk(j));
j = j + step;
}

Expand Down Expand Up @@ -1596,7 +1596,7 @@ public RubyArray<?> push(IRubyObject[] items) {
public RubyArray push(ThreadContext context, IRubyObject[] items) {
if (items.length == 0) modifyCheck(context);
for (IRubyObject item : items) {
append(item);
append(context, item);
}
return this;
}
Expand Down Expand Up @@ -2919,7 +2919,8 @@ public RubyArray collectArray(ThreadContext context, Block block) {

for (int i = 0; i < realLength; i++) {
// Do not coarsen the "safe" check, since it will misinterpret AIOOBE from the yield (see JRUBY-5434)
ary.append(block.yieldNonArray(context, eltOk(i), null)); // arr[i] = ...
// arr[i] = ...
ary.append(context, block.yieldNonArray(context, eltOk(i), null));
}

return ary.finishRawArray(context);
Expand Down Expand Up @@ -3020,7 +3021,7 @@ public IRubyObject selectCommon(ThreadContext context, Block block) {
for (int i = 0; i < realLength; i++) {
// Do not coarsen the "safe" check, since it will misinterpret AIOOBE from the yield (see JRUBY-5434)
IRubyObject value = eltOk(i);
if (block.yield(context, value).isTrue()) result.append(value);
if (block.yield(context, value).isTrue()) result.append(context, value);
}

return result.finishRawArray(context);
Expand Down Expand Up @@ -3551,12 +3552,12 @@ protected boolean flatten(ThreadContext context, final int level, final RubyArra
while (i < ary.realLength) {
IRubyObject elt = ary.eltOk(i++);
if (level >= 0 && stack.size() / 2 >= level) {
result.append(elt);
result.append(context, elt);
continue;
}
tmp = TypeConverter.checkArrayType(context, elt);
if (tmp.isNil()) {
result.append(elt);
result.append(context, elt);
} else { // nested array element
if (memo != null) {
if (memo.get(tmp) != null) throw argumentError(context, "tried to flatten recursive array");
Expand Down Expand Up @@ -3926,7 +3927,7 @@ public IRubyObject difference(ThreadContext context, IRubyObject[] args) {
if (arrays[j].includesByEql(context, elt)) break;
}
}
if (j == args.length) diff.append(elt);
if (j == args.length) diff.append(context, elt);
}

return diff;
Expand Down Expand Up @@ -4094,7 +4095,7 @@ private void unionInternal(ThreadContext context, RubyArray... args) {
for (int j = 0; j < args[i].realLength; j++) {
IRubyObject elt = args[i].elt(j);
if (includesByEql(context, elt)) continue;
append(elt);
append(context, elt);
}
}
}
Expand Down Expand Up @@ -5824,7 +5825,11 @@ public <T> T toJava(Class<T> target) {
}

public boolean add(Object element) {
append(JavaUtil.convertJavaToUsableRubyObject(metaClass.runtime, element));
return add(getRuntime().getCurrentContext(), element);
}

public boolean add(ThreadContext context, Object element) {
append(context, JavaUtil.convertJavaToUsableRubyObject(metaClass.runtime, element));
return true;
}

Expand Down
3 changes: 2 additions & 1 deletion core/src/main/java/org/jruby/RubyGlobal.java
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,13 @@ public class RubyGlobal {
public static void initARGV(Ruby runtime) {
var context = runtime.getCurrentContext();
// define ARGV and $* for this runtime
var argvArray = newArray(context);
String[] argv = runtime.getInstanceConfig().getArgv();
var argvArray = newRawArray(context, argv.length);

for (String arg : argv) {
argvArray.append(context, RubyString.newInternalFromJavaExternal(runtime, arg));
}
argvArray.finishRawArray(context);

if (runtime.getObject().getConstantNoConstMissing("ARGV") != null) {
((RubyArray<?>)runtime.getObject().getConstant("ARGV")).replace(context, argvArray);
Expand Down
10 changes: 5 additions & 5 deletions core/src/main/java/org/jruby/RubyKernel.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
import org.jruby.exceptions.CatchThrow;
import org.jruby.exceptions.MainExitException;
import org.jruby.exceptions.RaiseException;
import org.jruby.internal.runtime.GlobalVariables;
import org.jruby.internal.runtime.methods.DynamicMethod;
import org.jruby.internal.runtime.methods.JavaMethod.JavaMethodNBlock;
import org.jruby.ir.interpreter.Interpreter;
Expand Down Expand Up @@ -948,13 +949,12 @@ private static void exit(Ruby runtime, IRubyObject[] args, boolean hard) {
*/
@JRubyMethod(name = "global_variables", module = true, visibility = PRIVATE)
public static RubyArray global_variables(ThreadContext context, IRubyObject recv) {
var globalVariables = newArray(context);
GlobalVariables globals = context.runtime.getGlobalVariables();
var globalVariables = newRawArray(context, globals.size());

for (String globalVariableName : context.runtime.getGlobalVariables().getNames()) {
globalVariables.append(context, asSymbol(context, globalVariableName));
}
globals.eachName(context, globalVariables, (c, g, s) -> g.append(c, asSymbol(c, s)));

return globalVariables;
return globalVariables.finishRawArray(context);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/org/jruby/RubyModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -4567,11 +4567,11 @@ public final void setConstantVisibility(Ruby runtime, String name, boolean hidde

@JRubyMethod(name = "refinements")
public IRubyObject refinements(ThreadContext context) {
var refinementModules = newArray(context);
var refinementModules = newRawArray(context, refinements.size());

refinements.forEach((key, value) -> refinementModules.append(context, value));

return refinementModules;
return refinementModules.finishRawArray(context);
}

@JRubyMethod(name = "target")
Expand Down
5 changes: 3 additions & 2 deletions core/src/main/java/org/jruby/ext/ffi/AbstractMemory.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import static org.jruby.api.Convert.*;
import static org.jruby.api.Create.newArray;
import static org.jruby.api.Create.newEmptyString;
import static org.jruby.api.Create.newRawArray;
import static org.jruby.api.Error.*;

/**
Expand Down Expand Up @@ -1861,7 +1862,7 @@ public IRubyObject get_string(ThreadContext context, IRubyObject offArg, IRubyOb
@JRubyMethod(name = { "get_array_of_string" })
public IRubyObject get_array_of_string(ThreadContext context, IRubyObject rbOffset) {
final int POINTER_SIZE = (Platform.getPlatform().addressSize() / 8);
final var arr = newArray(context);
final var arr = newRawArray(context, (size - POINTER_SIZE) / POINTER_SIZE);

for (long off = getOffset(rbOffset); off <= size - POINTER_SIZE; off += POINTER_SIZE) {
final MemoryIO mem = getMemoryIO().getMemoryIO(off);
Expand All @@ -1870,7 +1871,7 @@ public IRubyObject get_array_of_string(ThreadContext context, IRubyObject rbOffs
arr.add(MemoryUtil.getTaintedString(context.runtime, mem, 0));
}

return arr;
return arr.finishRawArray(context);
}

@JRubyMethod(name = { "get_array_of_string" })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import static org.jruby.api.Create.newArray;
import static org.jruby.api.Convert.asSymbol;
import static org.jruby.api.Create.newRawArray;
import static org.jruby.api.Error.typeError;

@JRubyClass(name = "FFI::VariadicInvoker", parent = "Object")
Expand Down Expand Up @@ -114,15 +115,17 @@ public static VariadicInvoker newInstance(ThreadContext context, IRubyObject kla
CallingConvention callConvention = "stdcall".equals(convention) ?
CallingConvention.STDCALL : CallingConvention.DEFAULT;

var fixed = newArray(context);
int length = paramTypes.getLength();
var fixed = newRawArray(context, length);
int fixedParamCount = 0;
for (int i = 0; i < paramTypes.getLength(); ++i) {
for (int i = 0; i < length; ++i) {
Type type = (Type)paramTypes.entry(i);
if (type.getNativeType() != org.jruby.ext.ffi.NativeType.VARARGS) {
fixed.append(context, type);
fixedParamCount++;
}
}
fixed.finishRawArray(context);

FunctionInvoker functionInvoker = DefaultMethodFactory.getFunctionInvoker(returnType);

Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/ext/socket/RubyTCPSocket.java
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ public static IRubyObject gethostbyname(ThreadContext context, IRubyObject recv,

return RubyArray.newArray(context.runtime,
newString(context, do_not_reverse_lookup(context, recv).isTrue() ? addr.getHostAddress() : addr.getCanonicalHostName()),
newArray(context),
newEmptyArray(context),
asFixnum(context, addr instanceof Inet4Address ? AF_INET.longValue() : AF_INET6.longValue()),
newString(context, addr.getHostAddress()));
}
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/org/jruby/ext/socket/SocketUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public static IRubyObject gethostname(ThreadContext context) {

public static IRubyObject gethostbyaddr(ThreadContext context, IRubyObject[] args) {
var ret0 = newString(context, Sockaddr.addressFromString(context.runtime, args[0].convertToString().toString()).getCanonicalHostName());
var ret1 = newArray(context);
var ret1 = newEmptyArray(context);
var ret2 = asFixnum(context, 2); // AF_INET
var ret3 = args[0];

Expand Down Expand Up @@ -148,7 +148,7 @@ public static IRubyObject gethostbyname(ThreadContext context, IRubyObject hostn

return RubyArray.newArray(context.runtime,
newString(context, addr.getCanonicalHostName()),
newArray(context),
newEmptyArray(context),
asFixnum(context, AF_INET.longValue()),
newString(context, new ByteList(addr.getAddress())));
} catch(UnknownHostException e) {
Expand Down
10 changes: 10 additions & 0 deletions core/src/main/java/org/jruby/internal/runtime/GlobalVariables.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@
import org.jruby.common.IRubyWarnings.ID;
import org.jruby.exceptions.RaiseException;
import org.jruby.runtime.IAccessor;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.func.TriConsumer;

/**
*
Expand Down Expand Up @@ -163,6 +165,10 @@ public Set<String> getNames() {
return globalVariables.keySet();
}

public <State> void eachName(ThreadContext context, State state, TriConsumer<ThreadContext, State, String> consumer) {
globalVariables.forEach((s, g) -> consumer.accept(context, state, s));
}

private GlobalVariable createIfNotDefined(String name) {
return globalVariables.computeIfAbsent(name, (n) -> GlobalVariable.newUndefined(runtime, n));
}
Expand All @@ -176,4 +182,8 @@ public IRubyObject getDefaultSeparator() {
public void setDefaultSeparator(IRubyObject defaultSeparator) {
this.defaultSeparator = defaultSeparator;
}

public int size() {
return globalVariables.size();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.jruby.runtime.builtin.IRubyObject;

import static org.jruby.api.Create.newArray;
import static org.jruby.api.Create.newEmptyArray;
import static org.jruby.api.Error.runtimeError;
import static org.jruby.util.RubyStringBuilder.ids;
import static org.jruby.util.RubyStringBuilder.str;
Expand Down Expand Up @@ -113,7 +114,7 @@ public ExitableReturn interpret(ThreadContext context, Block block, IRubyObject
break;
case RET_OP:
processReturnOp(context, block, instr, operation, currDynScope, temp, self, currScope);
return new ExitableReturn(newArray(context), Block.NULL_BLOCK);
return new ExitableReturn(newEmptyArray(context), Block.NULL_BLOCK);
case BRANCH_OP:
switch (operation) {
case JUMP:
Expand Down
52 changes: 38 additions & 14 deletions core/src/main/java/org/jruby/javasupport/ext/JavaLang.java
Original file line number Diff line number Diff line change
Expand Up @@ -548,41 +548,65 @@ public static IRubyObject declared_annotations_p(final ThreadContext context, fi
@JRubyMethod
public static IRubyObject java_instance_methods(final ThreadContext context, final IRubyObject self) {
final java.lang.Class<?> klass = unwrapJavaObject(self);
final var methods = newArray(context);
for (java.lang.reflect.Method method : klass.getMethods()) {
if (!Modifier.isStatic(method.getModifiers())) methods.add(method);
Method[] publicMethods = klass.getMethods();

// quick count for accurate size
int size = 0;
for (java.lang.reflect.Method method : publicMethods) if (!Modifier.isStatic(method.getModifiers())) size++;
final var methods = newRawArray(context, size);

for (java.lang.reflect.Method method : publicMethods) {
if (!Modifier.isStatic(method.getModifiers())) methods.add(context, method);
}
return methods;
return methods.finishRawArray(context);
}

@JRubyMethod
public static IRubyObject declared_instance_methods(final ThreadContext context, final IRubyObject self) {
final java.lang.Class<?> klass = unwrapJavaObject(self);
final var methods = newArray(context);
for (java.lang.reflect.Method method : klass.getDeclaredMethods()) {
if (!Modifier.isStatic(method.getModifiers())) methods.add(method);
Method[] declaredMethods = klass.getDeclaredMethods();

// quick count for accurate size
int size = 0;
for (java.lang.reflect.Method method : declaredMethods) if (!Modifier.isStatic(method.getModifiers())) size++;
final var methods = newRawArray(context, size);

for (java.lang.reflect.Method method : declaredMethods) {
if (!Modifier.isStatic(method.getModifiers())) methods.add(context, method);
}
return methods;
return methods.finishRawArray(context);
}

@JRubyMethod
public static IRubyObject java_class_methods(final ThreadContext context, final IRubyObject self) {
final java.lang.Class<?> klass = unwrapJavaObject(self);
final var methods = newArray(context);
for ( java.lang.reflect.Method method : klass.getMethods() ) {
Method[] publicMethods = klass.getMethods();

// quick count for accurate size
int size = 0;
for (java.lang.reflect.Method method : publicMethods) if (Modifier.isStatic(method.getModifiers())) size++;
final var methods = newRawArray(context, size);

for ( java.lang.reflect.Method method : publicMethods) {
if (Modifier.isStatic(method.getModifiers())) methods.add(method);
}
return methods;
return methods.finishRawArray(context);
}

@JRubyMethod
public static IRubyObject declared_class_methods(final ThreadContext context, final IRubyObject self) {
final java.lang.Class<?> klass = unwrapJavaObject(self);
final var methods = newArray(context);
for (java.lang.reflect.Method method : klass.getDeclaredMethods()) {
Method[] declaredMethods = klass.getDeclaredMethods();

// quick count for accurate size
int size = 0;
for (java.lang.reflect.Method method : declaredMethods) if (Modifier.isStatic(method.getModifiers())) size++;
final var methods = newRawArray(context, size);

for (java.lang.reflect.Method method : declaredMethods) {
if (Modifier.isStatic(method.getModifiers())) methods.add(method);
}
return methods;
return methods.finishRawArray(context);
}

@JRubyMethod(name = "<=>") // Ruby Comparable
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/java/org/jruby/parser/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
import org.jruby.util.CommonByteLists;

import static org.jruby.api.Create.newArray;
import static org.jruby.api.Create.newEmptyArray;
import static org.jruby.api.Create.newString;
import static org.jruby.parser.ParserType.*;

Expand Down Expand Up @@ -225,7 +226,7 @@ protected RubyArray<?> getLines(boolean isEvalParse, String file, int length) {
if (!(scriptLines instanceof RubyHash)) return null;

var context = runtime.getCurrentContext();
var list = length == -1 ? newArray(context) : newArray(context, length);
var list = length == -1 ? newEmptyArray(context) : newArray(context, length);
((RubyHash) scriptLines).op_aset(context, newString(context, file), list);
return list;
}
Expand Down
Loading

0 comments on commit bfb53c8

Please sign in to comment.