Skip to content

Commit

Permalink
Showing 9 changed files with 146 additions and 2 deletions.
24 changes: 24 additions & 0 deletions core/src/main/java/org/jruby/ir/IRScope.java
Original file line number Diff line number Diff line change
@@ -1195,6 +1195,30 @@ public boolean needsFrame() {
return requireFrame;
}

public boolean needsOnlyBackref() {
boolean backrefSeen = false;
for (IRFlags flag : getFlags()) {
switch (flag) {
case BINDING_HAS_ESCAPED:
case CAN_CAPTURE_CALLERS_BINDING:
case REQUIRES_LASTLINE:
case REQUIRES_VISIBILITY:
case REQUIRES_BLOCK:
case REQUIRES_SELF:
case REQUIRES_METHODNAME:
case REQUIRES_CLASS:
case USES_EVAL:
case USES_ZSUPER:
return false;
case REQUIRES_BACKREF:
backrefSeen = true;
break;
}
}

return backrefSeen;
}

public boolean reuseParentScope() {
return getFlags().contains(IRFlags.REUSE_PARENT_DYNSCOPE);
}
2 changes: 2 additions & 0 deletions core/src/main/java/org/jruby/ir/IRVisitor.java
Original file line number Diff line number Diff line change
@@ -90,6 +90,7 @@ private void error(Object object) {
public void PopBindingInstr(PopBindingInstr popbindinginstr) { error(popbindinginstr); }
public void PopBlockFrameInstr(PopBlockFrameInstr instr) { error(instr); }
public void PopMethodFrameInstr(PopMethodFrameInstr instr) { error(instr); }
public void PopBackrefFrameInstr(PopBackrefFrameInstr instr) { error(instr); }
public void PrepareBlockArgsInstr(PrepareBlockArgsInstr instr) { error(instr); }
public void PrepareFixedBlockArgsInstr(PrepareFixedBlockArgsInstr instr) { error(instr); }
public void PrepareSingleBlockArgInstr(PrepareSingleBlockArgInstr instr) { error(instr); }
@@ -103,6 +104,7 @@ private void error(Object object) {
public void PushBlockFrameInstr(PushBlockFrameInstr instr) { error(instr); }
public void PushMethodBindingInstr(PushMethodBindingInstr instr) { error(instr); }
public void PushMethodFrameInstr(PushMethodFrameInstr instr) { error(instr); }
public void PushBackrefFrameInstr(PushBackrefFrameInstr instr) { error(instr); }
public void RaiseArgumentErrorInstr(RaiseArgumentErrorInstr raiseargumenterrorinstr) { error(raiseargumenterrorinstr); }
public void RaiseRequiredKeywordArgumentErrorInstr(RaiseRequiredKeywordArgumentError instr) { error(instr); }
public void ReifyClosureInstr(ReifyClosureInstr reifyclosureinstr) { error(reifyclosureinstr); }
2 changes: 2 additions & 0 deletions core/src/main/java/org/jruby/ir/Operation.java
Original file line number Diff line number Diff line change
@@ -211,8 +211,10 @@ public enum Operation {
/** Other JRuby internal primitives for optimizations */
MODULE_GUARD(OpFlags.f_is_jump_or_branch), /* a guard acts as a branch */
PUSH_METHOD_FRAME(OpFlags.f_is_book_keeping_op | OpFlags.f_has_side_effect),
PUSH_BACKREF_FRAME(OpFlags.f_is_book_keeping_op | OpFlags.f_has_side_effect),
PUSH_METHOD_BINDING(OpFlags.f_is_book_keeping_op | OpFlags.f_has_side_effect),
POP_METHOD_FRAME(OpFlags.f_is_book_keeping_op | OpFlags.f_has_side_effect),
POP_BACKREF_FRAME(OpFlags.f_is_book_keeping_op | OpFlags.f_has_side_effect),
PUSH_BLOCK_FRAME(OpFlags.f_is_book_keeping_op | OpFlags.f_has_side_effect),
PUSH_BLOCK_BINDING(OpFlags.f_is_book_keeping_op | OpFlags.f_has_side_effect),
POP_BLOCK_FRAME(OpFlags.f_is_book_keeping_op | OpFlags.f_has_side_effect),
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.jruby.ir.instructions;

import org.jruby.ir.IRVisitor;
import org.jruby.ir.Operation;
import org.jruby.ir.persistence.IRReaderDecoder;
import org.jruby.ir.transformations.inlining.CloneInfo;
import org.jruby.ir.transformations.inlining.SimpleCloneInfo;

public class PopBackrefFrameInstr extends NoOperandInstr implements FixedArityInstr {
public PopBackrefFrameInstr() {
super(Operation.POP_BACKREF_FRAME);
}

@Override
public Instr clone(CloneInfo ii) {
return ii instanceof SimpleCloneInfo ? this : NopInstr.NOP; // FIXME: Is this correct
}

public static PopBackrefFrameInstr decode(IRReaderDecoder d) {
return new PopBackrefFrameInstr();
}

@Override
public void visit(IRVisitor visitor) {
visitor.PopBackrefFrameInstr(this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.jruby.ir.instructions;

import org.jruby.ir.IRVisitor;
import org.jruby.ir.Operation;
import org.jruby.ir.persistence.IRReaderDecoder;
import org.jruby.ir.transformations.inlining.CloneInfo;
import org.jruby.ir.transformations.inlining.SimpleCloneInfo;

public class PushBackrefFrameInstr extends NoOperandInstr implements FixedArityInstr {
public PushBackrefFrameInstr() {
super(Operation.PUSH_BACKREF_FRAME);
}

@Override
public Instr clone(CloneInfo ii) {
return ii instanceof SimpleCloneInfo ? this : NopInstr.NOP; // FIXME: Is this correct?
}

public static PushBackrefFrameInstr decode(IRReaderDecoder d) {
return new PushBackrefFrameInstr();
}

@Override
public void visit(IRVisitor visitor) {
visitor.PushBackrefFrameInstr(this);
}
}
Original file line number Diff line number Diff line change
@@ -63,7 +63,13 @@ private void popSavedState(IRScope scope, boolean isGEB, boolean requireBinding,
instrs.add(new PopBlockFrameInstr(savedFrame));
}
} else {
if (requireFrame) instrs.add(new PopMethodFrameInstr());
if (requireFrame) {
if (scope.needsOnlyBackref()) {
instrs.add(new PopBackrefFrameInstr());
} else {
instrs.add(new PopMethodFrameInstr());
}
}
}
}

@@ -125,7 +131,13 @@ public Object execute(IRScope scope, Object... data) {
}
}
} else {
if (requireFrame) entryBB.addInstr(new PushMethodFrameInstr(scope.getName()));
if (requireFrame) {
if (scope.needsOnlyBackref()) {
entryBB.addInstr(new PushBackrefFrameInstr());
} else {
entryBB.addInstr(new PushMethodFrameInstr(scope.getName()));
}
}
if (requireBinding) entryBB.addInstr(new PushMethodBindingInstr());
}

12 changes: 12 additions & 0 deletions core/src/main/java/org/jruby/ir/targets/JVMVisitor.java
Original file line number Diff line number Diff line change
@@ -1617,6 +1617,12 @@ public void PopMethodFrameInstr(PopMethodFrameInstr popframeinstr) {
jvmMethod().invokeVirtual(Type.getType(ThreadContext.class), Method.getMethod("void postMethodFrameOnly()"));
}

@Override
public void PopBackrefFrameInstr(PopBackrefFrameInstr popframeinstr) {
jvmMethod().loadContext();
jvmMethod().invokeVirtual(Type.getType(ThreadContext.class), Method.getMethod("void postBackrefMethod()"));
}

@Override
public void PrepareBlockArgsInstr(PrepareBlockArgsInstr instr) {
jvmMethod().loadContext();
@@ -1721,6 +1727,12 @@ public void PushMethodFrameInstr(PushMethodFrameInstr pushframeinstr) {
jvmAdapter().invokevirtual(p(ThreadContext.class), "setCurrentVisibility", sig(void.class, Visibility.class));
}

@Override
public void PushBackrefFrameInstr(PushBackrefFrameInstr pushframeinstr) {
jvmMethod().loadContext();
jvmMethod().invokeVirtual(Type.getType(ThreadContext.class), Method.getMethod("void preBackrefMethod()"));
}

@Override
public void PutClassVariableInstr(PutClassVariableInstr putclassvariableinstr) {
visit(putclassvariableinstr.getValue());
8 changes: 8 additions & 0 deletions core/src/main/java/org/jruby/runtime/Frame.java
Original file line number Diff line number Diff line change
@@ -177,6 +177,14 @@ public void updateFrameForEval(IRubyObject self) {
this.visibility = Visibility.PRIVATE;
}

public void updateFrameForBackref() {
// nothing
}

public void clearFrameForBackref() {
this.backRef = null;
}

/**
* Clear the frame, as when the call completes. Clearing prevents cached
* frames from holding references after the call is done.
30 changes: 30 additions & 0 deletions core/src/main/java/org/jruby/runtime/ThreadContext.java
Original file line number Diff line number Diff line change
@@ -463,6 +463,28 @@ private void pushCallFrame(RubyModule clazz, String name,
}
}

private void pushBackrefFrame() {
int index = ++this.frameIndex;
Frame[] stack = frameStack;
stack[index].updateFrameForBackref();
if (index + 1 == stack.length) {
expandFrameStack();
}
}

private void popBackrefFrame() {
Frame[] stack = frameStack;
int index = frameIndex--;
Frame frame = stack[index];

// if the frame was captured, we must replace it but not clear
if (frame.isCaptured()) {
stack[index] = new Frame();
} else {
frame.clearFrameForBackref();
}
}

private void pushEvalFrame(IRubyObject self) {
int index = ++this.frameIndex;
Frame[] stack = frameStack;
@@ -908,10 +930,18 @@ public void preMethodFrameOnly(RubyModule clazz, String name, IRubyObject self)
pushCallFrame(clazz, name, self, Block.NULL_BLOCK);
}

public void preBackrefMethod() {
pushBackrefFrame();
}

public void postMethodFrameOnly() {
popFrame();
}

public void postBackrefMethod() {
popBackrefFrame();
}

public void preMethodScopeOnly(StaticScope staticScope) {
pushScope(DynamicScope.newDynamicScope(staticScope));
}

0 comments on commit 33f05bc

Please sign in to comment.