Skip to content

Commit

Permalink
Showing 14 changed files with 184 additions and 67 deletions.
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);
2 changes: 1 addition & 1 deletion lib/ruby/truffle/truffle/bigdecimal.rb
Original file line number Diff line number Diff line change
@@ -94,7 +94,7 @@ def ==(o)
alias_method :===, :==

def coerce(other)
[BigDecimal(other), self]
[BigDecimal(other, 20), self]
end

# TODO (pitr 28-may-2015): compare with pure Java versions
4 changes: 4 additions & 0 deletions spec/ruby/library/bigdecimal/new_spec.rb
Original file line number Diff line number Diff line change
@@ -93,4 +93,8 @@
BigDecimal.new("-12345.6E-1").should == -reference
end

it 'raises ArgumentError when Float is used without precision' do
lambda { BigDecimal(1.0) }.should raise_error(ArgumentError)
end

end
6 changes: 6 additions & 0 deletions test/truffle/pe/language/ivar_pe.rb
Original file line number Diff line number Diff line change
@@ -23,6 +23,10 @@ def reset_b(b)
@b = b
self
end

def ivar_get_a
instance_variable_get :@a
end
end
end

@@ -31,3 +35,5 @@ def reset_b(b)

example "IVarFixtures::Foo.new(1,2).reset_b(42).b", 42
example "IVarFixtures::Foo.new(1,2).reset_b([]).b.empty?", true

example "IVarFixtures::Foo.new(1,2).ivar_get_a", 1
Original file line number Diff line number Diff line change
@@ -58,6 +58,8 @@
import org.jruby.truffle.nodes.methods.LookupMethodNode;
import org.jruby.truffle.nodes.methods.LookupMethodNodeGen;
import org.jruby.truffle.nodes.objects.*;
import org.jruby.truffle.nodes.objectstorage.ReadHeadObjectFieldNode;
import org.jruby.truffle.nodes.objectstorage.ReadHeadObjectFieldNodeGen;
import org.jruby.truffle.nodes.objectstorage.WriteHeadObjectFieldNode;
import org.jruby.truffle.nodes.objectstorage.WriteHeadObjectFieldNodeGen;
import org.jruby.truffle.nodes.rubinius.ObjectPrimitiveNodes;
@@ -972,16 +974,48 @@ public InstanceVariableGetNode(RubyContext context, SourceSection sourceSection)
super(context, sourceSection);
}

protected static final int LIMIT = Options.FIELD_LOOKUP_CACHE;

