Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 8e5f3e9d8977
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: d807cb25e341
Choose a head ref
  • 2 commits
  • 9 files changed
  • 1 contributor

Commits on Nov 29, 2015

  1. Copy the full SHA
    ff8306a View commit details
  2. Added one more instruction towards IR-instr based block invocation

    * Hooked up with interpreter.
    subbuss committed Nov 29, 2015
    Copy the full SHA
    d807cb2 View commit details
1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/ir/IRVisitor.java
Original file line number Diff line number Diff line change
@@ -125,6 +125,7 @@ private void error(Object object) {
public void ToAryInstr(ToAryInstr toaryinstr) { error(toaryinstr); }
public void UndefMethodInstr(UndefMethodInstr undefmethodinstr) { error(undefmethodinstr); }
public void UnresolvedSuperInstr(UnresolvedSuperInstr unresolvedsuperinstr) { error(unresolvedsuperinstr); }
public void UpdateBlockExecutionStateInstr (UpdateBlockExecutionStateInstr instr) { error(instr); }
public void YieldInstr(YieldInstr yieldinstr) { error(yieldinstr); }
public void ZeroOperandArgNoBlockCallInstr(ZeroOperandArgNoBlockCallInstr zeroOperandArgNoBlockCallInstr) { error(zeroOperandArgNoBlockCallInstr); }
public void ZSuperInstr(ZSuperInstr zsuperinstr) { error(zsuperinstr); }
3 changes: 2 additions & 1 deletion core/src/main/java/org/jruby/ir/Operation.java
Original file line number Diff line number Diff line change
@@ -213,7 +213,8 @@ public enum Operation {
POP_BINDING(OpFlags.f_is_book_keeping_op | OpFlags.f_has_side_effect),
SAVE_BINDING_VIZ(OpFlags.f_is_book_keeping_op | OpFlags.f_has_side_effect),
RESTORE_BINDING_VIZ(OpFlags.f_is_book_keeping_op | OpFlags.f_has_side_effect),
TOGGLE_BACKTRACE(OpFlags.f_is_book_keeping_op | OpFlags.f_has_side_effect);
TOGGLE_BACKTRACE(OpFlags.f_is_book_keeping_op | OpFlags.f_has_side_effect),
UPDATE_BLOCK_STATE(OpFlags.f_is_book_keeping_op | OpFlags.f_has_side_effect);

public final OpClass opClass;
private int flags;
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.jruby.ir.instructions;

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

/* Generic placeholder instruction for miscellaneous stuff that
* needs to be done before a block's coded is executed.
* Eventually, this should hopefully get folded away into other things.
*/
public class UpdateBlockExecutionStateInstr extends OneOperandInstr implements FixedArityInstr {
public UpdateBlockExecutionStateInstr(Operand self) {
super(Operation.UPDATE_BLOCK_STATE, self);
}

public Operand getSelf() {
return getOperand1();
}

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

public static UpdateBlockExecutionStateInstr decode(IRReaderDecoder d) {
return new UpdateBlockExecutionStateInstr(d.decodeVariable());
}

@Override
public void encode(IRWriterEncoder e) {
super.encode(e);
e.encode(getSelf());
}

@Override
public void visit(IRVisitor visitor) {
visitor.UpdateBlockExecutionStateInstr(this);
}
}
10 changes: 10 additions & 0 deletions core/src/main/java/org/jruby/ir/interpreter/InterpreterEngine.java
Original file line number Diff line number Diff line change
@@ -58,6 +58,7 @@
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.parser.StaticScope;
import org.jruby.EvalType;
import org.jruby.runtime.Binding;
import org.jruby.runtime.Block;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.Frame;
@@ -186,6 +187,15 @@ public IRubyObject interpret(ThreadContext context, Block block, IRubyObject sel
context.pushScope(currDynScope);
} else if (operation == Operation.PUSH_BLOCK_BINDING) {
currDynScope = getBlockScope(context, block, interpreterContext);
} else if (operation == Operation.UPDATE_BLOCK_STATE) {
if (self == null || block.getEvalType() == EvalType.BINDING_EVAL) {
// Update self to the binding's self
Binding b = block.getBinding();
self = b.getSelf();
b.getFrame().setSelf(self);
}
// Clear block's eval type
block.setEvalType(EvalType.NONE);
} else {
processBookKeepingOp(context, block, instr, operation, name, args, self, blockArg, implClass, currDynScope, temp, currScope);
}
9 changes: 9 additions & 0 deletions core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@
import org.jruby.internal.runtime.methods.InterpretedIRMethod;
import org.jruby.internal.runtime.methods.MixedModeIRMethod;
import org.jruby.internal.runtime.methods.UndefinedMethod;
import org.jruby.ir.IRFlags;
import org.jruby.ir.IRManager;
import org.jruby.ir.IRMetaClassBody;
import org.jruby.ir.IRScope;
@@ -450,6 +451,14 @@ public static IRubyObject yield(ThreadContext context, Object blk, Object yieldA
return (unwrapArray && (yieldVal instanceof RubyArray)) ? b.yieldArray(context, yieldVal, null) : b.yield(context, yieldVal);
}

private boolean blockHasExplicitCallProtocol(Block block) {
if (block.getBody() instanceof IRBlockBody) {
return ((IRBlockBody)block.getBody()).getScope().getFlags().contains(IRFlags.HAS_EXPLICIT_CALL_PROTOCOL);
} else {
return false;
}
}

public static IRubyObject yieldSpecific(ThreadContext context, Object blk) {
if (blk instanceof RubyProc) blk = ((RubyProc)blk).getBlock();
if (blk instanceof RubyNil) blk = Block.NULL_BLOCK;
5 changes: 5 additions & 0 deletions core/src/main/java/org/jruby/runtime/Block.java
Original file line number Diff line number Diff line change
@@ -108,6 +108,11 @@ public DynamicScope allocScope(DynamicScope parentScope) {
return newScope;
}

public EvalType getEvalType() {
// SSS FIXME: This is smelly
return body instanceof IRBlockBody ? ((IRBlockBody)body).getEvalType() : null;
}

public void setEvalType(EvalType evalType) {
body.setEvalType(evalType);
}
29 changes: 11 additions & 18 deletions core/src/main/java/org/jruby/runtime/CompiledIRBlockBody.java
Original file line number Diff line number Diff line change
@@ -33,36 +33,29 @@ public ArgumentDescriptor[] getArgumentDescriptors() {

protected IRubyObject commonYieldPath(ThreadContext context, Block block, IRubyObject[] args, IRubyObject self, Block blockArg) {
Binding binding = block.getBinding();

// SSS: Important! Use getStaticScope() to use a copy of the static-scope stored in the block-body.
// Do not use 'closure.getStaticScope()' -- that returns the original copy of the static scope.
// This matters because blocks created for Thread bodies modify the static-scope field of the block-body
// that records additional state about the block body.
//
// FIXME: Rather than modify static-scope, it seems we ought to set a field in block-body which is then
// used to tell dynamic-scope that it is a dynamic scope for a thread body. Anyway, to be revisited later!
Visibility oldVis = binding.getFrame().getVisibility();
Frame prevFrame = context.preYieldNoScope(binding);

// SSS FIXME: Why is self null in non-binding-eval contexts?
if (self == null || this.evalType.get() == EvalType.BINDING_EVAL) {
self = useBindingSelf(binding);
}

// SSS FIXME: Maybe, we should allocate a NoVarsScope/DummyScope for for-loop bodies because the static-scope here
// probably points to the parent scope? To be verified and fixed if necessary. There is no harm as it is now. It
// is just wasteful allocation since the scope is not used at all.

// Pass on eval state info to the dynamic scope and clear it on the block-body
DynamicScope prevScope = binding.getDynamicScope();
if (this.pushScope) {
// SSS FIXME: for lambdas, this behavior is different
// compared to what InterpretedIRBlockBody and MixedModeIRBlockBody do
context.pushScope(DynamicScope.newDynamicScope(getStaticScope(), prevScope, this.evalType.get()));
} else if (this.reuseParentScope) {
// Reuse!
// We can avoid the push only if surrounding vars aren't referenced!
// Reuse! We can avoid the push only if surrounding vars aren't referenced!
context.pushScope(prevScope);
}
this.evalType.set(EvalType.NONE);

// SSS FIXME: Why is self null in non-binding-eval contexts?
if (self == null || this.evalType.get() == EvalType.BINDING_EVAL) {
self = useBindingSelf(binding);
}

// Clear evaltype now that it has been set on dyn-scope
block.setEvalType(EvalType.NONE);

if (usesKwargs) IRRuntimeHelpers.frobnicateKwargsArgument(context, getSignature().required(), args);

Original file line number Diff line number Diff line change
@@ -98,7 +98,7 @@ protected IRubyObject commonYieldPath(ThreadContext context, Block block, IRubyO

// SSS FIXME: Why is self null in non-binding-eval contexts?
if (self == null || getEvalType() == EvalType.BINDING_EVAL) {
useBindingSelf(binding);
self = useBindingSelf(binding);
}

// Clear evaltype now that it has been set on dyn-scope
38 changes: 14 additions & 24 deletions core/src/main/java/org/jruby/runtime/MixedModeIRBlockBody.java
Original file line number Diff line number Diff line change
@@ -36,8 +36,8 @@ public MixedModeIRBlockBody(IRClosure closure, Signature signature) {

@Override
public void setEvalType(EvalType evalType) {
this.evalType.set(evalType);
if (jittedBody != null) jittedBody.setEvalType(evalType);
if (jittedBody == null) this.evalType.set(evalType);
else jittedBody.setEvalType(evalType);
}

@Override
@@ -90,47 +90,37 @@ public String getName() {
}

protected IRubyObject commonYieldPath(ThreadContext context, Block block, IRubyObject[] args, IRubyObject self, Block blockArg) {
Binding binding = block.getBinding();
if (callCount >= 0) promoteToFullBuild(context);

CompiledIRBlockBody jittedBody = this.jittedBody;

if (jittedBody != null) {
return jittedBody.commonYieldPath(context, block, args, self, blockArg);
}

// SSS: Important! Use getStaticScope() to use a copy of the static-scope stored in the block-body.
// Do not use 'closure.getStaticScope()' -- that returns the original copy of the static scope.
// This matters because blocks created for Thread bodies modify the static-scope field of the block-body
// that records additional state about the block body.
//
// FIXME: Rather than modify static-scope, it seems we ought to set a field in block-body which is then
// used to tell dynamic-scope that it is a dynamic scope for a thread body. Anyway, to be revisited later!
InterpreterContext ic = ensureInstrsReady();

Binding binding = block.getBinding();
Visibility oldVis = binding.getFrame().getVisibility();
Frame prevFrame = context.preYieldNoScope(binding);

// SSS FIXME: Why is self null in non-binding-eval contexts?
if (self == null || this.evalType.get() == EvalType.BINDING_EVAL) {
self = useBindingSelf(binding);
}

// SSS FIXME: Maybe, we should allocate a NoVarsScope/DummyScope for for-loop bodies because the static-scope here
// probably points to the parent scope? To be verified and fixed if necessary. There is no harm as it is now. It
// is just wasteful allocation since the scope is not used at all.

InterpreterContext ic = ensureInstrsReady();

// Pass on eval state info to the dynamic scope and clear it on the block-body
DynamicScope actualScope = binding.getDynamicScope();
if (ic.pushNewDynScope()) {
actualScope = DynamicScope.newDynamicScope(getStaticScope(), actualScope, this.evalType.get());
if (block.type == Block.Type.LAMBDA) actualScope.setLambda(true);
context.pushScope(actualScope);
context.pushScope(block.allocScope(actualScope));
} else if (ic.reuseParentDynScope()) {
// Reuse! We can avoid the push only if surrounding vars aren't referenced!
context.pushScope(actualScope);
}
this.evalType.set(EvalType.NONE);

// SSS FIXME: Why is self null in non-binding-eval contexts?
if (self == null || this.evalType.get() == EvalType.BINDING_EVAL) {
self = useBindingSelf(binding);
}

// Clear evaltype now that it has been set on dyn-scope
block.setEvalType(EvalType.NONE);

try {
return Interpreter.INTERPRET_BLOCK(context, block, self, ic, args, binding.getMethod(), blockArg);