Skip to content

Commit

Permalink
Showing 25 changed files with 513 additions and 259 deletions.
6 changes: 3 additions & 3 deletions core/pom.xml
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ DO NOT MODIFIY - GENERATED CODE
<artifactId>jruby-core</artifactId>
<name>JRuby Core</name>
<properties>
<version.ruby>2.2.2</version.ruby>
<version.ruby>2.2.3</version.ruby>
<prawn.dir>${test.dir}/prawn</prawn.dir>
<spec.tags.dir>${spec.dir}/tags</spec.tags.dir>
<polyglot.dump.pom>pom.xml</polyglot.dump.pom>
@@ -28,7 +28,7 @@ DO NOT MODIFIY - GENERATED CODE
<jruby.test.memory.permgen>2G</jruby.test.memory.permgen>
<installer.gems>${jruby.win32ole.gem}</installer.gems>
<prawn.git.repo>git://github.com/sandal/prawn.git</prawn.git.repo>
<version.ruby.minor>2</version.ruby.minor>
<version.ruby.minor>3</version.ruby.minor>
<tzdata.version>2013d</tzdata.version>
<install4j.executable>/Applications/install4j 4/bin/install4jc</install4j.executable>
<jay.bin>jay</jay.bin>
@@ -48,7 +48,7 @@ DO NOT MODIFIY - GENERATED CODE
<parser.dir>core/src/main/java/org/jruby/parser</parser.dir>
<jruby.basedir>${basedir}/..</jruby.basedir>
<rubyspec.dir>${spec.dir}/ruby</rubyspec.dir>
<version.ruby.revision>50293</version.ruby.revision>
<version.ruby.revision>51636</version.ruby.revision>
<jruby.test.memory>3G</jruby.test.memory>
<mspec.dir>${spec.dir}/mspec</mspec.dir>
<build.date>${maven.build.timestamp}</build.date>
45 changes: 23 additions & 22 deletions core/src/main/java/org/jruby/ext/bigdecimal/RubyBigDecimal.java
Original file line number Diff line number Diff line change
@@ -506,24 +506,21 @@ private static RubyBigDecimal newInstance(ThreadContext context, IRubyObject rec
String strValue = arg.convertToString().toString().trim();

int sign = 1;
if(strValue.length() > 0) {
switch (strValue.charAt(0)) {
case '_' :
return newZero(context.runtime, 1); // leading "_" are not allowed
case 'N' :
if ( "NaN".equals(strValue) ) return newNaN(context.runtime);
break;
case 'I' :
if ( "Infinity".equals(strValue) ) return newInfinity(context.runtime, 1);
break;
case '-' :
if ( "-Infinity".equals(strValue) ) return newInfinity(context.runtime, -1);
sign = -1;
break;
case '+' :
if ( "+Infinity".equals(strValue) ) return newInfinity(context.runtime, +1);
break;
}
switch ( strValue.length() > 0 ? strValue.charAt(0) : ' ' ) {
case '_' : return newZero(context.runtime, 1); // leading "_" are not allowed
case 'N' :
if ( "NaN".equals(strValue) ) return newNaN(context.runtime);
break;
case 'I' :
if ( "Infinity".equals(strValue) ) return newInfinity(context.runtime, 1);
break;
case '-' :
if ( "-Infinity".equals(strValue) ) return newInfinity(context.runtime, -1);
sign = -1;
break;
case '+' :
if ( "+Infinity".equals(strValue) ) return newInfinity(context.runtime, +1);
break;
}

// Convert String to Java understandable format (for BigDecimal).
@@ -533,17 +530,21 @@ private static RubyBigDecimal newInstance(ThreadContext context, IRubyObject rec
Matcher matcher = NUMBER_PATTERN.matcher(strValue);
strValue = matcher.replaceFirst("$1"); // 3. MRI ignores the trailing junk

String exp = matcher.group(2);
if(!exp.isEmpty()) {
String exp = matcher.group(2); int idx;
if ( exp != null && ! exp.isEmpty() ) {
String expValue = matcher.group(3);
if (expValue.isEmpty() || expValue.equals("-") || expValue.equals("+")) {
strValue = strValue.concat("0"); // 4. MRI allows 1E, 1E-, 1E+
} else if (isExponentOutOfRange(expValue)) {
}
else if (isExponentOutOfRange(expValue)) {
// Handle infinity (Integer.MIN_VALUE + 1) < expValue < Integer.MAX_VALUE
return newInfinity(context.runtime, sign);
}
}

else if ( ( idx = matcher.start(3) ) > 0 ) {
strValue = strValue.substring(0, idx); // ignored tail junk e.g. "5-6" -> "-6"
}

BigDecimal decimal;
try {
decimal = new BigDecimal(strValue, mathContext);
9 changes: 4 additions & 5 deletions core/src/main/java/org/jruby/ext/timeout/Timeout.java
Original file line number Diff line number Diff line change
@@ -46,7 +46,6 @@
import org.jruby.anno.JRubyMethod;
import org.jruby.exceptions.RaiseException;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.Arity;
import org.jruby.runtime.Block;
import org.jruby.runtime.ThreadContext;
import static org.jruby.runtime.Visibility.*;
@@ -58,9 +57,9 @@
public class Timeout implements Library {
public void load(Ruby runtime, boolean wrap) throws IOException {
RubyModule timeout = runtime.defineModule("Timeout");
RubyClass superclass = runtime.getRuntimeError();
RubyClass timeoutError = runtime.defineClassUnder("Error", superclass, superclass.getAllocator(), timeout);
runtime.defineClassUnder("ExitException", runtime.getException(), runtime.getException().getAllocator(), timeout);
RubyClass RuntimeError = runtime.getRuntimeError();
RubyClass TimeoutError = runtime.defineClassUnder("Error", RuntimeError, RuntimeError.getAllocator(), timeout);
timeout.defineConstant("ExitException", TimeoutError);

// Here we create an "anonymous" exception type used for unrolling the stack.
// MRI creates a new one for *every call* to timeout, which can be costly.
@@ -76,7 +75,7 @@ public void load(Ruby runtime, boolean wrap) throws IOException {
timeout.defineAnnotatedMethods(Timeout.class);

// Toplevel defines
runtime.getObject().defineConstant("TimeoutError", timeoutError);
runtime.getObject().defineConstant("TimeoutError", TimeoutError);
runtime.getObject().defineAnnotatedMethods(TimeoutToplevel.class);
}

Original file line number Diff line number Diff line change
@@ -34,90 +34,4 @@ public static PrepareBlockArgsInstr decode(IRReaderDecoder d) {
public void visit(IRVisitor visitor) {
visitor.PrepareBlockArgsInstr(this);
}

protected IRubyObject[] toAry(ThreadContext context, IRubyObject[] args) {
if (args.length == 1 && args[0].respondsTo("to_ary")) {
IRubyObject newAry = Helpers.aryToAry(args[0]);
if (newAry.isNil()) {
args = new IRubyObject[] { args[0] };
} else if (newAry instanceof RubyArray) {
args = ((RubyArray) newAry).toJavaArray();
} else {
throw context.runtime.newTypeError(args[0].getType().getName() + "#to_ary should return Array");
}
}
return args;
}

protected IRubyObject[] prepareProcArgs(ThreadContext context, Block b, IRubyObject[] args) {
if (args.length == 1) {
int arityValue = b.getBody().getSignature().arityValue();
return IRRuntimeHelpers.convertValueIntoArgArray(context, args[0], arityValue, b.type == Block.Type.NORMAL && args[0] instanceof RubyArray);
} else {
return args;
}
}

public IRubyObject[] prepareBlockArgs(ThreadContext context, Block b, IRubyObject[] args) {
// This is the placeholder for scenarios
// not handled by specialized instructions.
if (args == null) {
return IRubyObject.NULL_ARRAY;
}

boolean isProcCall = context.getCurrentBlockType() == Block.Type.PROC;
if (isProcCall) {
return prepareProcArgs(context, b, args);
}

boolean isLambda = b.type == Block.Type.LAMBDA;
if (isLambda && isProcCall) {
return args;
}

BlockBody body = b.getBody();
Signature sig = body.getSignature();

// blockArity == 0 and 1 have been handled in the specialized instructions
// This test is when we only have opt / rest arg (either keyword or non-keyword)
// but zero required args.
if (sig.arityValue() == -1) {
return args;
}

// We get here only when we have both required and optional/rest args
// (keyword or non-keyword in either case).
// So, convert a single value to an array if possible.
args = toAry(context, args);

// Nothing more to do for lambdas
if (isLambda) {
return args;
}

// Deal with keyword args that needs special handling
int needsKwargs = sig.hasKwargs() ? 1 - sig.getRequiredKeywordForArityCount() : 0;
int required = sig.required();
int actual = args.length;
if (needsKwargs == 0 || required > actual) {
// Nothing to do if we have fewer args in args than what is required
// The required arg instructions will return nil in those cases.
return args;
}

if (sig.isFixed() && required > 0 && required+needsKwargs != actual) {
// Make sure we have a ruby-hash
IRubyObject[] newArgs = Arrays.copyOf(args, required+needsKwargs);
if (actual < required+needsKwargs) {
// Not enough args and we need an empty {} for kwargs processing.
newArgs[newArgs.length - 1] = RubyHash.newHash(context.runtime);
} else {
// We have more args than we need and kwargs is always the last arg.
newArgs[newArgs.length - 1] = args[args.length - 1];
}
args = newArgs;
}

return args;
}
}
Original file line number Diff line number Diff line change
@@ -23,36 +23,6 @@ public static PrepareFixedBlockArgsInstr decode(IRReaderDecoder d) {
return new PrepareFixedBlockArgsInstr();
}

public IRubyObject[] prepareBlockArgs(ThreadContext context, Block b, IRubyObject[] args) {
if (args == null) {
return IRubyObject.NULL_ARRAY;
}

boolean isProcCall = context.getCurrentBlockType() == Block.Type.PROC;
if (isProcCall) {
return prepareProcArgs(context, b, args);
}

boolean isLambda = b.type == Block.Type.LAMBDA;
if (isLambda && isProcCall) {
return args;
}

// SSS FIXME: This check here is not required as long as
// the single-instruction cases always uses PreapreSingleBlockArgInstr
// But, including this here for robustness for now.
if (b.getBody().getSignature().arityValue() == 1) {
return args;
}

// Since we have more than 1 required arg,
// convert a single value to an array if possible.
args = toAry(context, args);

// If there are insufficient args, ReceivePreReqdInstr will return nil
return args;
}

@Override
public void visit(IRVisitor visitor) {
visitor.PrepareFixedBlockArgsInstr(this);
Original file line number Diff line number Diff line change
@@ -22,25 +22,6 @@ public Instr clone(CloneInfo ii) {
public static PrepareSingleBlockArgInstr decode(IRReaderDecoder d) {
return new PrepareSingleBlockArgInstr();
}

public IRubyObject[] prepareBlockArgs(ThreadContext context, Block b, IRubyObject[] args) {
if (args == null) args = IRubyObject.NULL_ARRAY;

// Deal with proc calls
if (context.getCurrentBlockType() == Block.Type.PROC) {
if (args.length == 0) {
args = context.runtime.getSingleNilArray();
} else if (args.length == 1) {
args = prepareProcArgs(context, b, args);
} else {
args = new IRubyObject[] { args[0] };
}
}

// Nothing more to do! Hurray!
// If there are insufficient args, ReceivePreReqdInstr will return nil
return args;
}

@Override
public void visit(IRVisitor visitor) {
Original file line number Diff line number Diff line change
@@ -47,6 +47,7 @@ public InterpreterContext(IRScope scope, List<Instr> instructions) {
this.temporaryVariablecount = scope.getTemporaryVariablesCount();
this.instructions = instructions != null ? prepareBuildInstructions(instructions) : null;
this.hasExplicitCallProtocol = scope.getFlags().contains(IRFlags.HAS_EXPLICIT_CALL_PROTOCOL);
// FIXME: Centralize this out of InterpreterContext
this.reuseParentDynScope = scope.getFlags().contains(IRFlags.REUSE_PARENT_DYNSCOPE);
this.pushNewDynScope = !scope.getFlags().contains(IRFlags.DYNSCOPE_ELIMINATED) && !reuseParentDynScope;
this.popDynScope = this.pushNewDynScope || this.reuseParentDynScope;
36 changes: 7 additions & 29 deletions core/src/main/java/org/jruby/ir/interpreter/InterpreterEngine.java
Original file line number Diff line number Diff line change
@@ -17,7 +17,6 @@
import org.jruby.ir.instructions.LineNumberInstr;
import org.jruby.ir.instructions.NonlocalReturnInstr;
import org.jruby.ir.instructions.PopBlockFrameInstr;
import org.jruby.ir.instructions.PrepareBlockArgsInstr;
import org.jruby.ir.instructions.PushBlockFrameInstr;
import org.jruby.ir.instructions.ReceiveArgBase;
import org.jruby.ir.instructions.ReceivePostReqdArgInstr;
@@ -58,8 +57,6 @@
import org.jruby.ir.operands.Variable;
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;
@@ -106,17 +103,6 @@ public IRubyObject interpret(ThreadContext context, Block block, IRubyObject sel
return interpret(context, block, self, interpreterContext, implClass, name, new IRubyObject[] {arg1, arg2, arg3, arg4}, blockArg);
}

private DynamicScope getNewBlockScope(ThreadContext context, Block block, InterpreterContext interpreterContext) {
DynamicScope newScope = block.getBinding().getDynamicScope();
if (interpreterContext.pushNewDynScope()) return block.allocScope(newScope);

// Reuse! We can avoid the push only if surrounding vars aren't referenced!
if (interpreterContext.reuseParentDynScope()) return newScope;

// No change
return null;
}

public IRubyObject interpret(ThreadContext context, Block block, IRubyObject self,
InterpreterContext interpreterContext, RubyModule implClass,
String name, IRubyObject[] args, Block blockArg) {
@@ -187,27 +173,19 @@ public IRubyObject interpret(ThreadContext context, Block block, IRubyObject sel
context.pushScope(currDynScope);
break;
case PUSH_BLOCK_BINDING:
DynamicScope newScope = getNewBlockScope(context, block, interpreterContext);
if (newScope != null) {
currDynScope = newScope;
context.pushScope(currDynScope);
}
currDynScope = IRRuntimeHelpers.pushBlockDynamicScopeIfNeeded(context, block, interpreterContext.pushNewDynScope(), interpreterContext.reuseParentDynScope());
break;
case 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);
self = IRRuntimeHelpers.updateBlockState(block, self);
break;
case PREPARE_SINGLE_BLOCK_ARG:
args = IRRuntimeHelpers.prepareSingleBlockArgs(context, block, args);
break;
case PREPARE_FIXED_BLOCK_ARGS:
args = IRRuntimeHelpers.prepareFixedBlockArgs(context, block, args);
break;
case PREPARE_BLOCK_ARGS:
args = ((PrepareBlockArgsInstr)instr).prepareBlockArgs(context, block, args);
if (block.type == Block.Type.LAMBDA) block.getBody().getSignature().checkArity(context.runtime, args);
args = IRRuntimeHelpers.prepareBlockArgs(context, block, args);
break;
default:
processBookKeepingOp(context, block, instr, operation, name, args, self, blockArg, implClass, currDynScope, temp, currScope);
Original file line number Diff line number Diff line change
@@ -92,10 +92,10 @@ public Object execute(IRScope scope, Object... data) {
if (scope instanceof IRClosure) {
savedViz = scope.createTemporaryVariable();
savedFrame = scope.createTemporaryVariable();
entryBB.addInstr(new SaveBindingVisibilityInstr(savedViz));
entryBB.addInstr(new PushBlockFrameInstr(savedFrame, scope.getName()));
if (requireBinding) entryBB.addInstr(new PushBlockBindingInstr());
entryBB.addInstr(new UpdateBlockExecutionStateInstr(Self.SELF));
entryBB.insertInstr(0, new SaveBindingVisibilityInstr(savedViz));
entryBB.insertInstr(1, new PushBlockFrameInstr(savedFrame, scope.getName()));
entryBB.insertInstr(2, new UpdateBlockExecutionStateInstr(Self.SELF));
if (requireBinding) entryBB.insertInstr(3, new PushBlockBindingInstr());
Signature sig = ((IRClosure)scope).getSignature();

// If it doesn't need any args, no arg preparation involved!
Original file line number Diff line number Diff line change
@@ -86,6 +86,10 @@ public void insertInstr(Instr i) {
instrs.add(0, i);
}

public void insertInstr(int index, Instr i) {
instrs.add(index, i);
}

public List<Instr> getInstrs() {
return instrs;
}
177 changes: 177 additions & 0 deletions core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java
Original file line number Diff line number Diff line change
@@ -47,6 +47,7 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.invoke.MethodHandle;
import java.util.Arrays;

public class IRRuntimeHelpers {
private static final Logger LOG = LoggerFactory.getLogger("IRRuntimeHelpers");
@@ -793,6 +794,7 @@ public static RubyModule findInstanceMethodContainer(ThreadContext context, Dyna
case MODULE_BODY:
case CLASS_BODY:
case METACLASS_BODY:
case SCRIPT_BODY:
return (RubyModule) self;

case INSTANCE_METHOD:
@@ -1465,4 +1467,179 @@ public static RubyFixnum getArgScopeDepth(ThreadContext context, StaticScope cur
}
return context.runtime.newFixnum(i);
}

public static IRubyObject[] toAry(ThreadContext context, IRubyObject[] args) {
if (args.length == 1 && args[0].respondsTo("to_ary")) {
IRubyObject newAry = Helpers.aryToAry(args[0]);
if (newAry.isNil()) {
args = new IRubyObject[] { args[0] };
} else if (newAry instanceof RubyArray) {
args = ((RubyArray) newAry).toJavaArray();
} else {
throw context.runtime.newTypeError(args[0].getType().getName() + "#to_ary should return Array");
}
}
return args;
}

public static IRubyObject[] prepareProcArgs(ThreadContext context, Block b, IRubyObject[] args) {
if (args.length == 1) {
int arityValue = b.getBody().getSignature().arityValue();
return IRRuntimeHelpers.convertValueIntoArgArray(context, args[0], arityValue, b.type == Block.Type.NORMAL && args[0] instanceof RubyArray);
} else {
return args;
}
}

@JIT
public static IRubyObject[] prepareBlockArgs(ThreadContext context, Block block, IRubyObject[] args) {
// This is the placeholder for scenarios
// not handled by specialized instructions.
if (args == null) {
return IRubyObject.NULL_ARRAY;
}

boolean isProcCall = context.getCurrentBlockType() == Block.Type.PROC;
if (isProcCall) {
return prepareProcArgs(context, block, args);
}

boolean isLambda = block.type == Block.Type.LAMBDA;
if (isLambda && isProcCall) {
return args;
}

BlockBody body = block.getBody();
org.jruby.runtime.Signature sig = body.getSignature();

// blockArity == 0 and 1 have been handled in the specialized instructions
// This test is when we only have opt / rest arg (either keyword or non-keyword)
// but zero required args.
if (sig.arityValue() == -1) {
return args;
}

// We get here only when we have both required and optional/rest args
// (keyword or non-keyword in either case).
// So, convert a single value to an array if possible.
args = toAry(context, args);

// Nothing more to do for lambdas
if (isLambda) {
return args;
}

// Deal with keyword args that needs special handling
int needsKwargs = sig.hasKwargs() ? 1 - sig.getRequiredKeywordForArityCount() : 0;
int required = sig.required();
int actual = args.length;
if (needsKwargs == 0 || required > actual) {
// Nothing to do if we have fewer args in args than what is required
// The required arg instructions will return nil in those cases.
return args;
}

if (sig.isFixed() && required > 0 && required+needsKwargs != actual) {
// Make sure we have a ruby-hash
IRubyObject[] newArgs = Arrays.copyOf(args, required + needsKwargs);
if (actual < required+needsKwargs) {
// Not enough args and we need an empty {} for kwargs processing.
newArgs[newArgs.length - 1] = RubyHash.newHash(context.runtime);
} else {
// We have more args than we need and kwargs is always the last arg.
newArgs[newArgs.length - 1] = args[args.length - 1];
}
args = newArgs;
}

if (block.type == Block.Type.LAMBDA) block.getBody().getSignature().checkArity(context.runtime, args);

return args;
}

public static IRubyObject[] prepareFixedBlockArgs(ThreadContext context, Block block, IRubyObject[] args) {
if (args == null) {
return IRubyObject.NULL_ARRAY;
}

boolean isProcCall = context.getCurrentBlockType() == Block.Type.PROC;
if (isProcCall) {
return IRRuntimeHelpers.prepareProcArgs(context, block, args);
}

boolean isLambda = block.type == Block.Type.LAMBDA;
if (isLambda && isProcCall) {
return args;
}

// SSS FIXME: This check here is not required as long as
// the single-instruction cases always uses PreapreSingleBlockArgInstr
// But, including this here for robustness for now.
if (block.getBody().getSignature().arityValue() == 1) {
return args;
}

// Since we have more than 1 required arg,
// convert a single value to an array if possible.
args = IRRuntimeHelpers.toAry(context, args);

if (block.type == Block.Type.LAMBDA) block.getBody().getSignature().checkArity(context.runtime, args);

// If there are insufficient args, ReceivePreReqdInstr will return nil
return args;
}

public static IRubyObject[] prepareSingleBlockArgs(ThreadContext context, Block block, IRubyObject[] args) {
if (args == null) args = IRubyObject.NULL_ARRAY;

// Deal with proc calls
if (context.getCurrentBlockType() == Block.Type.PROC) {
if (args.length == 0) {
args = context.runtime.getSingleNilArray();
} else if (args.length == 1) {
args = prepareProcArgs(context, block, args);
} else {
args = new IRubyObject[] { args[0] };
}
}

if (block.type == Block.Type.LAMBDA) block.getBody().getSignature().checkArity(context.runtime, args);

// Nothing more to do! Hurray!
// If there are insufficient args, ReceivePreReqdInstr will return nil
return args;
}

private static DynamicScope getNewBlockScope(Block block, boolean pushNewDynScope, boolean reuseParentDynScope) {
DynamicScope newScope = block.getBinding().getDynamicScope();
if (pushNewDynScope) return block.allocScope(newScope);

// Reuse! We can avoid the push only if surrounding vars aren't referenced!
if (reuseParentDynScope) return newScope;

// No change
return null;
}

@JIT
public static DynamicScope pushBlockDynamicScopeIfNeeded(ThreadContext context, Block block, boolean pushNewDynScope, boolean reuseParentDynScope) {
DynamicScope newScope = getNewBlockScope(block, pushNewDynScope, reuseParentDynScope);
if (newScope != null) {
context.pushScope(newScope);
}
return newScope;
}

@JIT
public static IRubyObject updateBlockState(Block block, IRubyObject self) {
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);
return self;
}
}
14 changes: 13 additions & 1 deletion core/src/main/java/org/jruby/ir/targets/IRBytecodeAdapter.java
Original file line number Diff line number Diff line change
@@ -132,6 +132,10 @@ public void loadContext() {
adapter.aload(signature.argOffset("context"));
}

public void loadSelfBlock() {
adapter.aload(signature.argOffset(JVMVisitor.SELF_BLOCK_NAME));
}

public void loadStaticScope() {
adapter.aload(signature.argOffset("scope"));
}
@@ -145,7 +149,7 @@ public void loadArgs() {
}

public void loadBlock() {
adapter.aload(signature.argOffset("block"));
adapter.aload(signature.argOffset(JVMVisitor.BLOCK_ARG_NAME));
}

public void loadFrameClass() {
@@ -170,6 +174,14 @@ public void loadBlockType() {
}
}

public void storeSelf() {
adapter.astore(signature.argOffset("self"));
}

public void storeArgs() {
adapter.astore(signature.argOffset("args"));
}

public void storeLocal(int i) {
adapter.astore(i);
}
112 changes: 101 additions & 11 deletions core/src/main/java/org/jruby/ir/targets/JVMVisitor.java
Original file line number Diff line number Diff line change
@@ -58,6 +58,16 @@ public class JVMVisitor extends IRVisitor {
private static final Logger LOG = LoggerFactory.getLogger("JVMVisitor");
public static final String DYNAMIC_SCOPE = "$dynamicScope";
private static final boolean DEBUG = false;
public static final String BLOCK_ARG_NAME = "blockArg";
public static final String SELF_BLOCK_NAME = "selfBlock";

private static final Signature METHOD_SIGNATURE_BASE = Signature
.returning(IRubyObject.class)
.appendArgs(new String[]{"context", "scope", "self", BLOCK_ARG_NAME, "class", "callName"}, ThreadContext.class, StaticScope.class, IRubyObject.class, Block.class, RubyModule.class, String.class);

public static final Signature CLOSURE_SIGNATURE = Signature
.returning(IRubyObject.class)
.appendArgs(new String[]{"context", SELF_BLOCK_NAME, "scope", "self", "args", BLOCK_ARG_NAME, "superName", "type"}, ThreadContext.class, Block.class, StaticScope.class, IRubyObject.class, IRubyObject[].class, Block.class, String.class, Block.Type.class);

public JVMVisitor() {
this.jvm = Options.COMPILE_INVOKEDYNAMIC.load() ? new JVM7() : new JVM6();
@@ -143,12 +153,17 @@ public void emitScope(IRScope scope, String name, Signature signature, boolean s
jvm.cls().visitField(Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC | Opcodes.ACC_VOLATILE, scopeField, ci(IRScope.class), null, null).visitEnd();
}

// Some scopes (closures, module/class bodies) do not have explicit call protocol yet.
// Unconditionally load current dynamic scope for those bodies.
if (!scope.hasExplicitCallProtocol()) {
// No call protocol, dynscope has been prepared for us
jvmMethod().loadContext();
jvmMethod().invokeVirtual(Type.getType(ThreadContext.class), Method.getMethod("org.jruby.runtime.DynamicScope getCurrentScope()"));
jvmStoreLocal(DYNAMIC_SCOPE);
} else if (scope instanceof IRClosure) {
// just load scope from context
// FIXME: don't do this if we won't need the scope
jvmMethod().loadContext();
jvmAdapter().invokevirtual(p(ThreadContext.class), "getCurrentScope", sig(DynamicScope.class));
jvmStoreLocal(DYNAMIC_SCOPE);
}

IRBytecodeAdapter m = jvmMethod();
@@ -198,10 +213,6 @@ public void emitScope(IRScope scope, String name, Signature signature, boolean s
jvm.popmethod();
}

private static final Signature METHOD_SIGNATURE_BASE = Signature
.returning(IRubyObject.class)
.appendArgs(new String[]{"context", "scope", "self", "block", "class", "callName"}, ThreadContext.class, StaticScope.class, IRubyObject.class, Block.class, RubyModule.class, String.class);

public static final Signature signatureFor(IRScope method, boolean aritySplit) {
if (aritySplit) {
StaticScope argScope = method.getStaticScope();
@@ -224,10 +235,6 @@ public static final Signature signatureFor(IRScope method, boolean aritySplit) {
return METHOD_SIGNATURE_BASE.insertArgs(3, new String[]{"args"}, IRubyObject[].class);
}

public static final Signature CLOSURE_SIGNATURE = Signature
.returning(IRubyObject.class)
.appendArgs(new String[]{"context", "scope", "self", "args", "block", "superName", "type"}, ThreadContext.class, StaticScope.class, IRubyObject.class, IRubyObject[].class, Block.class, String.class, Block.Type.class);

public void emitScriptBody(IRScriptBody script) {
// Note: no index attached because there should be at most one script body per .class
String name = JavaNameMangler.encodeScopeForBacktrace(script);
@@ -1390,12 +1397,46 @@ public void PopBindingInstr(PopBindingInstr popbindinginstr) {
jvmMethod().invokeVirtual(Type.getType(ThreadContext.class), Method.getMethod("void popScope()"));
}

@Override
public void PopBlockFrameInstr(PopBlockFrameInstr instr) {
jvmMethod().loadContext();
visit(instr.getFrame());
jvmAdapter().invokevirtual(p(ThreadContext.class), "postYieldNoScope", sig(void.class, Frame.class));
}

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

@Override
public void PrepareBlockArgsInstr(PrepareBlockArgsInstr instr) {
jvmMethod().loadContext();
jvmMethod().loadSelfBlock();
jvmMethod().loadArgs();
jvmMethod().invokeIRHelper("prepareBlockArgs", sig(IRubyObject[].class, ThreadContext.class, Block.class, IRubyObject[].class));
jvmMethod().storeArgs();
}

@Override
public void PrepareFixedBlockArgsInstr(PrepareFixedBlockArgsInstr instr) {
jvmMethod().loadContext();
jvmMethod().loadSelfBlock();
jvmMethod().loadArgs();
jvmMethod().invokeIRHelper("prepareFixedBlockArgs", sig(IRubyObject[].class, ThreadContext.class, Block.class, IRubyObject[].class));
jvmMethod().storeArgs();
}

@Override
public void PrepareSingleBlockArgInstr(PrepareSingleBlockArgInstr instr) {
jvmMethod().loadContext();
jvmMethod().loadSelfBlock();
jvmMethod().loadArgs();
jvmMethod().invokeIRHelper("prepareSingleBlockArgs", sig(IRubyObject[].class, ThreadContext.class, Block.class, IRubyObject[].class));
jvmMethod().storeArgs();
}

@Override
public void ProcessModuleBodyInstr(ProcessModuleBodyInstr processmodulebodyinstr) {
jvmMethod().loadContext();
@@ -1405,6 +1446,31 @@ public void ProcessModuleBodyInstr(ProcessModuleBodyInstr processmodulebodyinstr
jvmStoreLocal(processmodulebodyinstr.getResult());
}

@Override
public void PushBlockBindingInstr(PushBlockBindingInstr instr) {
IRScope scope = jvm.methodData().scope;
// FIXME: Centralize this out of InterpreterContext
boolean reuseParentDynScope = scope.getFlags().contains(IRFlags.REUSE_PARENT_DYNSCOPE);
boolean pushNewDynScope = !scope.getFlags().contains(IRFlags.DYNSCOPE_ELIMINATED) && !reuseParentDynScope;
boolean popDynScope = pushNewDynScope || reuseParentDynScope;

jvmMethod().loadContext();
jvmMethod().loadSelfBlock();
jvmAdapter().ldc(pushNewDynScope);
jvmAdapter().ldc(reuseParentDynScope);
jvmMethod().invokeIRHelper("pushBlockDynamicScopeIfNeeded", sig(DynamicScope.class, ThreadContext.class, Block.class, boolean.class, boolean.class));
jvmStoreLocal(DYNAMIC_SCOPE);
}

@Override
public void PushBlockFrameInstr(PushBlockFrameInstr instr) {
jvmMethod().loadContext();
jvmMethod().loadSelfBlock();
jvmAdapter().invokevirtual(p(Block.class), "getBinding", sig(Binding.class));
jvmAdapter().invokevirtual(p(ThreadContext.class), "preYieldNoScope", sig(Frame.class, Binding.class));
jvmStoreLocal(instr.getResult());
}

@Override
public void PushMethodBindingInstr(PushMethodBindingInstr pushbindinginstr) {
jvmMethod().loadContext();
@@ -1488,7 +1554,7 @@ public void PutGlobalVarInstr(PutGlobalVarInstr putglobalvarinstr) {
@Override
public void ReifyClosureInstr(ReifyClosureInstr reifyclosureinstr) {
jvmMethod().loadRuntime();
jvmLoadLocal("$block");
jvmLoadLocal("$blockArg");
jvmMethod().invokeIRHelper("newProc", sig(IRubyObject.class, Ruby.class, Block.class));
jvmStoreLocal(reifyclosureinstr.getResult());
}
@@ -1622,6 +1688,14 @@ public void RestArgMultipleAsgnInstr(RestArgMultipleAsgnInstr restargmultipleasg
jvmStoreLocal(restargmultipleasgninstr.getResult());
}

@Override
public void RestoreBindingVisibilityInstr(RestoreBindingVisibilityInstr instr) {
jvmMethod().loadSelfBlock();
jvmAdapter().invokevirtual(p(Block.class), "getBinding", sig(Binding.class));
visit(instr.getVisibility());
jvmAdapter().invokevirtual(p(Binding.class), "setVisibility", sig(void.class, Visibility.class));
}

@Override
public void RuntimeHelperCall(RuntimeHelperCall runtimehelpercall) {
switch (runtimehelpercall.getHelperMethod()) {
@@ -1731,6 +1805,14 @@ public void RuntimeHelperCall(RuntimeHelperCall runtimehelpercall) {
}
}

@Override
public void SaveBindingVisibilityInstr(SaveBindingVisibilityInstr instr) {
jvmMethod().loadSelfBlock();
jvmAdapter().invokevirtual(p(Block.class), "getBinding", sig(Binding.class));
jvmAdapter().invokevirtual(p(Binding.class), "getVisibility", sig(Visibility.class));
jvmStoreLocal(instr.getResult());
}

@Override
public void ToggleBacktraceInstr(ToggleBacktraceInstr instr) {
jvmMethod().loadContext();
@@ -1859,6 +1941,14 @@ public void UnresolvedSuperInstr(UnresolvedSuperInstr unresolvedsuperinstr) {
superCommon(name, unresolvedsuperinstr, args, definingModule, containsArgSplat, closure);
}

@Override
public void UpdateBlockExecutionStateInstr (UpdateBlockExecutionStateInstr instr) {
jvmMethod().loadSelfBlock();
jvmMethod().loadSelf();
jvmMethod().invokeIRHelper("updateBlockState", sig(IRubyObject.class, Block.class, IRubyObject.class));
jvmMethod().storeSelf();
}

@Override
public void YieldInstr(YieldInstr yieldinstr) {
jvmMethod().loadContext();
19 changes: 16 additions & 3 deletions core/src/main/java/org/jruby/runtime/CompiledIRBlockBody.java
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@ public CompiledIRBlockBody(MethodHandle handle, IRScope closure, long encodedSig
this.reuseParentScope = closure.getFlags().contains(IRFlags.REUSE_PARENT_DYNSCOPE);
this.pushScope = !closure.getFlags().contains(IRFlags.DYNSCOPE_ELIMINATED) && !this.reuseParentScope;
this.usesKwargs = closure.receivesKeywordArgs();
this.hasCallProtocolIR = closure.getFlags().contains(IRFlags.HAS_EXPLICIT_CALL_PROTOCOL);

// Done in the interpreter (WrappedIRClosure) but we do it here
closure.getStaticScope().determineModule();
@@ -33,12 +34,24 @@ public ArgumentDescriptor[] getArgumentDescriptors() {

@Override
protected IRubyObject callDirect(ThreadContext context, Block block, IRubyObject[] args, Block blockArg) {
throw new RuntimeException("callDirect not implemented in CompiledIRBlockBody. Implement me!");
context.setCurrentBlockType(Block.Type.PROC);
try {
return (IRubyObject)handle.invokeExact(context, block, getStaticScope(), (IRubyObject)null, args, blockArg, block.getBinding().getMethod(), block.type);
} catch (Throwable t) {
Helpers.throwException(t);
return null; // not reached
}
}

@Override
protected IRubyObject yieldDirect(ThreadContext context, Block block, IRubyObject[] args, IRubyObject self) {
throw new RuntimeException("yieldDirect not implemented in CompiledIRBlockBody. Implement me!");
context.setCurrentBlockType(Block.Type.NORMAL);
try {
return (IRubyObject)handle.invokeExact(context, block, getStaticScope(), self, args, Block.NULL_BLOCK, block.getBinding().getMethod(), block.type);
} catch (Throwable t) {
Helpers.throwException(t);
return null; // not reached
}
}

protected IRubyObject commonYieldPath(ThreadContext context, Block block, IRubyObject[] args, IRubyObject self, Block blockArg) {
@@ -70,7 +83,7 @@ protected IRubyObject commonYieldPath(ThreadContext context, Block block, IRubyO
if (usesKwargs) IRRuntimeHelpers.frobnicateKwargsArgument(context, getSignature().required(), args);

try {
return (IRubyObject)handle.invokeExact(context, getStaticScope(), self, args, blockArg, binding.getMethod(), block.type);
return (IRubyObject)handle.invokeExact(context, block, getStaticScope(), self, args, blockArg, binding.getMethod(), block.type);
} catch (Throwable t) {
Helpers.throwException(t);
return null; // not reached
6 changes: 3 additions & 3 deletions default.build.properties
Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@ rake.args=
install4j.executable=/Applications/install4j 4/bin/install4jc

# Ruby versions
version.ruby=2.2.2
version.ruby=2.2.3
version.ruby.major=2.2
version.ruby.minor=2
version.ruby.revision=50293
version.ruby.minor=3
version.ruby.revision=51636
68 changes: 55 additions & 13 deletions lib/ruby/stdlib/cmath.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
##
# = Trigonometric and transcendental functions for complex numbers.
#
# CMath is a library that provides trigonometric and transcendental
# functions for complex numbers.
# functions for complex numbers. The functions in this module accept
# integers, floating-point numbers or complex numbers as arguments.
#
# Note that the selection of functions is similar, but not identical,
# to that in module math. The reason for having two modules is that
# some users aren't interested in complex numbers, and perhaps don't
# even know what they are. They would rather have Math.sqrt(-1) raise
# an exception than return a complex number.
#
# == Usage
#
# To start using this library, simply:
# To start using this library, simply require cmath library:
#
# require "cmath"
#
# Square root of a negative number is a complex number.
# And after call any CMath function. For example:
#
# CMath.sqrt(-9) #=> 0+3.0i
# CMath.exp(0 + 0i) #=> 1.0+0.0i
# CMath.log10(-5.to_c) #=> (0.6989700043360187+1.3643763538418412i)
#
# CMath.sqrt(-9) #=> 0+3.0i
#
# For more information you can see Complec class.

module CMath

@@ -44,9 +57,7 @@ module CMath
##
# Math::E raised to the +z+ power
#
# exp(Complex(0,0)) #=> 1.0+0.0i
# exp(Complex(0,PI)) #=> -1.0+1.2246467991473532e-16i
# exp(Complex(0,PI/2.0)) #=> 6.123233995736766e-17+1.0i
# CMath.exp(2i) #=> (-0.4161468365471424+0.9092974268256817i)
def exp(z)
begin
if z.real?
@@ -62,10 +73,11 @@ def exp(z)
end

##
# Returns the natural logarithm of Complex. If a second argument is given,
# Returns the natural logarithm of Complex. If a second argument is given,
# it will be the base of logarithm.
#
# log(Complex(0,0)) #=> -Infinity+0.0i
# CMath.log(1 + 4i) #=> (1.416606672028108+1.3258176636680326i)
# CMath.log(1 + 4i, 10) #=> (0.6152244606891369+0.5757952953408879i)
def log(*args)
begin
z, b = args
@@ -88,6 +100,8 @@ def log(*args)

##
# returns the base 2 logarithm of +z+
#
# CMath.log2(-1) => (0.0+4.532360141827194i)
def log2(z)
begin
if z.real? and z >= 0
@@ -102,6 +116,8 @@ def log2(z)

##
# returns the base 10 logarithm of +z+
#
# CMath.log10(-1) #=> (0.0+1.3643763538418412i)
def log10(z)
begin
if z.real? and z >= 0
@@ -116,9 +132,8 @@ def log10(z)

##
# Returns the non-negative square root of Complex.
# sqrt(-1) #=> 0+1.0i
# sqrt(Complex(-1,0)) #=> 0.0+1.0i
# sqrt(Complex(0,8)) #=> 2.0+2.0i
#
# CMath.sqrt(-1 + 0i) #=> 0.0+1.0i
def sqrt(z)
begin
if z.real?
@@ -144,12 +159,16 @@ def sqrt(z)

##
# returns the principal value of the cube root of +z+
#
# CMath.cbrt(1 + 4i) #=> (1.449461632813119+0.6858152562177092i)
def cbrt(z)
z ** (1.0/3)
end

##
# returns the sine of +z+, where +z+ is given in radians
#
# CMath.sin(1 + 1i) #=> (1.2984575814159773+0.6349639147847361i)
def sin(z)
begin
if z.real?
@@ -165,6 +184,8 @@ def sin(z)

##
# returns the cosine of +z+, where +z+ is given in radians
#
# CMath.cos(1 + 1i) #=> (0.8337300251311491-0.9888977057628651i)
def cos(z)
begin
if z.real?
@@ -180,6 +201,8 @@ def cos(z)

##
# returns the tangent of +z+, where +z+ is given in radians
#
# CMath.tan(1 + 1i) #=> (0.27175258531951174+1.0839233273386943i)
def tan(z)
begin
if z.real?
@@ -194,6 +217,8 @@ def tan(z)

##
# returns the hyperbolic sine of +z+, where +z+ is given in radians
#
# CMath.sinh(1 + 1i) #=> (0.6349639147847361+1.2984575814159773i)
def sinh(z)
begin
if z.real?
@@ -209,6 +234,8 @@ def sinh(z)

##
# returns the hyperbolic cosine of +z+, where +z+ is given in radians
#
# CMath.cosh(1 + 1i) #=> (0.8337300251311491+0.9888977057628651i)
def cosh(z)
begin
if z.real?
@@ -224,6 +251,8 @@ def cosh(z)

##
# returns the hyperbolic tangent of +z+, where +z+ is given in radians
#
# CMath.tanh(1 + 1i) #=> (1.0839233273386943+0.27175258531951174i)
def tanh(z)
begin
if z.real?
@@ -238,6 +267,8 @@ def tanh(z)

##
# returns the arc sine of +z+
#
# CMath.asin(1 + 1i) #=> (0.6662394324925153+1.0612750619050355i)
def asin(z)
begin
if z.real? and z >= -1 and z <= 1
@@ -252,6 +283,8 @@ def asin(z)

##
# returns the arc cosine of +z+
#
# CMath.acos(1 + 1i) #=> (0.9045568943023813-1.0612750619050357i)
def acos(z)
begin
if z.real? and z >= -1 and z <= 1
@@ -266,6 +299,8 @@ def acos(z)

##
# returns the arc tangent of +z+
#
# CMath.atan(1 + 1i) #=> (1.0172219678978514+0.4023594781085251i)
def atan(z)
begin
if z.real?
@@ -281,6 +316,8 @@ def atan(z)
##
# returns the arc tangent of +y+ divided by +x+ using the signs of +y+ and
# +x+ to determine the quadrant
#
# CMath.atan2(1 + 1i, 0) #=> (1.5707963267948966+0.0i)
def atan2(y,x)
begin
if y.real? and x.real?
@@ -295,6 +332,8 @@ def atan2(y,x)

##
# returns the inverse hyperbolic sine of +z+
#
# CMath.asinh(1 + 1i) #=> (1.0612750619050357+0.6662394324925153i)
def asinh(z)
begin
if z.real?
@@ -309,6 +348,8 @@ def asinh(z)

##
# returns the inverse hyperbolic cosine of +z+
#
# CMath.acosh(1 + 1i) #=> (1.0612750619050357+0.9045568943023813i)
def acosh(z)
begin
if z.real? and z >= 1
@@ -323,6 +364,8 @@ def acosh(z)

##
# returns the inverse hyperbolic tangent of +z+
#
# CMath.atanh(1 + 1i) #=> (0.4023594781085251+1.0172219678978514i)
def atanh(z)
begin
if z.real? and z >= -1 and z <= 1
@@ -397,4 +440,3 @@ def handle_no_method_error # :nodoc:
module_function :handle_no_method_error

end

21 changes: 10 additions & 11 deletions lib/ruby/stdlib/fileutils.rb
Original file line number Diff line number Diff line change
@@ -156,10 +156,10 @@ def uptodate?(new, old_list)
end
module_function :uptodate?

def remove_trailing_slash(dir)
def remove_tailing_slash(dir)
dir == '/' ? dir : dir.chomp(?/)
end
private_module_function :remove_trailing_slash
private_module_function :remove_tailing_slash

#
# Options: mode noop verbose
@@ -207,7 +207,7 @@ def mkdir_p(list, options = {})
fu_output_message "mkdir -p #{options[:mode] ? ('-m %03o ' % options[:mode]) : ''}#{list.join ' '}" if options[:verbose]
return *list if options[:noop]

list.map {|path| remove_trailing_slash(path)}.each do |path|
list.map {|path| remove_tailing_slash(path)}.each do |path|
# optimize for the most common case
begin
fu_mkdir path, options[:mode]
@@ -244,7 +244,7 @@ def mkdir_p(list, options = {})
OPT_TABLE['makedirs'] = [:mode, :noop, :verbose]

def fu_mkdir(path, mode) #:nodoc:
path = remove_trailing_slash(path)
path = remove_tailing_slash(path)
if mode
Dir.mkdir path, mode
File.chmod mode, path
@@ -272,7 +272,7 @@ def rmdir(list, options = {})
return if options[:noop]
list.each do |dir|
begin
Dir.rmdir(dir = remove_trailing_slash(dir))
Dir.rmdir(dir = remove_tailing_slash(dir))
if parents
until (parent = File.dirname(dir)) == '.' or parent == dir
dir = parent
@@ -518,7 +518,7 @@ def mv(src, dest, options = {})
begin
if destent.exist?
if destent.directory?
raise Errno::EEXIST, dest
raise Errno::EEXIST, d
else
destent.remove_file if rename_cannot_overwrite_file?
end
@@ -726,15 +726,14 @@ def remove_entry_secure(path, force = false)
end
# freeze tree root
euid = Process.euid
dot_file = fullpath + "/."
File.lstat(dot_file).tap {|fstat|
unless fu_stat_identical_entry?(st, fstat)
File.open(fullpath + '/.') {|f|
unless fu_stat_identical_entry?(st, f.stat)
# symlink (TOC-to-TOU attack?)
File.unlink fullpath
return
end
File.chown euid, -1, dot_file
File.chmod 0700, dot_file
f.chown euid, -1
f.chmod 0700
unless fu_stat_identical_entry?(st, File.lstat(fullpath))
# TOC-to-TOU attack?
File.unlink fullpath
11 changes: 3 additions & 8 deletions lib/ruby/stdlib/net/ftp.rb
Original file line number Diff line number Diff line change
@@ -377,15 +377,9 @@ def sendport(host, port) # :nodoc:
end
private :sendport

# Constructs a TCPServer socket, and sends it the PORT command
#
# Returns the constructed TCPServer socket
# Constructs a TCPServer socket
def makeport # :nodoc:
sock = TCPServer.open(@sock.addr[3], 0)
port = sock.addr[1]
host = sock.addr[3]
sendport(host, port)
return sock
TCPServer.open(@sock.addr[3], 0)
end
private :makeport

@@ -421,6 +415,7 @@ def transfercmd(cmd, rest_offset = nil) # :nodoc:
else
sock = makeport
begin
sendport(sock.addr[3], sock.addr[1])
if @resume and rest_offset
resp = sendcmd("REST " + rest_offset.to_s)
if resp[0] != ?3
3 changes: 1 addition & 2 deletions lib/ruby/stdlib/net/http.rb
Original file line number Diff line number Diff line change
@@ -928,8 +928,7 @@ def connect
if @ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE
s.post_connection_check(@address)
end
# Commented out until JRuby implements OpenSSL::SSL::Session
#@ssl_session = s.session
@ssl_session = s.session
rescue => exception
D "Conn close because of connect error #{exception}"
@socket.close if @socket and not @socket.closed?
10 changes: 6 additions & 4 deletions lib/ruby/stdlib/net/http/response.rb
Original file line number Diff line number Diff line change
@@ -250,7 +250,8 @@ def inflater # :nodoc:
return yield @socket unless @decode_content
return yield @socket if self['content-range']

case self['content-encoding']
v = self['content-encoding']
case v && v.downcase
when 'deflate', 'gzip', 'x-gzip' then
self.delete 'content-encoding'

@@ -259,11 +260,11 @@ def inflater # :nodoc:
begin
yield inflate_body_io
ensure
e = $!
orig_err = $!
begin
inflate_body_io.finish
rescue
raise e
rescue => err
raise orig_err || err
end
end
when 'none', 'identity' then
@@ -358,6 +359,7 @@ def initialize socket
# Finishes the inflate stream.

def finish
return if @inflate.total_in == 0
@inflate.finish
end

8 changes: 7 additions & 1 deletion lib/ruby/stdlib/net/imap.rb
Original file line number Diff line number Diff line change
@@ -2625,7 +2625,13 @@ def body_ext_mpart
return param
end
disposition = body_fld_dsp
match(T_SPACE)

token = lookahead
if token.symbol == T_SPACE
shift_token
else
return param, disposition
end
language = body_fld_lang

token = lookahead
8 changes: 7 additions & 1 deletion lib/ruby/stdlib/time.rb
Original file line number Diff line number Diff line change
@@ -426,7 +426,13 @@ def strptime(date, format, now=self.now)
d = Date._strptime(date, format)
raise ArgumentError, "invalid strptime format - `#{format}'" unless d
if seconds = d[:seconds]
t = Time.at(seconds)
if sec_fraction = d[:sec_fraction]
usec = sec_fraction * 1000000
usec *= -1 if seconds < 0
else
usec = 0
end
t = Time.at(seconds, usec)
if zone = d[:zone]
force_zone!(t, zone)
end
Original file line number Diff line number Diff line change
@@ -79,3 +79,10 @@
- date
- bigdecimal
- pathname
:stored_commands:
:ci:
- "jruby+truffle setup"
- :test
:test: "jruby+truffle run --exclude-pattern 'jdom_engine' --require-pattern 'test/**/**/*_test.rb' -r exclude_tests -- -I test -e 'nil'"


56 changes: 53 additions & 3 deletions lib/ruby/truffle/jruby+truffle/runner.rb
Original file line number Diff line number Diff line change
@@ -81,6 +81,10 @@ class JRubyTruffleRunner
executable: ['-S', '--executable NAME', 'finds and runs an executable of a gem', assign_new_value, nil],
jexception: ['--jexception', 'print Java exceptions', assign_new_value, false]
},
stored: {
help: ['-h', '--help', 'Show this message', assign_new_value, false],
list: ['-l', '--list', 'List stored commands', assign_new_value, false]
},
clean: {
help: ['-h', '--help', 'Show this message', assign_new_value, false]
},
@@ -138,7 +142,29 @@ class JRubyTruffleRunner
TXT

HELP = { global: global_help, setup: setup_help, run: run_help, clean: clean_help }
stored_help = <<-TXT.gsub(/^ {6}/, '')
Usage: #{EXECUTABLE} [options] stored [subcommand-options] [COMMAND_NAME]
Runs stored list of bash commands. They are stored under :stored_commands key
in options. It can contain single command or an array of commands,
e.g. to define how to run CI cycle for a given gem/application on JRuby+Truffle.
Examples: #{EXECUTABLE} stored --list
#{EXECUTABLE} stored ci
Stored commands may reference each other by Symbols.
Configuration example:
:stored_commands:
:ci:
- "jruby+truffle setup"
- :test
:test: "jruby+truffle run -S rake -- test"
TXT

HELP = { global: global_help, setup: setup_help, run: run_help, clean: clean_help, stored: stored_help }
end


@@ -312,8 +338,7 @@ def subcommand_setup(rest)
end

def subcommand_run(rest)
jruby_path = Pathname("#{@options[:global][:interpreter_path]}/../..").expand_path

jruby_path = Pathname("#{@options[:global][:interpreter_path]}/../..").expand_path
ruby_options, rest = if rest.include?('--')
split = rest.index('--')
[rest[0...split], rest[(split+1)..-1]]
@@ -370,6 +395,31 @@ def subcommand_run(rest)
exit $?.exitstatus
end

def subcommand_stored(rest)
if @options[:stored][:list]
pp @options[:stored_commands]
exit
end

commands = get_stored_command rest.first

puts "executing #{commands.size} commands:"
commands.each { |cmd| print_cmd cmd, true }
puts

commands.each do |cmd|
unless execute_cmd(cmd, fail: false, print_always: true)
exit $?.exitstatus
end
end
end

def get_stored_command(name, fail: true)
result = @options.fetch(:stored_commands, {})[name.to_sym]
raise("unknown stored command: #{name}") if fail && !result
Array(result).flat_map { |c| (c.is_a? Symbol) ? get_stored_command(c) : c }
end

def subcommand_clean(rest)
FileUtils.rm_rf @options[:global][:truffle_bundle_path]
end
8 changes: 8 additions & 0 deletions test/jruby/test_big_decimal.rb
Original file line number Diff line number Diff line change
@@ -348,6 +348,14 @@ def test_GH_2650
assert_equal(BigDecimal.new("10.9", 2).to_f, 10.9)
end

# GH-3527
def test_tail_junk
b = BigDecimal.new("5-6")
assert_equal BigDecimal('5'), b
b = BigDecimal.new("100+42")
assert_equal 100, b.to_i
end

class BigDeci < BigDecimal

# MRI does not invoke initialize on 1.8./1.9

0 comments on commit 6bc47ec

Please sign in to comment.