Skip to content

Commit

Permalink
Showing 18 changed files with 200 additions and 162 deletions.
14 changes: 10 additions & 4 deletions core/src/main/java/org/jruby/ir/Compiler.java
Original file line number Diff line number Diff line change
@@ -10,11 +10,10 @@
import org.jruby.ast.executable.Script;
import org.jruby.ast.executable.ScriptAndCode;
import org.jruby.compiler.NotCompilableException;
import org.jruby.exceptions.JumpException;
import org.jruby.exceptions.RaiseException;
import org.jruby.ir.targets.JVMVisitor;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.Block;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
@@ -88,11 +87,18 @@ public IRubyObject __file__(ThreadContext context, IRubyObject self, IRubyObject

@Override
public IRubyObject load(ThreadContext context, IRubyObject self, boolean wrap) {
Helpers.preLoadCommon(context, staticScope, false);
DynamicScope tlbScope = scope.getToplevelScope();
if (tlbScope == null) {
context.preMethodScopeOnly(staticScope);
} else {
context.preScopedBody(tlbScope);
tlbScope.growIfNeeded();
}

try {
return __file__(context, self, IRubyObject.NULL_ARRAY, Block.NULL_BLOCK);
} finally {
Helpers.postLoad(context);
context.popScope();
}
}
};
10 changes: 5 additions & 5 deletions core/src/main/java/org/jruby/ir/IRScriptBody.java
Original file line number Diff line number Diff line change
@@ -12,23 +12,23 @@
public class IRScriptBody extends IRScope {
private List<IRClosure> beginBlocks;
private List<IRClosure> endBlocks;
private DynamicScope tlbScope;
private DynamicScope toplevelScope;

public IRScriptBody(IRManager manager, String sourceName, StaticScope staticScope) {
super(manager, null, sourceName, sourceName, 0, staticScope);
this.tlbScope = null;
this.toplevelScope = null;
if (!getManager().isDryRun() && staticScope != null) {
staticScope.setIRScope(this);
staticScope.setScopeType(this.getScopeType());
}
}

public DynamicScope getTopLevelBindingScope() {
return tlbScope;
public DynamicScope getToplevelScope() {
return toplevelScope;
}

public void setTopLevelBindingScope(DynamicScope tlbScope) {
this.tlbScope = tlbScope;
this.toplevelScope = tlbScope;
}

@Override
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@
import org.jruby.ir.IRVisitor;
import org.jruby.ir.Operation;
import org.jruby.ir.operands.Operand;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.ir.transformations.inlining.CloneInfo;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.DynamicScope;
@@ -19,6 +20,10 @@ public RaiseRequiredKeywordArgumentError(String name) {
this.name = name;
}

public String getName() {
return name;
}

@Override
public Operand[] getOperands() {
return new Operand[0];
@@ -31,7 +36,7 @@ public Instr clone(CloneInfo ii) {

@Override
public Object interpret(ThreadContext context, StaticScope currScope, DynamicScope currDynScope, IRubyObject self, Object[] temp) {
throw context.runtime.newArgumentError("missing keyword: " + name);
throw IRRuntimeHelpers.newRequiredKeywordArgumentError(context, name);
}

@Override
29 changes: 16 additions & 13 deletions core/src/main/java/org/jruby/ir/interpreter/Interpreter.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.jruby.ir.interpreter;

import org.jruby.*;
import org.jruby.ast.Node;
import org.jruby.ast.RootNode;
import org.jruby.common.IRubyWarnings.ID;
import org.jruby.exceptions.RaiseException;
@@ -149,7 +148,7 @@ protected IRubyObject execute(Ruby runtime, IRScriptBody irScope, IRubyObject se
}

scope.setModule(currModule);
DynamicScope tlbScope = irScope.getTopLevelBindingScope();
DynamicScope tlbScope = irScope.getToplevelScope();
if (tlbScope == null) {
context.preMethodScopeOnly(scope);
} else {
@@ -381,11 +380,14 @@ private static void processCall(ThreadContext context, Instr instr, Operation op

private static void processBookKeepingOp(ThreadContext context, Instr instr, Operation operation,
String name, IRubyObject[] args, IRubyObject self, Block block,
RubyModule implClass, Visibility visibility) {
RubyModule implClass) {
switch(operation) {
case PUSH_FRAME:
context.preMethodFrameOnly(implClass, name, self, block);
context.setCurrentVisibility(visibility);
// Only the top-level script scope has PRIVATE visibility.
// This is already handled as part of Interpreter.execute above.
// Everything else is PUBLIC by default.
context.setCurrentVisibility(Visibility.PUBLIC);
break;
case POP_FRAME:
context.popFrame();
@@ -549,7 +551,7 @@ private static void processOtherOp(ThreadContext context, Instr instr, Operation
}

private static IRubyObject interpret(ThreadContext context, IRubyObject self,
InterpreterContext interpreterContext, Visibility visibility, RubyModule implClass,
InterpreterContext interpreterContext, RubyModule implClass,
String name, IRubyObject[] args, Block block, Block.Type blockType) {
Instr[] instrs = interpreterContext.getInstructions();
Object[] temp = interpreterContext.allocateTemporaryVariables();
@@ -561,12 +563,13 @@ private static IRubyObject interpret(ThreadContext context, IRubyObject self,
Object exception = null;
DynamicScope currDynScope = context.getCurrentScope();
StaticScope currScope = interpreterContext.getStaticScope();
IRScope scope = currScope.getIRScope();
boolean acceptsKeywordArgument = interpreterContext.receivesKeywordArguments();

// Init profiling this scope
boolean debug = IRRuntimeHelpers.isDebug();
boolean profile = IRRuntimeHelpers.inProfileMode();
//Integer scopeVersion = profile ? Profiler.initProfiling(scope) : 0;
boolean acceptsKeywordArgument = interpreterContext.receivesKeywordArguments();
Integer scopeVersion = profile ? Profiler.initProfiling(scope) : 0;

// Enter the looooop!
while (ipc < n) {
@@ -593,7 +596,7 @@ private static IRubyObject interpret(ThreadContext context, IRubyObject self,
receiveArg(context, instr, operation, args, acceptsKeywordArgument, currDynScope, temp, exception, block);
break;
case CALL_OP:
//if (profile) Profiler.updateCallSite(instr, scope, scopeVersion);
if (profile) Profiler.updateCallSite(instr, scope, scopeVersion);
processCall(context, instr, operation, currDynScope, currScope, temp, self);
break;
case RET_OP:
@@ -612,7 +615,7 @@ private static IRubyObject interpret(ThreadContext context, IRubyObject self,
currDynScope = interpreterContext.newDynamicScope(context);
context.pushScope(currDynScope);
} else {
processBookKeepingOp(context, instr, operation, name, args, self, block, implClass, visibility);
processBookKeepingOp(context, instr, operation, name, args, self, block, implClass);
}
break;
case OTHER_OP:
@@ -661,7 +664,7 @@ public static IRubyObject INTERPRET_ROOT(ThreadContext context, IRubyObject self
InterpreterContext ic, RubyModule clazz, String name) {
try {
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
return interpret(context, self, ic, null, clazz, name, IRubyObject.NULL_ARRAY, Block.NULL_BLOCK, null);
return interpret(context, self, ic, clazz, name, IRubyObject.NULL_ARRAY, Block.NULL_BLOCK, null);
} finally {
ThreadContext.popBacktrace(context);
}
@@ -671,7 +674,7 @@ public static IRubyObject INTERPRET_EVAL(ThreadContext context, IRubyObject self
InterpreterContext ic, RubyModule clazz, IRubyObject[] args, String name, Block block, Block.Type blockType) {
try {
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
return interpret(context, self, ic, null, clazz, name, args, block, blockType);
return interpret(context, self, ic, clazz, name, args, block, blockType);
} finally {
ThreadContext.popBacktrace(context);
}
@@ -681,7 +684,7 @@ public static IRubyObject INTERPRET_BLOCK(ThreadContext context, IRubyObject sel
InterpreterContext ic, IRubyObject[] args, String name, Block block, Block.Type blockType) {
try {
ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());
return interpret(context, self, ic, null, null, name, args, block, blockType);
return interpret(context, self, ic, null, name, args, block, blockType);
} finally {
ThreadContext.popBacktrace(context);
}
@@ -696,7 +699,7 @@ public static IRubyObject INTERPRET_METHOD(ThreadContext context, InterpretedIRM
try {
if (!isSynthetic) ThreadContext.pushBacktrace(context, name, ic.getFileName(), context.getLine());

return interpret(context, self, ic, method.getVisibility(), method.getImplementationClass().getMethodLocation(), name, args, block, null);
return interpret(context, self, ic, method.getImplementationClass().getMethodLocation(), name, args, block, null);
} finally {
if (!isSynthetic) ThreadContext.popBacktrace(context);
}
22 changes: 13 additions & 9 deletions core/src/main/java/org/jruby/ir/interpreter/Profiler.java
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ private static class IRCallSite {
long count;
InterpretedIRMethod tgtM;

public IRCallSite() { }
public IRCallSite() {}

public IRCallSite(IRCallSite cs) {
this.s = cs.s;
@@ -86,7 +86,7 @@ private static void analyzeProfile() {
IRCallSite cs = csp.cs;

if (cs.v != scopeVersionMap.get(cs.s).intValue()) {
// System.out.println("Skipping callsite: <" + cs.s + "," + cs.v + "> with compiled version: " + scopeVersionMap.get(cs.s));
System.out.println("Skipping callsite: <" + cs.s + "," + cs.v + "> with compiled version: " + scopeVersionMap.get(cs.s));
continue;
}

@@ -149,8 +149,8 @@ public int compare(IRCallSite a, IRCallSite b) {
// This check is arbitrary
if (i == 100 || freq > 99.0) break;

// System.out.println("Considering: " + ircs.call + " with id: " + ircs.call.callSiteId +
// " in scope " + ircs.s + " with count " + ircs.count + "; contrib " + contrib + "; freq: " + freq);
System.out.println("Considering: " + ircs.call + " with id: " + ircs.call.callSiteId +
" in scope " + ircs.s + " with count " + ircs.count + "; contrib " + contrib + "; freq: " + freq);

// Now inline here!
CallBase call = ircs.call;
@@ -166,8 +166,8 @@ public int compare(IRCallSite a, IRCallSite b) {
// Dont inline large methods -- 500 is arbitrary
// Can be null if a previously inlined method hasn't been rebuilt
if ((instrs == null) || instrs.length > 500) {
// if (instrs == null) System.out.println("no instrs!");
// else System.out.println("large method with " + instrs.length + " instrs. skipping!");
if (instrs == null) System.out.println("no instrs!");
else System.out.println("large method with " + instrs.length + " instrs. skipping!");
continue;
}

@@ -179,7 +179,7 @@ public int compare(IRCallSite a, IRCallSite b) {
Operand clArg = call.getClosureArg(null);
inlineCall = (clArg instanceof WrappedIRClosure) && (((WrappedIRClosure)clArg).getClosure() == hc);
}

/*
if (inlineCall) {
noInlining = false;
long start = new java.util.Date().getTime();
@@ -194,6 +194,7 @@ public int compare(IRCallSite a, IRCallSite b) {
} else {
//System.out.println("--no inlining--");
}
*/
}

for (IRScope x: inlinedScopes) {
@@ -277,6 +278,8 @@ public int compare(IRScope a, IRScope b) {
}

public static Integer initProfiling(IRScope scope) {
if (scope == null) return null;

/* SSS: Not being used currently
tpCount = scopeThreadPollCounts.get(scope);
if (tpCount == null) {
@@ -311,6 +314,8 @@ public static Integer initProfiling(IRScope scope) {
}

public static void updateCallSite(Instr instr, IRScope scope, Integer scopeVersion) {
if (scope == null) return;

if (instr instanceof CallBase) {
callerSite.s = scope;
callerSite.v = scopeVersion;
@@ -319,8 +324,7 @@ public static void updateCallSite(Instr instr, IRScope scope, Integer scopeVersi
}

public static void clockTick() {
// SSS: Not being used currently
// tpCount.count++;
// tpCount.count++; // SSS: Not being used currently
globalThreadPollCount++;

// 20K is arbitrary
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/ir/operands/Hash.java
Original file line number Diff line number Diff line change
@@ -92,7 +92,7 @@ public Object retrieve(ThreadContext context, IRubyObject self, StaticScope curr

if (isKWArgsHash && pairs.get(0).getKey() == Symbol.KW_REST_ARG_DUMMY) {
// Dup the rest args hash and use that as the basis for inserting the non-rest args
hash = (RubyHash)((RubyHash) pairs.get(0).getValue().retrieve(context, self, currScope, currDynScope, temp)).dup(context);
hash = ((RubyHash) pairs.get(0).getValue().retrieve(context, self, currScope, currDynScope, temp)).dupFast(context);
// Skip the first pair
it.next();
} else {
15 changes: 15 additions & 0 deletions core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java
Original file line number Diff line number Diff line change
@@ -984,6 +984,16 @@ public static RubyHash constructHashFromArray(Ruby runtime, IRubyObject[] pairs)
return hash;
}

// Used by JIT
public static RubyHash dupKwargsHashAndPopulateFromArray(ThreadContext context, RubyHash dupHash, IRubyObject[] pairs) {
Ruby runtime = context.runtime;
RubyHash hash = dupHash.dupFast(context);
for (int i = 0; i < pairs.length;) {
hash.fastASet(runtime, pairs[i++], pairs[i++], true);
}
return hash;
}

// Used by JIT
public static IRubyObject searchConst(ThreadContext context, StaticScope staticScope, String constName, boolean noPrivateConsts) {
Ruby runtime = context.getRuntime();
@@ -1268,4 +1278,9 @@ public static IRubyObject irReqdArgMultipleAsgn(ThreadContext context, RubyArray
public static IRubyObject irNot(ThreadContext context, IRubyObject obj) {
return context.runtime.newBoolean(!(obj.isTrue()));
}

@JIT
public static RaiseException newRequiredKeywordArgumentError(ThreadContext context, String name) {
return context.runtime.newArgumentError("missing keyword: " + name);
}
}
19 changes: 18 additions & 1 deletion core/src/main/java/org/jruby/ir/targets/Bootstrap.java
Original file line number Diff line number Diff line change
@@ -85,13 +85,22 @@ public static CallSite array(Lookup lookup, String name, MethodType type) {

public static CallSite hash(Lookup lookup, String name, MethodType type) {
MethodHandle handle = Binder
.from(type)
.from(lookup, type)
.collect(1, IRubyObject[].class)
.invokeStaticQuiet(LOOKUP, Bootstrap.class, "hash");
CallSite site = new ConstantCallSite(handle);
return site;
}

public static CallSite kwargsHash(Lookup lookup, String name, MethodType type) {
MethodHandle handle = Binder
.from(lookup, type)
.collect(2, IRubyObject[].class)
.invokeStaticQuiet(LOOKUP, Bootstrap.class, "kwargsHash");
CallSite site = new ConstantCallSite(handle);
return site;
}

public static CallSite ivar(Lookup lookup, String name, MethodType type) throws Throwable {
String[] names = name.split(":");
String operation = names[0];
@@ -139,6 +148,10 @@ public static Handle hash() {
return new Handle(Opcodes.H_INVOKESTATIC, p(Bootstrap.class), "hash", sig(CallSite.class, Lookup.class, String.class, MethodType.class));
}

public static Handle kwargsHash() {
return new Handle(Opcodes.H_INVOKESTATIC, p(Bootstrap.class), "kwargsHash", sig(CallSite.class, Lookup.class, String.class, MethodType.class));
}

public static Handle invokeSuper() {
return SuperInvokeSite.BOOTSTRAP;
}
@@ -264,6 +277,10 @@ public static IRubyObject hash(ThreadContext context, IRubyObject[] pairs) {
return hash;
}

public static IRubyObject kwargsHash(ThreadContext context, RubyHash hash, IRubyObject[] pairs) {
return IRRuntimeHelpers.dupKwargsHashAndPopulateFromArray(context, hash, pairs);
}

static MethodHandle buildGenericHandle(InvokeSite site, DynamicMethod method, RubyClass dispatchClass) {
SmartBinder binder;

1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/ir/targets/ClassData.java
Original file line number Diff line number Diff line change
@@ -85,5 +85,6 @@ public void popmethod() {
public AtomicInteger callSiteCount = new AtomicInteger(0);
public Set<Integer> arrayMethodsDefined = new HashSet();
public Set<Integer> hashMethodsDefined = new HashSet();
public Set<Integer> kwargsHashMethodsDefined = new HashSet();
public Set<Integer> dregexpMethodsDefined = new HashSet();
}
11 changes: 10 additions & 1 deletion core/src/main/java/org/jruby/ir/targets/IRBytecodeAdapter.java
Original file line number Diff line number Diff line change
@@ -424,12 +424,21 @@ public org.objectweb.asm.Label newLabel() {
/**
* Construct a Hash from elements on stack.
*
* Stack required: all elements of hash
* Stack required: context, all elements of hash
*
* @param length number of element pairs
*/
public abstract void hash(int length);

/**
* Construct a Hash based on keyword arguments pasesd to this method, for use in zsuper
*
* Stack required: context, kwargs hash to dup, remaining elements of hash
*
* @param length number of element pairs
*/
public abstract void kwargsHash(int length);

/**
* Perform a thread event checkpoint.
*
32 changes: 31 additions & 1 deletion core/src/main/java/org/jruby/ir/targets/IRBytecodeAdapter6.java
Original file line number Diff line number Diff line change
@@ -487,7 +487,7 @@ public void array(int length) {
}

public void hash(int length) {
if (length > MAX_ARGUMENTS) throw new NotCompilableException("literal hash has more than " + (MAX_ARGUMENTS / 2) + " pairs");
if (length > MAX_ARGUMENTS / 2) throw new NotCompilableException("literal hash has more than " + (MAX_ARGUMENTS / 2) + " pairs");

SkinnyMethodAdapter adapter2;
String incomingSig = sig(JVM.OBJECT, params(ThreadContext.class, JVM.OBJECT, length * 2));
@@ -516,6 +516,36 @@ public void hash(int length) {
adapter.invokestatic(getClassData().clsName, "hash:" + length, incomingSig);
}

public void kwargsHash(int length) {
if (length > MAX_ARGUMENTS / 2) throw new NotCompilableException("kwargs hash has more than " + (MAX_ARGUMENTS / 2) + " pairs");

SkinnyMethodAdapter adapter2;
String incomingSig = sig(JVM.OBJECT, params(ThreadContext.class, RubyHash.class, IRubyObject.class, length * 2));

if (!getClassData().kwargsHashMethodsDefined.contains(length)) {
adapter2 = new SkinnyMethodAdapter(
adapter.getClassVisitor(),
Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC,
"kwargsHash:" + length,
incomingSig,
null,
null);

adapter2.aload(0);
adapter2.aload(1);
buildArrayFromLocals(adapter2, 2, length * 2);

adapter2.invokestatic(p(IRRuntimeHelpers.class), "dupKwargsHashAndPopulateFromArray", sig(RubyHash.class, ThreadContext.class, RubyHash.class, IRubyObject[].class));
adapter2.areturn();
adapter2.end();

getClassData().hashMethodsDefined.add(length);
}

// now call it
adapter.invokestatic(getClassData().clsName, "kwargsHash:" + length, incomingSig);
}

public void checkpoint() {
loadContext();
adapter.invokevirtual(
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
import org.jruby.RubyBignum;
import org.jruby.RubyClass;
import org.jruby.RubyEncoding;
import org.jruby.RubyHash;
import org.jruby.RubyRegexp;
import org.jruby.RubyString;
import org.jruby.compiler.NotCompilableException;
@@ -247,6 +248,12 @@ public void hash(int length) {
adapter.invokedynamic("hash", sig(JVM.OBJECT, params(ThreadContext.class, JVM.OBJECT, length * 2)), Bootstrap.hash());
}

public void kwargsHash(int length) {
if (length > MAX_ARGUMENTS / 2) throw new NotCompilableException("kwargs hash has more than " + (MAX_ARGUMENTS / 2) + " pairs");

adapter.invokedynamic("kwargsHash", sig(JVM.OBJECT, params(ThreadContext.class, RubyHash.class, JVM.OBJECT, length * 2)), Bootstrap.kwargsHash());
}

public void checkpoint() {
loadContext();
adapter.invokedynamic(
49 changes: 28 additions & 21 deletions core/src/main/java/org/jruby/ir/targets/JVMVisitor.java
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@
import org.jruby.*;
import org.jruby.compiler.NotCompilableException;
import org.jruby.compiler.impl.SkinnyMethodAdapter;
import org.jruby.exceptions.RaiseException;
import org.jruby.internal.runtime.GlobalVariables;
import org.jruby.internal.runtime.methods.DynamicMethod;
import org.jruby.ir.*;
@@ -37,6 +38,7 @@

import java.lang.invoke.MethodType;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

@@ -1326,6 +1328,14 @@ public void PushBindingInstr(PushBindingInstr pushbindinginstr) {
jvmMethod().invokeVirtual(Type.getType(ThreadContext.class), Method.getMethod("void pushScope(org.jruby.runtime.DynamicScope)"));
}

@Override
public void RaiseRequiredKeywordArgumentErrorInstr(RaiseRequiredKeywordArgumentError instr) {
jvmMethod().loadContext();
jvmAdapter().ldc(instr.getName());
jvmMethod().invokeIRHelper("newRequiredKeywordArgumentError", sig(RaiseException.class, ThreadContext.class, String.class));
jvmAdapter().athrow();
}

@Override
public void PushFrameInstr(PushFrameInstr pushframeinstr) {
jvmMethod().loadContext();
@@ -1395,11 +1405,6 @@ public void PutGlobalVarInstr(PutGlobalVarInstr putglobalvarinstr) {
jvmAdapter().pop();
}

@Override
public void RaiseArgumentErrorInstr(RaiseArgumentErrorInstr raiseargumenterrorinstr) {
super.RaiseArgumentErrorInstr(raiseargumenterrorinstr);
}

@Override
public void ReceiveClosureInstr(ReceiveClosureInstr receiveclosureinstr) {
jvmMethod().loadRuntime();
@@ -1494,11 +1499,6 @@ public void ReceiveSelfInstr(ReceiveSelfInstr receiveselfinstr) {
jvmStoreLocal(receiveselfinstr.getResult());
}

@Override
public void RecordEndBlockInstr(RecordEndBlockInstr recordendblockinstr) {
super.RecordEndBlockInstr(recordendblockinstr); //To change body of overridden methods use File | Settings | File Templates.
}

@Override
public void ReqdArgMultipleAsgnInstr(ReqdArgMultipleAsgnInstr reqdargmultipleasgninstr) {
jvmMethod().loadContext();
@@ -1939,24 +1939,31 @@ public void UnboxedFloat(org.jruby.ir.operands.UnboxedFloat flote) {
jvmAdapter().ldc(flote.getValue());
}

@Override
public void GlobalVariable(GlobalVariable globalvariable) {
super.GlobalVariable(globalvariable); //To change body of overridden methods use File | Settings | File Templates.
}

@Override
public void Hash(Hash hash) {
List<KeyValuePair<Operand, Operand>> pairs = hash.getPairs();
Iterator<KeyValuePair<Operand, Operand>> iter = pairs.iterator();
boolean kwargs = hash.isKWArgsHash && pairs.get(0).getKey() == Symbol.KW_REST_ARG_DUMMY;

jvmMethod().loadContext();
for (KeyValuePair<Operand, Operand> pair: hash.getPairs()) {
if (kwargs) {
visit(pairs.get(0).getValue());
jvmAdapter().checkcast(p(RubyHash.class));

iter.next();
}

for (; iter.hasNext() ;) {
KeyValuePair<Operand, Operand> pair = iter.next();
visit(pair.getKey());
visit(pair.getValue());
}
jvmMethod().hash(hash.getPairs().size());
}

@Override
public void IRException(IRException irexception) {
super.IRException(irexception); //To change body of overridden methods use File | Settings | File Templates.
if (kwargs) {
jvmMethod().kwargsHash(pairs.size() - 1);
} else {
jvmMethod().hash(pairs.size());
}
}

@Override
2 changes: 2 additions & 0 deletions rakelib/rspec.rake
Original file line number Diff line number Diff line change
@@ -53,6 +53,8 @@ namespace :spec do
end

permute_specs "regression", compile_flags do |t|
t.rspec_opts ||= []
t.rspec_opts << '-f s'
t.pattern = 'spec/regression/**/*_spec.rb'
end

35 changes: 35 additions & 0 deletions spec/compiler/general_spec.rb
Original file line number Diff line number Diff line change
@@ -927,5 +927,40 @@ def foo(a)
expect(x).to eq 1
end
end

it "passes kwargs through zsuper correctly" do
run 'class X1; def foo(a:1, b:2); [a, b]; end; end; class X2 < X1; def foo(a:1, b:2); a = 5; super; end; end; X2.new.foo(a:3, b:4)' do |x|
expect(x).to eq [5,4]
end
end

it "raises errors for missing required keyword arguments" do
expect {run('def foo(a:); end; foo'){}}.to raise_error(ArgumentError)
end

it "passes keyrest arguments through zsuper correctly" do
run '
class C
def foo(str: "foo", num: 42, **opts)
[str, num, opts]
end
end
class D < C
def foo(str: "bar", num: 45, **opts)
super
end
end
[C.new.foo, D.new.foo, D.new.foo(str: "d", num:75, a:1, b:2)]
' do |x|

expect(x).to eq [
["foo", 42, {}],
["bar", 45, {}],
["d", 75, {a:1,b:2}]
]
end
end
end
end
Original file line number Diff line number Diff line change
@@ -31,8 +31,9 @@
# Try to force finalizers to run
java.lang.Runtime.runtime.run_finalization

# Spin for a while, hoping to make this pass
# Spin for a while and GC, hoping to make this pass
1000.times do
JRuby.gc
JRuby.runtime.fiber_executor.maximum_pool_size = 1
break if (thread_bean.thread_count - thread_count) < 10
Thread.pass
102 changes: 0 additions & 102 deletions test/jruby/test_eval_with_binding.rb

This file was deleted.

2 changes: 0 additions & 2 deletions test/mri/excludes/TestEval.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
exclude :test_define_method_toplevel, "needs investigation"
exclude :test_eval_ascii_incompatible, "needs investigation"
exclude :test_eval_location_fstring, "needs investigation"
exclude :test_eval_with_toplevel_binding, "needs investigation"
exclude :test_file_encoding, "needs investigation"
exclude :test_instance_eval_method, "needs investigation"

0 comments on commit 2517489

Please sign in to comment.