diff --git a/core/src/main/java/org/jruby/RubyFixnum.java b/core/src/main/java/org/jruby/RubyFixnum.java index 59d5a57e219e..8099c0288d9b 100644 --- a/core/src/main/java/org/jruby/RubyFixnum.java +++ b/core/src/main/java/org/jruby/RubyFixnum.java @@ -222,6 +222,10 @@ public static RubyFixnum newFixnum(Ruby runtime, long value) { return new RubyFixnum(runtime, value); } + public static RubyFixnum newFixnum(Ruby runtime, int value) { + return newFixnum(runtime, (long) value); + } + private static boolean isInCacheRange(long value) { return value <= CACHE_OFFSET - 1 && value >= -CACHE_OFFSET; } diff --git a/core/src/main/java/org/jruby/compiler/impl/SkinnyMethodAdapter.java b/core/src/main/java/org/jruby/compiler/impl/SkinnyMethodAdapter.java index 6f354041fb7c..269549f8988a 100644 --- a/core/src/main/java/org/jruby/compiler/impl/SkinnyMethodAdapter.java +++ b/core/src/main/java/org/jruby/compiler/impl/SkinnyMethodAdapter.java @@ -206,6 +206,14 @@ public void pushInt(int value) { ldc(value); } } + + public void pushLong(long value) { + if (value == 0) { + lconst_0(); + } else { + ldc(value); + } + } public void pushBoolean(boolean bool) { if (bool) iconst_1(); else iconst_0(); @@ -564,6 +572,10 @@ public void if_icmple(Label arg0) { public void if_icmpgt(Label arg0) { getMethodVisitor().visitJumpInsn(IF_ICMPGT, arg0); } + + public void if_icmpge(Label arg0) { + getMethodVisitor().visitJumpInsn(IF_ICMPGE, arg0); + } public void if_icmplt(Label arg0) { getMethodVisitor().visitJumpInsn(IF_ICMPLT, arg0); diff --git a/core/src/main/java/org/jruby/ir/IRBuilder.java b/core/src/main/java/org/jruby/ir/IRBuilder.java index 9ccc6012ac48..90011b3ca1ce 100644 --- a/core/src/main/java/org/jruby/ir/IRBuilder.java +++ b/core/src/main/java/org/jruby/ir/IRBuilder.java @@ -1381,7 +1381,7 @@ private void buildFindPattern(Label testEnd, Variable result, Variable deconstru }); }); - Variable length = addResultInstr(new RuntimeHelperCall(temp(), ARRAY_LENGTH, new Operand[]{deconstructed})); + Variable length = addResultInstr(new RuntimeHelperCall(intTemp(), ARRAY_LENGTH, new Operand[]{deconstructed})); int fixedArgsLength = pattern.getArgs().size(); Operand argsNum = new Integer(fixedArgsLength); @@ -1391,7 +1391,7 @@ private void buildFindPattern(Label testEnd, Variable result, Variable deconstru jump(testEnd); }); - Variable limit = addResultInstr(new IntegerMathInstr(SUBTRACT, temp(), length, argsNum)); + Variable limit = addResultInstr(new IntegerMathInstr(SUBTRACT, intTemp(), length, argsNum)); Variable i = copy(new Integer(0)); for_loop(after -> addInstr(new BIntInstr(after, BIntInstr.Op.GT, i, limit)), @@ -1399,7 +1399,7 @@ private void buildFindPattern(Label testEnd, Variable result, Variable deconstru (after, bottom) -> { times(fixedArgsLength, (end_times, j) -> { Node pat = pattern.getArgs().get(j.value); - Operand deconstructIndex = addResultInstr(new IntegerMathInstr(ADD, temp(), i, new Integer(j.value))); + Operand deconstructIndex = addResultInstr(new IntegerMathInstr(ADD, intTemp(), i, new Integer(j.value))); Operand deconstructFixnum = as_fixnum(deconstructIndex); Operand test = call(temp(), deconstructed, "[]", deconstructFixnum); buildPatternMatch(result, copy(buildNil()), pat, test, false, isSinglePattern, errorString); @@ -1416,7 +1416,7 @@ private void buildFindPattern(Label testEnd, Variable result, Variable deconstru Node post = pattern.getPostRestArg(); if (post != null && !(post instanceof StarNode)) { - Operand deconstructIndex = addResultInstr(new IntegerMathInstr(ADD, createTemporaryVariable(), i, argsNum)); + Operand deconstructIndex = addResultInstr(new IntegerMathInstr(ADD, intTemp(), i, argsNum)); Operand deconstructFixnum = as_fixnum(deconstructIndex); Operand lengthFixnum = as_fixnum(length); Operand test = call(temp(), deconstructed, "[]", deconstructFixnum, lengthFixnum); @@ -1429,7 +1429,7 @@ private void buildFindPattern(Label testEnd, Variable result, Variable deconstru private void buildArrayPattern(Label testEnd, Variable result, Variable deconstructed, ArrayPatternNode pattern, Operand obj, boolean inAlteration, boolean isSinglePattern, Variable errorString) { - Variable restNum = addResultInstr(new CopyInstr(temp(), new Integer(0))); + Variable restNum = addResultInstr(new CopyInstr(intTemp(), new Integer(0))); if (pattern.hasConstant()) { Operand constant = build(pattern.getConstant()); @@ -1450,13 +1450,12 @@ private void buildArrayPattern(Label testEnd, Variable result, Variable deconstr }) ); - Operand minArgsCount = new Integer(pattern.minimumArgsNum()); - Variable length = addResultInstr(new RuntimeHelperCall(createTemporaryVariable(), ARRAY_LENGTH, new Operand[]{deconstructed})); + Variable length = addResultInstr(new RuntimeHelperCall(intTemp(), ARRAY_LENGTH, new Operand[]{deconstructed})); label("min_args_check_end", minArgsCheck -> { BIntInstr.Op compareOp = pattern.hasRestArg() ? BIntInstr.Op.GTE : BIntInstr.Op.EQ; - addInstr(new BIntInstr(minArgsCheck, compareOp, length, minArgsCount)); + addInstr(new BIntInstr(minArgsCheck, compareOp, length, new Integer(pattern.minimumArgsNum()))); fcall(errorString, buildSelf(), "sprintf", - new FrozenString("%s: %s length mismatch (given %d, expected %d)"), deconstructed, deconstructed, as_fixnum(length), as_fixnum(minArgsCount)); + new FrozenString("%s: %s length mismatch (given %d, expected %d)"), deconstructed, deconstructed, as_fixnum(length), new Fixnum(pattern.minimumArgsNum())); addInstr(new CopyInstr(result, fals())); jump(testEnd); }); @@ -1474,7 +1473,7 @@ private void buildArrayPattern(Label testEnd, Variable result, Variable deconstr } if (pattern.hasRestArg()) { - addInstr(new IntegerMathInstr(SUBTRACT, restNum, length, minArgsCount)); + addInstr(new IntegerMathInstr(SUBTRACT, restNum, length, new Integer(pattern.minimumArgsNum()))); if (pattern.isNamedRestArg()) { Variable min = copy(fix(preArgsSize)); @@ -1490,7 +1489,7 @@ private void buildArrayPattern(Label testEnd, Variable result, Variable deconstr if (postArgs != null) { for (int i = 0; i < postArgs.size(); i++) { Label matchElementCheck = getNewLabel("match_post_args_element(i)_end"); - Variable j = addResultInstr(new IntegerMathInstr(ADD, temp(), new Integer(i + preArgsSize), restNum)); + Variable j = addResultInstr(new IntegerMathInstr(ADD, intTemp(), new Integer(i + preArgsSize), restNum)); Variable k = as_fixnum(j); Variable elt = call(temp(), deconstructed, "[]", k); @@ -1596,6 +1595,10 @@ private Variable temp() { return createTemporaryVariable(); } + private Variable intTemp() { + return createIntVariable(); + } + private Operand fals() { return manager.getFalse(); } @@ -4991,7 +4994,14 @@ public Variable copy(Operand value) { } public Variable copy(Variable result, Operand value) { - return addResultInstr(new CopyInstr(result == null ? createTemporaryVariable() : result, value)); + if (result == null) { + if (value instanceof Integer || value instanceof TemporaryIntVariable) { + result = createIntVariable(); + } else { + result = createTemporaryVariable(); + } + } + return addResultInstr(new CopyInstr(result, value)); } public Operand buildZArray(Variable result) { @@ -5140,6 +5150,19 @@ private TemporaryVariable createTemporaryVariable() { } } + private TemporaryVariable createIntVariable() { + // BEGIN uses its parent builder to store any variables + if (variableBuilder != null) return variableBuilder.createIntVariable(); + + temporaryVariableIndex++; + + if (scope.getScopeType() == IRScopeType.CLOSURE) { + throw new RuntimeException("primitive int variables not supported in closure"); + } else { + return new TemporaryIntVariable(temporaryVariableIndex); + } + } + public LocalVariable getLocalVariable(RubySymbol name, int scopeDepth) { return scope.getLocalVariable(name, scopeDepth); } diff --git a/core/src/main/java/org/jruby/ir/IRManager.java b/core/src/main/java/org/jruby/ir/IRManager.java index ca787caace7c..676b69cdbc7e 100644 --- a/core/src/main/java/org/jruby/ir/IRManager.java +++ b/core/src/main/java/org/jruby/ir/IRManager.java @@ -349,6 +349,24 @@ public TemporaryLocalVariable newTemporaryLocalVariable(int index) { return tempVar; } + /** + * Temporarily provided for loading/storing a normal local as int on JVM; interpreter will still box as Integer. + * @param index + * @return + */ + public TemporaryLocalVariable newTemporaryIntVariable(int index) { + if (index >= temporaryLocalVariables.length-1) growTemporaryVariablePool(index); + + TemporaryLocalVariable tempVar = temporaryLocalVariables[index]; + + if (tempVar == null || !(tempVar instanceof TemporaryIntVariable)) { + tempVar = new TemporaryIntVariable(index); + temporaryLocalVariables[index] = tempVar; + } + + return tempVar; + } + /** * For scopes that don't require a dynamic scope we can run DCE and some other passes which cannot * be stymied by escaped bindings. diff --git a/core/src/main/java/org/jruby/ir/IRVisitor.java b/core/src/main/java/org/jruby/ir/IRVisitor.java index 2a712d0a74f5..7f429479b88c 100644 --- a/core/src/main/java/org/jruby/ir/IRVisitor.java +++ b/core/src/main/java/org/jruby/ir/IRVisitor.java @@ -37,7 +37,7 @@ private void error(Object object) { public void AttrAssignInstr(AttrAssignInstr attrassigninstr) { error(attrassigninstr); } public void BFalseInstr(BFalseInstr bfalseinstr) { error(bfalseinstr); } public void BlockGivenInstr(BlockGivenInstr blockgiveninstr) { error(blockgiveninstr); } - public void BGTEInstr(BIntInstr bneinstr) { error(bneinstr); } + public void BIntInstr(BIntInstr bIntInstr) { error(bIntInstr); } public void BNEInstr(BNEInstr bneinstr) { error(bneinstr); } public void BNilInstr(BNilInstr bnilinstr) { error(bnilinstr); } public void BreakInstr(BreakInstr breakinstr) { error(breakinstr); } @@ -204,6 +204,7 @@ private void error(Object object) { public void TemporaryLocalVariable(TemporaryLocalVariable temporarylocalvariable) { error(temporarylocalvariable); } public void TemporaryFloatVariable(TemporaryFloatVariable temporaryfloatvariable) { error(temporaryfloatvariable); } public void TemporaryFixnumVariable(TemporaryFixnumVariable temporaryfixnumvariable) { error(temporaryfixnumvariable); } + public void TemporaryIntVariable(TemporaryIntVariable temporaryintvariable) { error(temporaryintvariable); } public void TemporaryBooleanVariable(TemporaryBooleanVariable temporarybooleanvariable) { error(temporarybooleanvariable); } public void UndefinedValue(UndefinedValue undefinedvalue) { error(undefinedvalue); } public void UnexecutableNil(UnexecutableNil unexecutablenil) { error(unexecutablenil); } diff --git a/core/src/main/java/org/jruby/ir/instructions/BIntInstr.java b/core/src/main/java/org/jruby/ir/instructions/BIntInstr.java index 5cdeae53c840..9973ea30e44c 100644 --- a/core/src/main/java/org/jruby/ir/instructions/BIntInstr.java +++ b/core/src/main/java/org/jruby/ir/instructions/BIntInstr.java @@ -87,11 +87,15 @@ public int interpretAndGetNewIPC(ThreadContext context, DynamicScope currDynScop @Override public void visit(IRVisitor visitor) { - visitor.BGTEInstr(this); + visitor.BIntInstr(this); } @Override public String[] toStringNonOperandArgs() { return new String[] { op.toString() }; } + + public Op getOp() { + return op; + } } diff --git a/core/src/main/java/org/jruby/ir/interpreter/FullInterpreterContext.java b/core/src/main/java/org/jruby/ir/interpreter/FullInterpreterContext.java index fcdbd45014e9..9bb973cfde4e 100644 --- a/core/src/main/java/org/jruby/ir/interpreter/FullInterpreterContext.java +++ b/core/src/main/java/org/jruby/ir/interpreter/FullInterpreterContext.java @@ -323,6 +323,8 @@ public TemporaryLocalVariable getNewUnboxedVariable(Class type) { varType = TemporaryVariableType.FIXNUM; } else if (type == java.lang.Boolean.class) { varType = TemporaryVariableType.BOOLEAN; + } else if (type == java.lang.Integer.class) { + varType = TemporaryVariableType.INT; } else { varType = TemporaryVariableType.LOCAL; } @@ -347,6 +349,10 @@ public TemporaryLocalVariable getNewTemporaryVariable(TemporaryVariableType type case LOCAL: { return getScope().getManager().newTemporaryLocalVariable(temporaryVariableCount - 1); } + // FIXME: TemporaryIntegerVariable is being stored boxed since the primitive temp arrays are not wired up + case INT: { + return getScope().getManager().newTemporaryIntVariable(temporaryVariableCount - 1); + } } throw new RuntimeException("Invalid temporary variable being alloced in this scope: " + type); diff --git a/core/src/main/java/org/jruby/ir/operands/TemporaryVariableType.java b/core/src/main/java/org/jruby/ir/operands/TemporaryVariableType.java index a40bdda73265..ae0f81372e5a 100644 --- a/core/src/main/java/org/jruby/ir/operands/TemporaryVariableType.java +++ b/core/src/main/java/org/jruby/ir/operands/TemporaryVariableType.java @@ -5,7 +5,7 @@ * and we want to be able to quickly switch on type. */ public enum TemporaryVariableType { - LOCAL, BOOLEAN, FLOAT, FIXNUM, CLOSURE, CURRENT_MODULE; + LOCAL, BOOLEAN, FLOAT, INT, FIXNUM, CLOSURE, CURRENT_MODULE; private static final TemporaryVariableType[] VALUES = values(); diff --git a/core/src/main/java/org/jruby/ir/persistence/IRDumper.java b/core/src/main/java/org/jruby/ir/persistence/IRDumper.java index 52943d7dbd02..37f97cc28dd0 100644 --- a/core/src/main/java/org/jruby/ir/persistence/IRDumper.java +++ b/core/src/main/java/org/jruby/ir/persistence/IRDumper.java @@ -47,6 +47,7 @@ import org.jruby.ir.operands.TemporaryBooleanVariable; import org.jruby.ir.operands.TemporaryFixnumVariable; import org.jruby.ir.operands.TemporaryFloatVariable; +import org.jruby.ir.operands.TemporaryIntVariable; import org.jruby.ir.operands.TemporaryLocalVariable; import org.jruby.ir.operands.TemporaryVariable; import org.jruby.ir.operands.UnboxedBoolean; @@ -334,6 +335,7 @@ public void StandardError(StandardError standarderror) { } public void TemporaryVariable(TemporaryVariable temporaryvariable) { print(temporaryvariable.getId()); } public void TemporaryLocalVariable(TemporaryLocalVariable temporarylocalvariable) { TemporaryVariable(temporarylocalvariable); } public void TemporaryFloatVariable(TemporaryFloatVariable temporaryfloatvariable) { TemporaryVariable(temporaryfloatvariable); } + public void TemporaryIntVariable(TemporaryIntVariable temporaryintvariable) { TemporaryVariable(temporaryintvariable); } public void TemporaryFixnumVariable(TemporaryFixnumVariable temporaryfixnumvariable) { TemporaryVariable(temporaryfixnumvariable); } public void TemporaryBooleanVariable(TemporaryBooleanVariable temporarybooleanvariable) { TemporaryVariable(temporarybooleanvariable); } public void UndefinedValue(UndefinedValue undefinedvalue) { } diff --git a/core/src/main/java/org/jruby/ir/targets/JVM.java b/core/src/main/java/org/jruby/ir/targets/JVM.java index f3a8473558aa..6da1c6fe8fcc 100644 --- a/core/src/main/java/org/jruby/ir/targets/JVM.java +++ b/core/src/main/java/org/jruby/ir/targets/JVM.java @@ -108,6 +108,7 @@ public static String scriptToClass(String name) { public static final Type BOOLEAN_TYPE = Type.BOOLEAN_TYPE; public static final Type DOUBLE_TYPE = Type.DOUBLE_TYPE; public static final Type LONG_TYPE = Type.LONG_TYPE; + public static final Type INT_TYPE = Type.INT_TYPE; public static final Type BLOCK_TYPE = Type.getType(BLOCK); public static final Type THREADCONTEXT_TYPE = Type.getType(THREADCONTEXT); public static final Type STATICSCOPE_TYPE = Type.getType(STATICSCOPE); diff --git a/core/src/main/java/org/jruby/ir/targets/JVMVisitor.java b/core/src/main/java/org/jruby/ir/targets/JVMVisitor.java index 3bbbfd071185..4121a8233d12 100644 --- a/core/src/main/java/org/jruby/ir/targets/JVMVisitor.java +++ b/core/src/main/java/org/jruby/ir/targets/JVMVisitor.java @@ -44,6 +44,7 @@ import org.jruby.ir.operands.Boolean; import org.jruby.ir.operands.Float; import org.jruby.ir.operands.*; +import org.jruby.ir.operands.Integer; import org.jruby.ir.persistence.IRDumper; import org.jruby.ir.representations.BasicBlock; import org.jruby.ir.runtime.IRRuntimeHelpers; @@ -641,6 +642,7 @@ private int getJVMLocalVarIndex(Variable variable) { switch (((TemporaryLocalVariable)variable).getType()) { case FLOAT: return jvm.methodData().local(variable, JVM.DOUBLE_TYPE); case FIXNUM: return jvm.methodData().local(variable, JVM.LONG_TYPE); + case INT: return jvm.methodData().local(variable, JVM.INT_TYPE); case BOOLEAN: return jvm.methodData().local(variable, JVM.BOOLEAN_TYPE); default: return jvm.methodData().local(variable); } @@ -666,10 +668,12 @@ private void jvmStoreLocal(Variable variable) { genSetValue((LocalVariable) variable); } else if (variable instanceof TemporaryLocalVariable) { switch (((TemporaryLocalVariable)variable).getType()) { - case FLOAT: jvmAdapter().dstore(getJVMLocalVarIndex(variable)); break; - case FIXNUM: jvmAdapter().lstore(getJVMLocalVarIndex(variable)); break; - case BOOLEAN: jvmAdapter().istore(getJVMLocalVarIndex(variable)); break; - default: jvmMethod().storeLocal(getJVMLocalVarIndex(variable)); break; + case FLOAT: jvmAdapter().dstore(getJVMLocalVarIndex(variable)); break; + case FIXNUM: jvmAdapter().lstore(getJVMLocalVarIndex(variable)); break; + case INT: + case BOOLEAN: + jvmAdapter().istore(getJVMLocalVarIndex(variable)); break; + default: jvmMethod().storeLocal(getJVMLocalVarIndex(variable)); break; } } else { jvmMethod().storeLocal(getJVMLocalVarIndex(variable)); @@ -689,7 +693,9 @@ private void jvmStoreLocal(Runnable source, Variable variable) { switch (((TemporaryLocalVariable)variable).getType()) { case FLOAT: jvmAdapter().dstore(getJVMLocalVarIndex(variable)); break; case FIXNUM: jvmAdapter().lstore(getJVMLocalVarIndex(variable)); break; - case BOOLEAN: jvmAdapter().istore(getJVMLocalVarIndex(variable)); break; + case INT: + case BOOLEAN: + jvmAdapter().istore(getJVMLocalVarIndex(variable)); break; default: jvmMethod().storeLocal(getJVMLocalVarIndex(variable)); break; } } else { @@ -729,6 +735,7 @@ private void jvmLoadLocal(Variable variable) { switch (((TemporaryLocalVariable)variable).getType()) { case FLOAT: jvmAdapter().dload(getJVMLocalVarIndex(variable)); break; case FIXNUM: jvmAdapter().lload(getJVMLocalVarIndex(variable)); break; + case INT: jvmAdapter().iload(getJVMLocalVarIndex(variable)); break; case BOOLEAN: jvmAdapter().iload(getJVMLocalVarIndex(variable)); break; default: jvmMethod().loadLocal(getJVMLocalVarIndex(variable)); break; } @@ -771,6 +778,14 @@ public void ArrayDerefInstr(ArrayDerefInstr arrayderefinstr) { jvmStoreLocal(arrayderefinstr.getResult()); } + @Override + public void AsFixnumInstr(AsFixnumInstr fixnum) { + jvmMethod().getValueCompiler().pushRuntime(); + visit(fixnum.getOperand1()); + jvmAdapter().invokestatic(p(RubyFixnum.class), "newFixnum", sig(RubyFixnum.class, Ruby.class, int.class)); + jvmStoreLocal(fixnum.getResult()); + } + @Override public void AsStringInstr(AsStringInstr asstring) { jvmMethod().loadContext(); @@ -807,6 +822,32 @@ public void BlockGivenInstr(BlockGivenInstr blockGivenInstr) { jvmStoreLocal(blockGivenInstr.getResult()); } + @Override + public void BIntInstr(BIntInstr bIntInstr) { + visit(bIntInstr.getArg1()); + visit(bIntInstr.getArg2()); + switch (bIntInstr.getOp()) { + case LT: + jvmAdapter().if_icmplt(getJVMLabel(bIntInstr.getJumpTarget())); + break; + case GT: + jvmAdapter().if_icmpgt(getJVMLabel(bIntInstr.getJumpTarget())); + break; + case LTE: + jvmAdapter().if_icmple(getJVMLabel(bIntInstr.getJumpTarget())); + break; + case GTE: + jvmAdapter().if_icmpge(getJVMLabel(bIntInstr.getJumpTarget())); + break; + case EQ: + jvmAdapter().if_icmpeq(getJVMLabel(bIntInstr.getJumpTarget())); + break; + case NEQ: + jvmAdapter().if_icmpne(getJVMLabel(bIntInstr.getJumpTarget())); + break; + } + } + private void loadFloatArg(Operand arg) { if (arg instanceof Variable) { visit(arg); @@ -2343,6 +2384,12 @@ public void RuntimeHelperCall(RuntimeHelperCall runtimehelpercall) { jvmAdapter().invokestatic(p(IRRuntimeHelpers.class), "isHashEmpty", sig(IRubyObject.class, ThreadContext.class, IRubyObject.class)); jvmStoreLocal(runtimehelpercall.getResult()); break; + case ARRAY_LENGTH: + visit(runtimehelpercall.getArgs()[0]); + jvmAdapter().checkcast(p(RubyArray.class)); + jvmMethod().invokeIRHelper("arrayLength", sig(int.class, RubyArray.class)); + jvmStoreLocal(runtimehelpercall.getResult()); + break; default: throw new NotCompilableException("Unknown IR runtime helper method: " + runtimehelpercall.getHelperMethod() + "; INSTR: " + this); } @@ -2729,6 +2776,11 @@ public void Hash(Hash hash) { } } + @Override + public void Integer(Integer integer) { + jvmAdapter().pushInt(integer.value); + } + @Override public void LocalVariable(LocalVariable localvariable) { IRBytecodeAdapter m = jvmMethod(); @@ -2884,6 +2936,11 @@ public void TemporaryFixnumVariable(TemporaryFixnumVariable temporaryfixnumvaria jvmLoadLocal(temporaryfixnumvariable); } + @Override + public void TemporaryIntVariable(TemporaryIntVariable temporaryintvariable) { + jvmLoadLocal(temporaryintvariable); + } + @Override public void TemporaryBooleanVariable(TemporaryBooleanVariable temporarybooleanvariable) { jvmLoadLocal(temporarybooleanvariable);