Skip to content

Commit 10d2ce1

Browse files
committed
Multiple memory-retention improvements in IR.
* Lazily allocate Vertex edge sets only when needed for write. * Use lazily-allocated IntHashMap for IRMethod signatures. * Clear unused IRScope data strucures after successful JIT. Also changed some directed graph classes to use Iterable so we have a free hand to improve the actual data structure used.
1 parent 5ea7533 commit 10d2ce1

File tree

9 files changed

+94
-35
lines changed

9 files changed

+94
-35
lines changed

core/src/main/java/org/jruby/compiler/JITCompiler.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import org.jruby.util.JavaNameMangler;
4949
import org.jruby.util.OneShotClassLoader;
5050
import org.jruby.util.cli.Options;
51+
import org.jruby.util.collections.IntHashMap;
5152
import org.jruby.util.log.Logger;
5253
import org.jruby.util.log.LoggerFactory;
5354
import org.objectweb.asm.Opcodes;
@@ -58,6 +59,7 @@
5859
import java.lang.reflect.Method;
5960
import java.security.MessageDigest;
6061
import java.security.NoSuchAlgorithmException;
62+
import java.util.List;
6163
import java.util.Locale;
6264
import java.util.Map;
6365
import java.util.concurrent.ExecutorService;
@@ -243,7 +245,10 @@ public void run() {
243245
log(method, className + "." + methodName, "done jitting");
244246
}
245247

