Skip to content

Commit

Permalink
Merge branch 'master' into pattern_jit
Browse files Browse the repository at this point in the history
  • Loading branch information
headius committed Nov 29, 2023
2 parents 8304f83 + 1710cd2 commit 4907cad
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 25 deletions.
54 changes: 36 additions & 18 deletions core/src/main/java/org/jruby/RubyObjectSpace.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

import java.util.Iterator;
import java.util.Map;
import java.util.stream.Stream;

import org.jruby.anno.JRubyMethod;
import org.jruby.anno.JRubyModule;
Expand All @@ -51,6 +52,7 @@
import org.jruby.util.Inspector;
import org.jruby.util.Numeric;
import org.jruby.util.collections.WeakValuedIdentityMap;
import org.jruby.util.collections.WeakValuedMap;

@JRubyModule(name="ObjectSpace")
public class RubyObjectSpace {
Expand Down Expand Up @@ -231,59 +233,74 @@ public WeakMap(Ruby runtime, RubyClass cls) {

@JRubyMethod(name = "[]")
public IRubyObject op_aref(ThreadContext context, IRubyObject key) {
IRubyObject value = map.get(key);
Map<IRubyObject, IRubyObject> weakMap = getWeakMapFor(key);
IRubyObject value = weakMap.get(key);
if (value != null) return value;
return context.nil;
}

private Map<IRubyObject, IRubyObject> getWeakMapFor(IRubyObject key) {
if (key instanceof RubyFixnum || key instanceof RubyFloat) {
return valueMap;
}

return identityMap;
}

@JRubyMethod(name = "[]=")
public IRubyObject op_aref(ThreadContext context, IRubyObject key, IRubyObject value) {
Ruby runtime = context.runtime;

map.put(key, value);
Map<IRubyObject, IRubyObject> weakMap = getWeakMapFor(key);
weakMap.put(key, value);

return runtime.newFixnum(System.identityHashCode(value));
}

@JRubyMethod(name = "key?")
public IRubyObject key_p(ThreadContext context, IRubyObject key) {
return RubyBoolean.newBoolean(context, map.get(key) != null);
Map<IRubyObject, IRubyObject> weakMap = getWeakMapFor(key);
return RubyBoolean.newBoolean(context, weakMap.get(key) != null);
}

@JRubyMethod(name = "keys")
public IRubyObject keys(ThreadContext context) {
return context.runtime.newArrayNoCopy(
map.entrySet()
.stream()
getEntryStream()
.filter(entry -> entry.getValue() != null)
.map(entry -> entry.getKey())
.map(Map.Entry::getKey)
.toArray(IRubyObject[]::new));
}

private Stream<Map.Entry<IRubyObject, IRubyObject>> getEntryStream() {
return Stream.concat(identityMap.entrySet().stream(), valueMap.entrySet().stream());
}

@JRubyMethod(name = "values")
public IRubyObject values(ThreadContext context) {
return context.runtime.newArrayNoCopy(
map.values()
.stream()
getEntryStream()
.map(Map.Entry::getValue)
.filter(ref -> ref != null)
.toArray(IRubyObject[]::new));
}

@JRubyMethod(name = {"length", "size"})
public IRubyObject size(ThreadContext context) {
return context.runtime.newFixnum(map.size());
return context.runtime.newFixnum(identityMap.size() + valueMap.size());
}

@JRubyMethod(name = {"include?", "member?"})
public IRubyObject member_p(ThreadContext context, IRubyObject key) {
return RubyBoolean.newBoolean(context, map.containsKey(key));
return RubyBoolean.newBoolean(context, getWeakMapFor(key).containsKey(key));
}

@JRubyMethod(name = {"each", "each_pair"})
public IRubyObject each(ThreadContext context, Block block) {
map.forEach((key, value) -> {
getEntryStream().forEach((entry) -> {
IRubyObject value = entry.getValue();
if (value != null) {
block.yieldSpecific(context, key, value);
block.yieldSpecific(context, entry.getKey(), value);
}
});

Expand All @@ -292,23 +309,23 @@ public IRubyObject each(ThreadContext context, Block block) {

@JRubyMethod(name = "each_key")
public IRubyObject each_key(ThreadContext context, Block block) {
for (Map.Entry<IRubyObject, IRubyObject> entry : map.entrySet()) {
getEntryStream().forEach((entry) -> {
if (entry.getValue() != null) {
block.yieldSpecific(context, entry.getKey());
}
}
});

return this;
}

@JRubyMethod(name = "each_value")
public IRubyObject each_value(ThreadContext context, Block block) {
for (Map.Entry<IRubyObject, IRubyObject> entry : map.entrySet()) {
getEntryStream().forEach((entry) -> {
IRubyObject value = entry.getValue();
if (value != null) {
block.yieldSpecific(context, value);
}
}
});

return this;
}
Expand All @@ -320,7 +337,7 @@ public IRubyObject inspect(ThreadContext context) {
RubyString part = inspectPrefix(runtime.getCurrentContext(), metaClass.getRealClass(), inspectHashCode());
int base = part.length();

map.entrySet().forEach(entry -> {
getEntryStream().forEach(entry -> {
if (entry.getValue() != null) {
if (part.length() == base) {
part.cat(Inspector.COLON_SPACE);
Expand All @@ -339,6 +356,7 @@ public IRubyObject inspect(ThreadContext context) {
return part;
}

private final WeakValuedIdentityMap<IRubyObject, IRubyObject> map = new WeakValuedIdentityMap<IRubyObject, IRubyObject>();
private final WeakValuedIdentityMap<IRubyObject, IRubyObject> identityMap = new WeakValuedIdentityMap<>();
private final WeakValuedMap<IRubyObject, IRubyObject> valueMap = new WeakValuedMap<>();
}
}
23 changes: 16 additions & 7 deletions core/src/main/java/org/jruby/ir/IRBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -443,8 +443,14 @@ private void emitEnsureBlocks(IRLoop loop) {

private void determineIfWeNeedLineNumber(Node node) {
int currLineNum = node.getLine();
if (currLineNum != lastProcessedLineNum && !(node instanceof NilImplicitNode)) { // Do not emit multiple line number instrs for the same line
needsLineNumInfo = node.isNewline() ? LineInfo.Coverage : LineInfo.Backtrace;
if (currLineNum != lastProcessedLineNum && !(node instanceof NilImplicitNode)) {
LineInfo needsCoverage = node.isNewline() ? LineInfo.Coverage : null;
// DefNode will set it's own line number as part of impl but if it is for coverage we emit as instr also.
if (needsCoverage != null && (!(node instanceof DefNode) || coverageMode != 0)) { // Do not emit multiple line number instrs for the same line
needsLineNumInfo = node.isNewline() ? needsCoverage : LineInfo.Backtrace;
}

// This line is already process either by linenum or by instr which emits its own.
lastProcessedLineNum = currLineNum;
}
}
Expand Down Expand Up @@ -1454,8 +1460,10 @@ private void buildArrayPattern(Label testEnd, Variable result, Variable deconstr
label("min_args_check_end", minArgsCheck -> {
BIntInstr.Op compareOp = pattern.hasRestArg() ? BIntInstr.Op.GTE : BIntInstr.Op.EQ;
addInstr(new BIntInstr(minArgsCheck, compareOp, length, new Integer(pattern.minimumArgsNum())));
fcall(errorString, buildSelf(), "sprintf",
new FrozenString("%s: %s length mismatch (given %d, expected %d)"), deconstructed, deconstructed, as_fixnum(length), new Fixnum(pattern.minimumArgsNum()));
if (isSinglePattern) {
fcall(errorString, buildSelf(), "sprintf",
new FrozenString("%s: %s length mismatch (given %d, expected %d)"), deconstructed, deconstructed, as_fixnum(length), new Fixnum(pattern.minimumArgsNum()));
}
addInstr(new CopyInstr(result, fals()));
jump(testEnd);
});
Expand Down Expand Up @@ -1785,14 +1793,15 @@ public Operand buildPatternCase(PatternCaseNode patternCase) {

// build each "when"
Variable deconstructed = copy(buildNil());
for (Node aCase : patternCase.getCases().children()) {
Node[] cases = patternCase.getCases().children();
boolean isSinglePattern = cases.length == 1;
for (Node aCase : cases) {
InNode inNode = (InNode) aCase;
Label bodyLabel = getNewLabel();

boolean isSinglePattern = inNode.isSinglePattern();

Variable eqqResult = copy(tru());
labels.add(bodyLabel);

buildPatternMatch(eqqResult, deconstructed, inNode.getExpression(), value, false, isSinglePattern, errorString);
addInstr(createBranch(eqqResult, tru(), bodyLabel));
bodies.put(bodyLabel, inNode.getBody());
Expand Down
6 changes: 6 additions & 0 deletions core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java
Original file line number Diff line number Diff line change
Expand Up @@ -1745,6 +1745,7 @@ public static RubyModule newRubyClassFromIR(Ruby runtime, String id, StaticScope

@Interp
public static void defInterpretedClassMethod(ThreadContext context, IRScope method, IRubyObject obj) {
context.setLine(method.getLine());
String id = method.getId();
RubyClass rubyClass = checkClassForDef(context, id, obj);

Expand All @@ -1766,6 +1767,7 @@ public static void defCompiledClassMethod(ThreadContext context, MethodHandle ha
StaticScope scope, String encodedArgumentDescriptors,
IRubyObject obj, boolean maybeRefined, boolean receivesKeywordArgs,
boolean needsToFindImplementer) {
context.setLine(line);
RubyClass rubyClass = checkClassForDef(context, id, obj);

if (maybeRefined) scope.captureParentRefinements(context);
Expand All @@ -1787,6 +1789,7 @@ public static void defCompiledClassMethod(ThreadContext context, MethodHandle va
String encodedArgumentDescriptors,
IRubyObject obj, boolean maybeRefined, boolean receivesKeywordArgs,
boolean needsToFindImplementer) {
context.setLine(line);
RubyClass rubyClass = checkClassForDef(context, id, obj);

if (maybeRefined) scope.captureParentRefinements(context);
Expand All @@ -1810,6 +1813,7 @@ private static RubyClass checkClassForDef(ThreadContext context, String id, IRub

@Interp
public static void defInterpretedInstanceMethod(ThreadContext context, IRScope method, DynamicScope currDynScope, IRubyObject self) {
context.setLine(method.getLine());
Ruby runtime = context.runtime;
RubySymbol methodName = method.getName();
RubyModule rubyClass = findInstanceMethodContainer(context, currDynScope, self);
Expand All @@ -1834,6 +1838,7 @@ public static void defCompiledInstanceMethod(ThreadContext context, MethodHandle
StaticScope scope, String encodedArgumentDescriptors,
DynamicScope currDynScope, IRubyObject self, boolean maybeRefined,
boolean receivesKeywordArgs, boolean needsToFindImplementer) {
context.setLine(line);
Ruby runtime = context.runtime;
RubySymbol methodName = runtime.newSymbol(id);
RubyModule clazz = findInstanceMethodContainer(context, currDynScope, self);
Expand All @@ -1856,6 +1861,7 @@ public static void defCompiledInstanceMethod(ThreadContext context, MethodHandle
String encodedArgumentDescriptors,
DynamicScope currDynScope, IRubyObject self, boolean maybeRefined,
boolean receivesKeywordArgs, boolean needsToFindImplementer) {
context.setLine(line);
Ruby runtime = context.runtime;
RubySymbol methodName = runtime.newSymbol(id);
RubyModule clazz = findInstanceMethodContainer(context, currDynScope, self);
Expand Down
2 changes: 2 additions & 0 deletions core/src/main/java/org/jruby/ir/targets/JVMVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -1432,6 +1432,7 @@ public void DefineClassInstr(DefineClassInstr defineclassinstr) {
public void DefineClassMethodInstr(DefineClassMethodInstr defineclassmethodinstr) {
IRMethod method = defineclassmethodinstr.getMethod();

jvmMethod().updateLineNumber(method.getLine());
jvmMethod().loadContext();

JVMVisitorMethodContext context = new JVMVisitorMethodContext();
Expand Down Expand Up @@ -1467,6 +1468,7 @@ public void DefineInstanceMethodInstr(DefineInstanceMethodInstr defineinstanceme
IRBytecodeAdapter m = jvmMethod();
SkinnyMethodAdapter a = m.adapter;

jvmMethod().updateLineNumber(method.getLine());
m.loadContext();

emitMethod(method, context);
Expand Down

0 comments on commit 4907cad

Please sign in to comment.