@CreateCast("name")
public RubyNode coerceToString(RubyNode name) {
return NameToJavaStringNodeGen.create(getContext(), getSourceSection(), name);
public RubyNode coerceToSymbolOrString(RubyNode name) {
return NameToSymbolOrStringNodeGen.create(getContext(), getSourceSection(), name);
}

@Specialization(
guards = { "isRubySymbol(name)", "name == cachedName" },
limit = "LIMIT")
public Object instanceVariableGetSymbolCached(DynamicObject object, DynamicObject name,
@Cached("name") DynamicObject cachedName,
@Cached("createReadFieldNode(checkName(symbolToString(cachedName)))") ReadHeadObjectFieldNode readHeadObjectFieldNode) {
return readHeadObjectFieldNode.execute(object);
}

@Specialization(guards = "isRubySymbol(name)")
public Object instanceVariableGetSymbol(DynamicObject object, DynamicObject name) {
return ivarGet(object, symbolToString(name));
}

@TruffleBoundary
@Specialization
public Object instanceVariableGet(DynamicObject object, String name) {
final String ivar = RubyContext.checkInstanceVariableName(getContext(), name, this);
return object.get(ivar, nil());
@Specialization(guards = "isRubyString(name)")
public Object instanceVariableGetString(DynamicObject object, DynamicObject name) {
return ivarGet(object, name.toString());
}

@TruffleBoundary
private Object ivarGet(DynamicObject object, String name) {
return object.get(checkName(name), nil());
}

protected String symbolToString(DynamicObject name) {
return Layouts.SYMBOL.getString(name);
}

protected String checkName(String name) {
return RubyContext.checkInstanceVariableName(getContext(), name, this);
}

protected ReadHeadObjectFieldNode createReadFieldNode(String name) {
return ReadHeadObjectFieldNodeGen.create(name, nil());
}

}
Original file line number Diff line number Diff line change
@@ -164,12 +164,7 @@ protected DynamicObject createBigDecimal(VirtualFrame frame, Object value) {
return createBigDecimal.executeCreate(frame, value);
}

protected DynamicObject initializeBigDecimal(VirtualFrame frame, Object value, DynamicObject self) {
setupCreateBigDecimal();
return createBigDecimal.executeInitialize(frame, value, self);
}

protected DynamicObject initializeBigDecimal(VirtualFrame frame, Object value, DynamicObject self, int digits) {
protected DynamicObject initializeBigDecimal(VirtualFrame frame, Object value, DynamicObject self, Object digits) {
setupCreateBigDecimal();
return createBigDecimal.executeInitialize(frame, value, self, digits);
}
@@ -267,7 +262,7 @@ private void setBigDecimalValue(DynamicObject bigdecimal, Type type) {
Layouts.BIG_DECIMAL.setType(bigdecimal, type);
}

public abstract DynamicObject executeInitialize(VirtualFrame frame, Object value, DynamicObject alreadyAllocatedSelf, int digits);
public abstract DynamicObject executeInitialize(VirtualFrame frame, Object value, DynamicObject alreadyAllocatedSelf, Object digits);

public final DynamicObject executeCreate(VirtualFrame frame, Object value) {
if (allocateNode == null) {
@@ -276,11 +271,12 @@ public final DynamicObject executeCreate(VirtualFrame frame, Object value) {
}

DynamicObject rubyClass = (getBigDecimalClass());
return executeInitialize(frame, value, (DynamicObject) allocateNode.call(frame, rubyClass, "allocate", null));
return executeInitialize(frame, value, (DynamicObject) allocateNode.call(frame, rubyClass, "allocate", null), NotProvided.INSTANCE);
}

public final DynamicObject executeInitialize(VirtualFrame frame, Object value, DynamicObject alreadyAllocatedSelf) {
return executeInitialize(frame, value, alreadyAllocatedSelf, 0);
@Specialization
public DynamicObject create(VirtualFrame frame, long value, DynamicObject self, NotProvided digits) {
return create(frame, value, self, 0);
}

@Specialization
@@ -290,6 +286,12 @@ public DynamicObject create(VirtualFrame frame, long value, DynamicObject self,
return self;
}

@Specialization
public DynamicObject create(VirtualFrame frame, double value, DynamicObject self, NotProvided digits) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().argumentError("can't omit precision for a Float.", this));
}

@Specialization
public DynamicObject create(VirtualFrame frame, double value, DynamicObject self, int digits) {
setBigDecimalValue(self,
@@ -298,41 +300,60 @@ public DynamicObject create(VirtualFrame frame, double value, DynamicObject self
}

@Specialization(guards = "value == NEGATIVE_INFINITY || value == POSITIVE_INFINITY")
public DynamicObject createInfinity(VirtualFrame frame, Type value, DynamicObject self, int digits) {
public DynamicObject createInfinity(VirtualFrame frame, Type value, DynamicObject self, Object digits) {
return createWithMode(frame, value, self, "EXCEPTION_INFINITY", "Computation results to 'Infinity'");
}

@Specialization(guards = "value == NAN")
public DynamicObject createNaN(VirtualFrame frame, Type value, DynamicObject self, int digits) {
public DynamicObject createNaN(VirtualFrame frame, Type value, DynamicObject self, Object digits) {
return createWithMode(frame, value, self, "EXCEPTION_NaN", "Computation results to 'NaN'(Not a Number)");
}

@Specialization(guards = "value == NEGATIVE_ZERO")
public DynamicObject createNegativeZero(VirtualFrame frame, Type value, DynamicObject self, int digits) {
public DynamicObject createNegativeZero(VirtualFrame frame, Type value, DynamicObject self, Object digits) {
setBigDecimalValue(self, value);
return self;
}

@Specialization
public DynamicObject create(VirtualFrame frame, BigDecimal value, DynamicObject self, NotProvided digits) {
return create(frame, value, self, 0);
}
@Specialization
public DynamicObject create(VirtualFrame frame, BigDecimal value, DynamicObject self, int digits) {
setBigDecimalValue(self, value.round(new MathContext(digits, getRoundMode(frame))));
return self;
}

@Specialization(guards = "isRubyBignum(value)")
public DynamicObject createBignum(VirtualFrame frame, DynamicObject value, DynamicObject self, NotProvided digits) {
return createBignum(frame, value, self, 0);
}

@Specialization(guards = "isRubyBignum(value)")
public DynamicObject createBignum(VirtualFrame frame, DynamicObject value, DynamicObject self, int digits) {
setBigDecimalValue(self,
getBignumBigDecimalValue(value).round(new MathContext(digits, getRoundMode(frame))));
return self;
}

@Specialization(guards = "isRubyBigDecimal(value)")
public DynamicObject createBigDecimal(VirtualFrame frame, DynamicObject value, DynamicObject self, NotProvided digits) {
return createBigDecimal(frame, value, self, 0);
}

@Specialization(guards = "isRubyBigDecimal(value)")
public DynamicObject createBigDecimal(VirtualFrame frame, DynamicObject value, DynamicObject self, int digits) {
setBigDecimalValue(self,
Layouts.BIG_DECIMAL.getValue(value).round(new MathContext(digits, getRoundMode(frame))));
return self;
}

@Specialization(guards = "isRubyString(value)")
public DynamicObject createString(VirtualFrame frame, DynamicObject value, DynamicObject self, NotProvided digits) {
return createString(frame, value, self, 0);
}

@Specialization(guards = "isRubyString(value)")
public DynamicObject createString(VirtualFrame frame, DynamicObject value, DynamicObject self, int digits) {
return executeInitialize(frame, getValueFromString(value.toString(), digits), self, digits);
@@ -460,7 +481,7 @@ public InitializeNode(RubyContext context, SourceSection sourceSection) {

@Specialization
public Object initialize(VirtualFrame frame, DynamicObject self, Object value, NotProvided digits) {
return initializeBigDecimal(frame, value, self);
return initializeBigDecimal(frame, value, self, digits);
}

@Specialization
@@ -1864,7 +1885,7 @@ public Object roundSpecial(VirtualFrame frame, DynamicObject value, NotProvided
}
}

@Specialization(guards = {"!isNormal(value)", "wasProvided(precision)"})
@Specialization(guards = { "!isNormal(value)", "wasProvided(precision)" })
public Object roundSpecial(VirtualFrame frame, DynamicObject value, Object precision, Object unusedRoundingMode) {
return value;
}
@@ -2073,7 +2094,7 @@ public BigDecimal doBigDecimal(DynamicObject value) {
return Layouts.BIG_DECIMAL.getValue(value);
}

@Specialization(guards = {"!isRubyBignum(value)", "!isRubyBigDecimal(value)"})
@Specialization(guards = { "!isRubyBignum(value)", "!isRubyBigDecimal(value)" })
public Object doOther(VirtualFrame frame, DynamicObject value) {
final Object result = ruby(
frame,

0 comments on commit aef8516

Please sign in to comment.