Skip to content

Commit

Permalink
Showing 102 changed files with 810 additions and 1,090 deletions.
6 changes: 2 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -79,11 +79,9 @@ dependency-reduced-pom.xml
install/updates.xml

# generated ITs
maven/jruby/src/it/osgi_*equinox*
maven/jruby/src/it/osgi_*felix-3*
maven/jruby/src/it/osgi_*knoplerfish
maven/jruby/src/it/osgi_*
maven/jruby/src/it/j2ee_wlp
maven/jruby-complete/src/it/osgi_many_bundles_with_embedded_gems_*
maven/jruby-complete/src/it/osgi*

# IntelliJ project files
.idea
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -42,6 +42,10 @@ matrix:
jdk: oraclejdk7
- env: TARGET='-Pcomplete'
jdk: oraclejdk8
- env: TARGET='-Posgi'
jdk: openjdk7
- env: TARGET='-Pj2ee'
jdk: oraclejdk7
fast_finish: true
allow_failures:
- env: TARGET='-Prake -Dtask=spec:compiler'
2 changes: 1 addition & 1 deletion core/pom.rb
Original file line number Diff line number Diff line change
@@ -259,7 +259,7 @@
end


[ :dist, :'jruby-jars', :main, :all, :complete, :release, :snapshots ].each do |name|
[ :osgi, :dist, :'jruby-jars', :main, :all, :complete, :release, :snapshots ].each do |name|
profile name do
plugin :shade do
execute_goals( 'shade',
57 changes: 57 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
@@ -555,6 +555,63 @@
</plugins>
</build>
<profiles>
<profile>
<id>osgi</id>
<build>
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<id>pack jruby-core-noasm.jar</id>
<phase>verify</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>noasm</shadedClassifierName>
<artifactSet>
<includes>
<include>com.github.jnr:jnr-ffi</include>
<include>org.ow2.asm:*</include>
</includes>
</artifactSet>
<relocations>
<relocation>
<pattern>org.objectweb</pattern>
<shadedPattern>org.jruby.org.objectweb</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
<execution>
<id>pack jruby-core-complete.jar</id>
<phase>verify</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>complete</shadedClassifierName>
<relocations>
<relocation>
<pattern>org.objectweb</pattern>
<shadedPattern>org.jruby.org.objectweb</shadedPattern>
</relocation>
</relocations>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.jruby.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>dist</id>
<build>
6 changes: 3 additions & 3 deletions core/src/main/java/org/jruby/ir/IRFlags.java
Original file line number Diff line number Diff line change
@@ -41,19 +41,19 @@ public enum IRFlags {
CAN_RECEIVE_NONLOCAL_RETURNS, // may receive a non-local return during execution
HAS_BREAK_INSTRS, // contains at least one break
HAS_END_BLOCKS, // has an end block. big de-opt flag
HAS_EXPLICIT_CALL_PROTOCOL, // contains call protocol instrs. if so we don't need to manage bindings frame implicitly.
HAS_EXPLICIT_CALL_PROTOCOL, // contains call protocol instrs => we don't need to manage bindings frame implicitly
HAS_LOOPS, // has a loop
HAS_NONLOCAL_RETURNS, // has a non-local return
HAS_UNUSED_IMPLICIT_BLOCK_ARG,// Is %block implicit block arg unused?
RECEIVES_CLOSURE_ARG, // This scope (or parent receives a closure
RECEIVES_KEYWORD_ARGS, // receives keyword args
REQUIRES_DYNSCOPE, // does this scope require a dynamic scope?
USES_BACKREF_OR_LASTLINE, // Since backref ($~) and lastline ($_) vars are allocated space on the dynamic scope.
USES_BACKREF_OR_LASTLINE, // Since backref ($~) and lastline ($_) vars are allocated space on the dynamic scope
USES_EVAL, // calls eval
USES_ZSUPER, // has zsuper instr
REQUIRES_FRAME, // callee may read/write caller's frame elements
REQUIRES_VISIBILITY, // callee may read/write caller's visibility

DYNSCOPE_ELIMINATED, // local var load/stores have been converted to tmp var accesses
REUSE_PARENT_DYNSCOPE, // for clsoures -- reuse parent's dynscope
REUSE_PARENT_DYNSCOPE, // for closures -- reuse parent's dynscope
}
6 changes: 3 additions & 3 deletions core/src/main/java/org/jruby/ir/IRManager.java
Original file line number Diff line number Diff line change
@@ -17,9 +17,9 @@
/**
*/
public class IRManager {
public static String SAFE_COMPILER_PASSES = "LinearizeCFG";
public static String DEFAULT_COMPILER_PASSES = "OptimizeTempVarsPass,LocalOptimizationPass,LinearizeCFG";
public static String DEFAULT_JIT_PASSES = "AddLocalVarLoadStoreInstructions,AddCallProtocolInstructions,EnsureTempsAssigned,LinearizeCFG";
public static String SAFE_COMPILER_PASSES = "";
public static String DEFAULT_COMPILER_PASSES = "OptimizeTempVarsPass,LocalOptimizationPass";
public static String DEFAULT_JIT_PASSES = "AddLocalVarLoadStoreInstructions,AddCallProtocolInstructions,EnsureTempsAssigned";
public static String DEFAULT_INLINING_COMPILER_PASSES = "LocalOptimizationPass";

private int dummyMetaClassCount = 0;
104 changes: 49 additions & 55 deletions core/src/main/java/org/jruby/ir/IRScope.java
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@
import org.jruby.ir.passes.CompilerPass;
import org.jruby.ir.passes.CompilerPassScheduler;
import org.jruby.ir.passes.DeadCodeElimination;
import org.jruby.ir.passes.OptimizeDynScopesPass;
import org.jruby.ir.dataflow.analyses.StoreLocalVarPlacementProblem;
import org.jruby.ir.dataflow.analyses.LiveVariablesProblem;
import org.jruby.ir.passes.UnboxingPass;
@@ -105,6 +106,9 @@ public abstract class IRScope implements ParseResult {
/** Map of name -> dataflow problem */
private Map<String, DataFlowProblem> dfProbs;

/** What passes have been run on this scope? */
private List<CompilerPass> executedPasses;

private Instr[] linearizedInstrArray;
private List<BasicBlock> linearizedBBList;
private Map<Integer, Integer> rescueMap;
@@ -163,6 +167,8 @@ protected IRScope(IRScope s, IRScope lexicalParent) {
this.scopeId = globalScopeCount.getAndIncrement();
this.relinearizeCFG = false;

this.executedPasses = new ArrayList<CompilerPass>();

setupLexicalContainment();
}

@@ -208,6 +214,8 @@ public IRScope(IRManager manager, IRScope lexicalParent, String name,
this.scopeId = globalScopeCount.getAndIncrement();
this.relinearizeCFG = false;

this.executedPasses = new ArrayList<CompilerPass>();

setupLexicalContainment();
}

@@ -538,6 +546,10 @@ private boolean isUnsafeScope() {
return unsafeScope;
}

public List<CompilerPass> getExecutedPasses() {
return executedPasses;
}

private void runCompilerPasses(List<CompilerPass> passes) {
// SSS FIXME: Why is this again? Document this weirdness!
// Forcibly clear out the shared eval-scope variable allocator each time this method executes
@@ -561,40 +573,28 @@ private void runCompilerPasses(List<CompilerPass> passes) {

CompilerPassScheduler scheduler = getManager().schedulePasses(passes);
for (CompilerPass pass: scheduler) {
if (pass.previouslyRun(this) == null) {
pass.run(this);
}
pass.run(this);
}

if (RubyInstanceConfig.IR_UNBOXING) {
(new UnboxingPass()).run(this);
}
}

private void runDeadCodeAndVarLoadStorePasses() {
// For scopes that don't require a dynamic scope,
// inline-add lvar loads/store to tmp-var loads/stores.
private void optimizeSimpleScopes() {
// For safe scopes that don't require a dynamic scope,
// run DCE since the analysis is less likely to be
// stymied by escaped bindings.
if (!isUnsafeScope() && !flags.contains(REQUIRES_DYNSCOPE)) {
CompilerPass pass;
pass = new DeadCodeElimination();
if (pass.previouslyRun(this) == null) {
pass.run(this);
}

// This will run the simplified version of the pass
// that doesn't require dataflow analysis and hence
// can run on closures independent of enclosing scopes.
pass = new AddLocalVarLoadStoreInstructions();
if (pass.previouslyRun(this) == null) {
((AddLocalVarLoadStoreInstructions)pass).eliminateLocalVars(this);
setDataFlowSolution(StoreLocalVarPlacementProblem.NAME, new StoreLocalVarPlacementProblem());
setDataFlowSolution(LiveVariablesProblem.NAME, null);
}
(new DeadCodeElimination()).run(this);
(new OptimizeDynScopesPass()).run(this);
}
}

/** Run any necessary passes to get the IR ready for interpretation */
public synchronized Instr[] prepareForInterpretation(boolean isLambda) {
public void initScope(boolean isLambda) {
// Reset linearization, if any exists
resetLinearizationData();

// Build CFG and run compiler passes, if necessary
if (getCFG() == null) {
buildCFG();
@@ -615,41 +615,35 @@ public synchronized Instr[] prepareForInterpretation(boolean isLambda) {
// Run DCE and var load/store passes where applicable
// But, if we have been passed in a list of passes to run
// on the commandline, skip this opt.
runDeadCodeAndVarLoadStorePasses();
optimizeSimpleScopes();
}
}

/** Run any necessary passes to get the IR ready for interpretation */
public synchronized Instr[] prepareForInterpretation(boolean isLambda) {
initScope(isLambda);

checkRelinearization();

if (linearizedInstrArray != null) return linearizedInstrArray;

// System.out.println("-- passes run for: " + this + " = " + java.util.Arrays.toString(executedPasses.toArray()));

// Linearize CFG, etc.
return prepareInstructions();
}

/* SSS FIXME: Do we need to synchronize on this? Cache this info in a scope field? */
/** Run any necessary passes to get the IR ready for compilation */
public synchronized List<BasicBlock> prepareForCompilation() {
// Reset linearization, since we will add JIT-specific flow and instrs
resetLinearizationData();

// Build CFG and run compiler passes, if necessary
if (getCFG() == null) {
buildCFG();
}

// Add this always since we dont re-JIT a previously
// JIT-ted closure. But, check if there are other
// smarts available to us and eliminate adding this
// code to every closure there is.
// For lambdas, we need to add a global ensure block to catch
// uncaught breaks and throw a LocalJumpError.
//
// Add a global ensure block to catch uncaught breaks
// and throw a LocalJumpError.
if (this instanceof IRClosure) {
if (((IRClosure)this).addGEBForUncaughtBreaks()) {
resetState();
computeScopeFlags();
}
}
// Since we dont re-JIT a previously JIT-ted closure,
// mark all closures lambdas always. But, check if there are
// other smarts available to us and eliminate adding
// this code to every closure there is.
initScope(this instanceof IRClosure);

runCompilerPasses(getManager().getJITPasses(this));

@@ -1104,11 +1098,6 @@ public CFG cfg() {
return cfg;
}

public void resetDFProblemsState() {
dfProbs = new HashMap<String, DataFlowProblem>();
for (IRClosure c: nestedClosures) c.resetDFProblemsState();
}

public void resetState() {
relinearizeCFG = true;
linearizedInstrArray = null;
@@ -1127,8 +1116,17 @@ public void resetState() {
flags.remove(CAN_RECEIVE_NONLOCAL_RETURNS);
rescueMap = null;

// Reset dataflow problems state
resetDFProblemsState();
// Invalidate compiler pass state.
//
// SSS FIXME: This is to get around concurrent-modification issues
// since CompilerPass.invalidate modifies this, but some passes
// cannot be invalidated.
int i = 0;
while (i < executedPasses.size()) {
if (!executedPasses.get(i).invalidate(this)) {
i++;
}
}
}

public void inlineMethod(IRScope method, RubyModule implClass, int classToken, BasicBlock basicBlock, CallBase call, boolean cloneHost) {
@@ -1145,10 +1143,6 @@ public void inlineMethod(IRScope method, RubyModule implClass, int classToken, B
}
}

public void resetCFG() {
cfg = null;
}

/* Record a begin block -- not all scope implementations can handle them */
public void recordBeginBlock(IRClosure beginBlockClosure) {
throw new RuntimeException("BEGIN blocks cannot be added to: " + this.getClass().getName());
17 changes: 17 additions & 0 deletions core/src/main/java/org/jruby/ir/instructions/CallBase.java
Original file line number Diff line number Diff line change
@@ -164,6 +164,23 @@ public boolean computeScopeFlags(IRScope scope) {
}
}

// Kernel.local_variables inspects variables.
// and JRuby implementation uses dyn-scope to access the static-scope
// to output the local variables => we cannot strip dynscope in those cases.
// FIXME: We need to decouple static-scope and dyn-scope.
String mname = getMethodAddr().getName();
if (mname.equals("local_variables")) {
scope.getFlags().add(REQUIRES_DYNSCOPE);
} else if (mname.equals("send") || mname.equals("__send__")) {
Operand[] args = getCallArgs();
if (args.length >= 1) {
Operand meth = args[0];
if (meth instanceof StringLiteral && "local_variables".equals(((StringLiteral)meth).string)) {
scope.getFlags().add(REQUIRES_DYNSCOPE);
}
}
}

return modifiedScope;
}
/**
Original file line number Diff line number Diff line change
@@ -15,8 +15,6 @@
import java.util.ListIterator;

public class AddCallProtocolInstructions extends CompilerPass {
boolean addedInstrs = false;

@Override
public String getLabel() {
return "Add Call Protocol Instructions (push/pop of dyn-scope, frame, impl-class values)";
@@ -157,22 +155,16 @@ public Object execute(IRScope scope, Object... data) {
// Run on all nested closures.
for (IRClosure c: scope.getClosures()) execute(c);

// Mark as done
addedInstrs = true;

// LVA information is no longer valid after the pass
scope.setDataFlowSolution(LiveVariablesProblem.NAME, null);
// FIXME: Grrr ... this seems broken to have to create a new object to invalidate
(new LiveVariableAnalysis()).invalidate(scope);

return null;
}

@Override
public Object previouslyRun(IRScope scope) {
return addedInstrs ? new Object() : null;
}

@Override
public void invalidate(IRScope scope) {
public boolean invalidate(IRScope scope) {
// Cannot add call protocol instructions after we've added them once.
return false;
}
}
Loading

0 comments on commit 9ac8dfa

Please sign in to comment.