246-
Map<Integer, MethodType> signatures = ((IRMethod)method.getIRMethod()).getNativeSignatures();
248+
// clear out data structures we won't need anymore
249+
method.getIRMethod().clearAfterJIT();
250+
251+
IntHashMap<MethodType> signatures = ((IRMethod)method.getIRMethod()).getNativeSignatures();
247252
String jittedName = ((IRMethod)method.getIRMethod()).getJittedName();
248253
if (signatures.size() == 1) {
249254
// only variable-arity
@@ -255,7 +260,7 @@ public void run() {
255260
method.getImplementationClass()));
256261
} else {
257262
// also specific-arity
258-
for (Map.Entry<Integer, MethodType> entry : signatures.entrySet()) {
263+
for (IntHashMap.Entry<MethodType> entry : signatures.entrySet()) {
259264
if (entry.getKey() == -1) continue; // variable arity handle pushed above
260265

261266
method.switchToJitted(

core/src/main/java/org/jruby/ir/IRMethod.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.jruby.ir;
22

3+
import org.jcodings.util.IntHash;
34
import org.jruby.internal.runtime.methods.IRMethodArgs;
45
import org.jruby.ir.instructions.Instr;
56
import org.jruby.ir.instructions.ReceiveArgBase;
@@ -13,6 +14,7 @@
1314
import org.jruby.ir.operands.Splat;
1415
import org.jruby.util.KeyValuePair;
1516
import org.jruby.parser.StaticScope;
17+
import org.jruby.util.collections.IntHashMap;
1618

1719
import java.lang.invoke.MethodType;
1820
import java.util.ArrayList;
@@ -35,7 +37,10 @@ public class IRMethod extends IRScope {
3537
private List<String[]> argDesc;
3638

3739
// Signatures to the jitted versions of this method
38-
private Map<Integer, MethodType> signatures;
40+
private IntHashMap<MethodType> signatures = NULL_SIGNATURES;
41+
42+
// Max arity we support; this is only an artificial number to keep the signature store compact.
43+
private static final IntHashMap<MethodType> NULL_SIGNATURES = new IntHashMap<>(0);
3944

4045
// Method name in the jitted version of this method
4146
private String jittedName;
@@ -48,7 +53,6 @@ public IRMethod(IRManager manager, IRScope lexicalParent, String name,
4853
this.callArgs = new ArrayList<>();
4954
this.keywordArgs = new ArrayList<>();
5055
this.argDesc = new ArrayList<>();
51-
this.signatures = new HashMap<>();
5256

5357
if (!getManager().isDryRun() && staticScope != null) {
5458
staticScope.setIRScope(this);
@@ -115,15 +119,16 @@ public LocalVariable getLocalVariable(String name, int scopeDepth) {
115119
}
116120

117121
public void addNativeSignature(int arity, MethodType signature) {
122+
ensureSignatures();
118123
signatures.put(arity, signature);
119124
}
120125

121-
public MethodType getNativeSignature(int arity) {
122-
return signatures.get(arity);
126+
public IntHashMap<MethodType> getNativeSignatures() {
127+
return signatures;
123128
}
124129

125-
public Map<Integer, MethodType> getNativeSignatures() {
126-
return Collections.unmodifiableMap(signatures);
130+
private void ensureSignatures() {
131+
if (signatures == NULL_SIGNATURES) signatures = new IntHashMap<>(5, 0.25f);
127132
}
128133

129134
public String getJittedName() {

core/src/main/java/org/jruby/ir/IRScope.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,4 +1208,22 @@ public void savePersistenceInfo(int offset, IRReaderDecoder file) {
12081208
instructionsOffsetInfoPersistenceBuffer = offset;
12091209
persistenceStore = file;
12101210
}
1211+
1212+
/**
1213+
* Flush out data structures no longer neecessary after a successful JIT.
1214+
*/
1215+
public void clearAfterJIT() {
1216+
// Clear everything out, since we're never coming back this way again.
1217+
dfProbs = null;
1218+
cfg = null;
1219+
linearizedBBList = null;
1220+
// localVars = null;
1221+
definedLocalVars = null;
1222+
evalScopeVars = null;
1223+
executedPasses = null;
1224+
// nextVarIndex = null;
1225+
instrList = null;
1226+
nestedClosures = null;
1227+
lexicalChildren = null;
1228+
}
12111229
}

core/src/main/java/org/jruby/ir/targets/JVMVisitor.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.jruby.util.KeyValuePair;
3030
import org.jruby.util.RegexpOptions;
3131
import org.jruby.util.cli.Options;
32+
import org.jruby.util.collections.IntHashMap;
3233
import org.jruby.util.log.Logger;
3334
import org.jruby.util.log.LoggerFactory;
3435
import org.objectweb.asm.Handle;
@@ -922,7 +923,7 @@ public void DefineClassMethodInstr(DefineClassMethodInstr defineclassmethodinstr
922923

923924
emitMethod(method);
924925

925-
Map<Integer, MethodType> signatures = method.getNativeSignatures();
926+
IntHashMap<MethodType> signatures = method.getNativeSignatures();
926927

927928
MethodType signature = signatures.get(-1);
928929

@@ -951,7 +952,7 @@ public void DefineInstanceMethodInstr(DefineInstanceMethodInstr defineinstanceme
951952
m.loadContext();
952953

953954
emitMethod(method);
954-
Map<Integer, MethodType> signatures = method.getNativeSignatures();
955+
IntHashMap<MethodType> signatures = method.getNativeSignatures();
955956

956957
MethodType variable = signatures.get(-1); // always a variable arity handle
957958

@@ -970,7 +971,7 @@ public void DefineInstanceMethodInstr(DefineInstanceMethodInstr defineinstanceme
970971
a.invokestatic(p(IRRuntimeHelpers.class), "defCompiledInstanceMethod", defSignature);
971972
}
972973

973-
public String pushHandlesForDef(String name, Map<Integer, MethodType> signatures, MethodType variable, String variableOnly, String variableAndSpecific) {
974+
public String pushHandlesForDef(String name, IntHashMap<MethodType> signatures, MethodType variable, String variableOnly, String variableAndSpecific) {
974975
String defSignature;
975976

976977
jvmMethod().pushHandle(new Handle(Opcodes.H_INVOKESTATIC, jvm.clsData().clsName, name, sig(variable.returnType(), variable.parameterArray())));
@@ -981,7 +982,7 @@ public String pushHandlesForDef(String name, Map<Integer, MethodType> signatures
981982
defSignature = variableAndSpecific;
982983

983984
// FIXME: only supports one arity
984-
for (Map.Entry<Integer, MethodType> entry : signatures.entrySet()) {
985+
for (IntHashMap.Entry<MethodType> entry : signatures.entrySet()) {
985986
if (entry.getKey() == -1) continue; // variable arity signature pushed above
986987
jvmMethod().pushHandle(new Handle(Opcodes.H_INVOKESTATIC, jvm.clsData().clsName, name, sig(entry.getValue().returnType(), entry.getValue().parameterArray())));
987988
jvmAdapter().pushInt(entry.getKey());

core/src/main/java/org/jruby/ir/util/DataIterable.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212
* @author enebo
1313
*/
1414
public class DataIterable<T> implements Iterable<T> {
15-
private Set<Edge<T>> edges;
15+
private Iterable<Edge<T>> edges;
1616
private Object type;
1717
private boolean negate;
1818
private boolean source;
1919

20-
public DataIterable(Set<Edge<T>> edges, Object type, boolean source, boolean negate) {
20+
public DataIterable(Iterable<Edge<T>> edges, Object type, boolean source, boolean negate) {
2121
this.edges = edges;
2222
this.type = type;
2323
this.negate = negate;

core/src/main/java/org/jruby/ir/util/DataIterator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public class DataIterator<T> implements Iterator<T> {
1818
private boolean source;
1919
private boolean negate;
2020

21-
public DataIterator(Set<Edge<T>> edges, Object type, boolean source, boolean negate) {
21+
public DataIterator(Iterable<Edge<T>> edges, Object type, boolean source, boolean negate) {
2222
this.internalIterator = edges.iterator();
2323
this.type = type;
2424
this.source = source;

core/src/main/java/org/jruby/ir/util/EdgeTypeIterable.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
package org.jruby.ir.util;
22

33
import java.util.Iterator;
4+
import java.util.List;
45
import java.util.Set;
56

67
/**
78
*/
89
public class EdgeTypeIterable<T> implements Iterable<Edge<T>> {
9-
private Set<Edge<T>> edges;
10+
private Iterable<Edge<T>> edges;
1011
private Object type;
1112
private boolean negate;
1213

13-
public EdgeTypeIterable(Set<Edge<T>> edges, Object type) {
14+
public EdgeTypeIterable(Iterable<Edge<T>> edges, Object type) {
1415
this(edges, type, false);
1516

1617
}
1718

18-
public EdgeTypeIterable(Set<Edge<T>> edges, Object type, boolean negate) {
19+
public EdgeTypeIterable(Iterable<Edge<T>> edges, Object type, boolean negate) {
1920
this.edges = edges;
2021
this.type = type;
2122
this.negate = negate;

core/src/main/java/org/jruby/ir/util/EdgeTypeIterator.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.jruby.ir.util;
22

33
import java.util.Iterator;
4+
import java.util.List;
45
import java.util.NoSuchElementException;
56
import java.util.Set;
67

@@ -13,7 +14,7 @@ public class EdgeTypeIterator<T> implements Iterator<Edge<T>> {
1314
private Edge nextEdge = null;
1415
private boolean negate;
1516

16-
public EdgeTypeIterator(Set<Edge<T>> edges, Object type, boolean negate) {
17+
public EdgeTypeIterator(Iterable<Edge<T>> edges, Object type, boolean negate) {
1718
this.internalIterator = edges.iterator();
1819
this.type = type;
1920
this.negate = negate;

core/src/main/java/org/jruby/ir/util/Vertex.java

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
public class Vertex<T> implements Comparable<Vertex<T>> {
99
private DirectedGraph graph;
1010
private T data;
11-
private Set<Edge<T>> incoming = null;
12-
private Set<Edge<T>> outgoing = null;
11+
private Set<Edge<T>> incoming = Collections.EMPTY_SET;
12+
private Set<Edge<T>> outgoing = Collections.EMPTY_SET;
1313
int id;
1414

1515
public Vertex(DirectedGraph graph, T data, int id) {
@@ -24,8 +24,8 @@ public void addEdgeTo(Vertex destination) {
2424

2525
public void addEdgeTo(Vertex destination, Object type) {
2626
Edge edge = new Edge<T>(this, destination, type);
27-
getOutgoingEdges().add(edge);
28-
destination.getIncomingEdges().add(edge);
27+
addOutgoingEdge(edge);
28+
destination.addIncomingEdge(edge);
2929
graph.edges().add(edge);
3030
}
3131

@@ -42,14 +42,14 @@ public void addEdgeTo(T destination, Object type) {
4242
public boolean removeEdgeTo(Vertex destination) {
4343
for (Edge edge: getOutgoingEdges()) {
4444
if (edge.getDestination() == destination) {
45-
getOutgoingEdges().remove(edge);
46-
edge.getDestination().getIncomingEdges().remove(edge);
45+
removeOutgoingEdge(edge);
46+
edge.getDestination().removeIncomingEdge(edge);
4747
graph.edges().remove(edge);
4848
if(outDegree() == 0) {
49-
outgoing = null;
49+
outgoing = Collections.EMPTY_SET;
5050
}
5151
if(destination.inDegree() == 0) {
52-
destination.incoming = null;
52+
destination.incoming = Collections.EMPTY_SET;
5353
}
5454
return true;
5555
}
@@ -60,18 +60,18 @@ public boolean removeEdgeTo(Vertex destination) {
6060

6161
public void removeAllIncomingEdges() {
6262
for (Edge edge: getIncomingEdges()) {
63-
edge.getSource().getOutgoingEdges().remove(edge);
63+
edge.getSource().removeOutgoingEdge(edge);
6464
graph.edges().remove(edge);
6565
}
66-
incoming = null;
66+
incoming = Collections.EMPTY_SET;
6767
}
6868

6969
public void removeAllOutgoingEdges() {
7070
for (Edge edge: getOutgoingEdges()) {
71-
edge.getDestination().getIncomingEdges().remove(edge);
71+
edge.getDestination().removeIncomingEdge(edge);
7272
graph.edges().remove(edge);
7373
}
74-
outgoing = null;
74+
outgoing = Collections.EMPTY_SET;
7575
}
7676

7777
public void removeAllEdges() {
@@ -80,11 +80,11 @@ public void removeAllEdges() {
8080
}
8181

8282
public int inDegree() {
83-
return (incoming == null) ? 0 : incoming.size();
83+
return incoming.size();
8484
}
8585

8686
public int outDegree() {
87-
return (outgoing == null) ? 0 : outgoing.size();
87+
return outgoing.size();
8888
}
8989

9090
public Iterable<Edge<T>> getIncomingEdgesOfType(Object type) {
@@ -172,13 +172,41 @@ public Edge<T> getOutgoingEdge() {
172172
}
173173

174174
public Set<Edge<T>> getIncomingEdges() {
175-
if (incoming == null) incoming = new HashSet<Edge<T>>();
175+
return incoming;
176+
}
177+
178+
public void addIncomingEdge(Edge<T> edge) {
179+
getIncomingEdgesForWrite().add(edge);
180+
}
181+
182+
public void removeIncomingEdge(Edge<T> edge) {
183+
if (incoming.size() == 0) return;
184+
incoming.remove(edge);
185+
if (incoming.size() == 0) incoming = Collections.EMPTY_SET;
186+
}
187+
188+
private Set<Edge<T>> getIncomingEdgesForWrite() {
189+
if (incoming == Collections.EMPTY_SET) incoming = new HashSet<Edge<T>>();
176190

177191
return incoming;
178192
}
179193

194+
public void addOutgoingEdge(Edge<T> edge) {
195+
getOutgoingEdgesForWrite().add(edge);
196+
}
197+
198+
public void removeOutgoingEdge(Edge<T> edge) {
199+
if (outgoing.size() == 0) return;
200+
outgoing.remove(edge);
201+
if (outgoing.size() == 0) outgoing = Collections.EMPTY_SET;
202+
}
203+
180204
public Set<Edge<T>> getOutgoingEdges() {
181-
if (outgoing == null) outgoing = new HashSet<Edge<T>>();
205+
return outgoing;
206+
}
207+
208+
private Set<Edge<T>> getOutgoingEdgesForWrite() {
209+
if (outgoing == Collections.EMPTY_SET) outgoing = new HashSet<Edge<T>>();
182210

183211
return outgoing;
184212
}

0 commit comments

Comments
 (0)