Skip to content
Permalink

Comparing changes

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

Open a pull request

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

Commits on Nov 17, 2014

  1. Copy the full SHA
    74c5227 View commit details
  2. Copy the full SHA
    1e79efe View commit details
  3. Copy the full SHA
    7a5a93a View commit details
  4. Copy the full SHA
    5d533d4 View commit details
  5. Copy the full SHA
    dfe96d0 View commit details
  6. Clean up imports.

    headius committed Nov 17, 2014
    Copy the full SHA
    bd8e54b View commit details
  7. Copy the full SHA
    d8dd33d View commit details
4 changes: 1 addition & 3 deletions core/src/main/java/org/jruby/ir/Compiler.java
Original file line number Diff line number Diff line change
@@ -10,8 +10,6 @@
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;
@@ -89,7 +87,7 @@ public IRubyObject __file__(ThreadContext context, IRubyObject self, IRubyObject

@Override
public IRubyObject load(ThreadContext context, IRubyObject self, boolean wrap) {
DynamicScope tlbScope = scope.getTopLevelBindingScope();
DynamicScope tlbScope = scope.getToplevelScope();
if (tlbScope == null) {
context.preMethodScopeOnly(staticScope);
} else {
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
3 changes: 1 addition & 2 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 {
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);
}
}
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.
*
31 changes: 31 additions & 0 deletions core/src/main/java/org/jruby/ir/targets/IRBytecodeAdapter6.java
Original file line number Diff line number Diff line change
@@ -516,6 +516,37 @@ public void hash(int length) {
adapter.invokestatic(getClassData().clsName, "hash:" + length, incomingSig);
}

public void kwargsHash(int length) {
if (length > MAX_ARGUMENTS) 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.getfield(p(ThreadContext.class), "runtime", ci(Ruby.class));
adapter2.aload(1);
buildArrayFromLocals(adapter2, 2, length * 2);

adapter2.invokestatic(p(IRRuntimeHelpers.class), "constructHashFromArray", sig(RubyHash.class, Ruby.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(
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
10 changes: 10 additions & 0 deletions spec/compiler/general_spec.rb
Original file line number Diff line number Diff line change
@@ -927,5 +927,15 @@ 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
end
end