# HG changeset patch # User twisti # Date 1392789326 28800 # Node ID faa6fda7ee3635d10e1540645067a2e854c8eba8 # Parent 28f560605e77f1bed2c21e956e5d2b7b4d98a04d added Arrays.equals substitutions diff -r 28f560605e77 -r faa6fda7ee36 graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java --- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Tue Feb 18 15:04:47 2014 -0800 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Tue Feb 18 21:55:26 2014 -0800 @@ -974,8 +974,8 @@ } @Override - public void emitCharArrayEquals(Variable result, Value array1, Value array2, Value length) { - append(new AMD64CharArrayEqualsOp(this, result, array1, array2, asAllocatable(length))); + public void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length) { + append(new AMD64ArrayEqualsOp(this, kind, result, array1, array2, asAllocatable(length))); } @Override diff -r 28f560605e77 -r faa6fda7ee36 graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java --- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java Tue Feb 18 15:04:47 2014 -0800 +++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java Tue Feb 18 21:55:26 2014 -0800 @@ -734,7 +734,7 @@ } @Override - public void emitCharArrayEquals(Variable result, Value array1, Value array2, Value length) { + public void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length) { // TODO Auto-generated method stub throw GraalInternalError.unimplemented(); } diff -r 28f560605e77 -r faa6fda7ee36 graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java --- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Tue Feb 18 15:04:47 2014 -0800 +++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Tue Feb 18 21:55:26 2014 -0800 @@ -775,7 +775,7 @@ } @Override - public void emitCharArrayEquals(Variable result, Value array1, Value array2, Value length) { + public void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length) { // TODO Auto-generated method stub throw GraalInternalError.unimplemented(); } diff -r 28f560605e77 -r faa6fda7ee36 graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java --- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Tue Feb 18 15:04:47 2014 -0800 +++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Tue Feb 18 21:55:26 2014 -0800 @@ -443,7 +443,7 @@ } @Override - public void emitCharArrayEquals(Variable result, Value array1, Value array2, Value length) { + public void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length) { // TODO Auto-generated method stub throw GraalInternalError.unimplemented(); } diff -r 28f560605e77 -r faa6fda7ee36 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Tue Feb 18 15:04:47 2014 -0800 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Tue Feb 18 21:55:26 2014 -0800 @@ -1026,5 +1026,5 @@ public abstract void emitByteSwap(Variable result, Value operand); - public abstract void emitCharArrayEquals(Variable result, Value array1, Value array2, Value length); + public abstract void emitArrayEquals(Kind kind, Variable result, Value array1, Value array2, Value length); } diff -r 28f560605e77 -r faa6fda7ee36 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ArrayEqualsOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ArrayEqualsOp.java Tue Feb 18 21:55:26 2014 -0800 @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.graph.UnsafeAccess.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import java.lang.reflect.*; + +import com.oracle.graal.amd64.*; +import com.oracle.graal.amd64.AMD64.*; +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.asm.amd64.AMD64Address.Scale; +import com.oracle.graal.asm.amd64.AMD64Assembler.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; +import com.oracle.graal.nodes.spi.*; + +/** + * Emits code which compares two arrays of the same length. If the CPU supports any vector + * instructions specialized code is emitted to leverage these instructions. + */ +@Opcode("ARRAY_EQUALS") +public class AMD64ArrayEqualsOp extends AMD64LIRInstruction { + + private final Kind kind; + private final int arrayBaseOffset; + private final int arrayIndexScale; + + @Def({REG}) protected Value resultValue; + @Alive({REG}) protected Value array1Value; + @Alive({REG}) protected Value array2Value; + @Alive({REG}) protected Value lengthValue; + @Temp({REG}) protected Value temp1; + @Temp({REG}) protected Value temp2; + @Temp({REG}) protected Value temp3; + @Temp({REG}) protected Value temp4; + @Temp({REG}) protected Value vectorTemp1; + @Temp({REG}) protected Value vectorTemp2; + + public AMD64ArrayEqualsOp(LIRGeneratorTool tool, Kind kind, Value result, Value array1, Value array2, Value length) { + this.kind = kind; + + Class arrayClass = Array.newInstance(kind.toJavaClass(), 0).getClass(); + this.arrayBaseOffset = unsafe.arrayBaseOffset(arrayClass); + this.arrayIndexScale = unsafe.arrayIndexScale(arrayClass); + + this.resultValue = result; + this.array1Value = array1; + this.array2Value = array2; + this.lengthValue = length; + + // Allocate some temporaries. + this.temp1 = tool.newVariable(tool.target().wordKind); + this.temp2 = tool.newVariable(tool.target().wordKind); + this.temp3 = tool.newVariable(tool.target().wordKind); + this.temp4 = tool.newVariable(tool.target().wordKind); + + // We only need the vector temporaries if we generate SSE code. + if (supportsSSE41(tool.target())) { + this.vectorTemp1 = tool.newVariable(Kind.Double); + this.vectorTemp2 = tool.newVariable(Kind.Double); + } + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + Register result = asRegister(resultValue); + Register array1 = asRegister(temp1); + Register array2 = asRegister(temp2); + Register length = asRegister(temp3); + + Label trueLabel = new Label(); + Label falseLabel = new Label(); + Label done = new Label(); + + // Load array base addresses. + masm.leaq(array1, new AMD64Address(asRegister(array1Value), arrayBaseOffset)); + masm.leaq(array2, new AMD64Address(asRegister(array2Value), arrayBaseOffset)); + + // Get array length in bytes. + masm.imull(length, asRegister(lengthValue), arrayIndexScale); + masm.movl(result, length); // copy + + if (supportsSSE41(crb.target)) { + emitSSE41Compare(crb, masm, result, array1, array2, length, trueLabel, falseLabel); + } + + emit8ByteCompare(crb, masm, result, array1, array2, length, trueLabel, falseLabel); + emitTailCompares(masm, result, array1, array2, length, trueLabel, falseLabel); + + // Return true + masm.bind(trueLabel); + masm.movl(result, 1); + masm.jmpb(done); + + // Return false + masm.bind(falseLabel); + masm.xorl(result, result); + + // That's it + masm.bind(done); + } + + /** + * Returns if the underlying AMD64 architecture supports SSE 4.1 instructions. + * + * @param target target description of the underlying architecture + * @return true if the underlying architecture supports SSE 4.1 + */ + private static boolean supportsSSE41(TargetDescription target) { + AMD64 arch = (AMD64) target.arch; + return arch.getFeatures().contains(CPUFeature.SSE4_1); + } + + /** + * Vector size used in {@link #emitSSE41Compare}. + */ + private static final int SSE4_1_VECTOR_SIZE = 16; + + /** + * Emits code that uses SSE4.1 128-bit (16-byte) vector compares. + */ + private void emitSSE41Compare(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) { + assert supportsSSE41(crb.target); + + Register vector1 = asDoubleReg(vectorTemp1); + Register vector2 = asDoubleReg(vectorTemp2); + + Label loop = new Label(); + Label compareTail = new Label(); + + // Compare 16-byte vectors + masm.andl(result, SSE4_1_VECTOR_SIZE - 1); // tail count (in bytes) + masm.andl(length, ~(SSE4_1_VECTOR_SIZE - 1)); // vector count (in bytes) + masm.jccb(ConditionFlag.Zero, compareTail); + + masm.leaq(array1, new AMD64Address(array1, length, Scale.Times1, 0)); + masm.leaq(array2, new AMD64Address(array2, length, Scale.Times1, 0)); + masm.negq(length); + + // Align the main loop + masm.align(crb.target.wordSize * 2); + masm.bind(loop); + masm.movdqu(vector1, new AMD64Address(array1, length, Scale.Times1, 0)); + masm.movdqu(vector2, new AMD64Address(array2, length, Scale.Times1, 0)); + masm.pxor(vector1, vector2); + masm.ptest(vector1, vector1); + masm.jcc(ConditionFlag.NotZero, falseLabel); + masm.addq(length, SSE4_1_VECTOR_SIZE); + masm.jcc(ConditionFlag.NotZero, loop); + + masm.testl(result, result); + masm.jcc(ConditionFlag.Zero, trueLabel); + + /* + * Compare the remaining bytes with an unaligned memory load aligned to the end of the + * array. + */ + masm.movdqu(vector1, new AMD64Address(array1, result, Scale.Times1, -SSE4_1_VECTOR_SIZE)); + masm.movdqu(vector2, new AMD64Address(array2, result, Scale.Times1, -SSE4_1_VECTOR_SIZE)); + masm.pxor(vector1, vector2); + masm.ptest(vector1, vector1); + masm.jcc(ConditionFlag.NotZero, falseLabel); + masm.jmp(trueLabel); + + masm.bind(compareTail); + masm.movl(length, result); + } + + /** + * Vector size used in {@link #emit8ByteCompare}. + */ + private static final int VECTOR_SIZE = 8; + + /** + * Emits code that uses 8-byte vector compares. + */ + private void emit8ByteCompare(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) { + Label loop = new Label(); + Label compareTail = new Label(); + + Register temp = asRegister(temp4); + + masm.andl(result, VECTOR_SIZE - 1); // tail count (in bytes) + masm.andl(length, ~(VECTOR_SIZE - 1)); // vector count (in bytes) + masm.jccb(ConditionFlag.Zero, compareTail); + + masm.leaq(array1, new AMD64Address(array1, length, Scale.Times1, 0)); + masm.leaq(array2, new AMD64Address(array2, length, Scale.Times1, 0)); + masm.negq(length); + + // Align the main loop + masm.align(crb.target.wordSize * 2); + masm.bind(loop); + masm.movq(temp, new AMD64Address(array1, length, Scale.Times1, 0)); + masm.cmpq(temp, new AMD64Address(array2, length, Scale.Times1, 0)); + masm.jccb(ConditionFlag.NotEqual, falseLabel); + masm.addq(length, VECTOR_SIZE); + masm.jccb(ConditionFlag.NotZero, loop); + + masm.testl(result, result); + masm.jccb(ConditionFlag.Zero, trueLabel); + + /* + * Compare the remaining bytes with an unaligned memory load aligned to the end of the + * array. + */ + masm.movq(temp, new AMD64Address(array1, result, Scale.Times1, -VECTOR_SIZE)); + masm.cmpq(temp, new AMD64Address(array2, result, Scale.Times1, -VECTOR_SIZE)); + masm.jccb(ConditionFlag.NotEqual, falseLabel); + masm.jmpb(trueLabel); + + masm.bind(compareTail); + masm.movl(length, result); + } + + /** + * Emits code to compare the remaining 1 to 4 bytes. + */ + private void emitTailCompares(AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) { + Label compare2Bytes = new Label(); + Label compare1Byte = new Label(); + + Register temp = asRegister(temp4); + + if (kind.getByteCount() <= 4) { + // Compare trailing 4 bytes, if any. + masm.testl(result, 4); + masm.jccb(ConditionFlag.Zero, compare2Bytes); + masm.movl(temp, new AMD64Address(array1, 0)); + masm.cmpl(temp, new AMD64Address(array2, 0)); + masm.jccb(ConditionFlag.NotEqual, falseLabel); + + if (kind.getByteCount() <= 2) { + // Move array pointers forward. + masm.leaq(array1, new AMD64Address(array1, 4)); + masm.leaq(array2, new AMD64Address(array2, 4)); + + // Compare trailing 2 bytes, if any. + masm.bind(compare2Bytes); + masm.testl(result, 2); + masm.jccb(ConditionFlag.Zero, compare1Byte); + masm.movzwl(temp, new AMD64Address(array1, 0)); + masm.movzwl(length, new AMD64Address(array2, 0)); + masm.cmpl(temp, length); + masm.jccb(ConditionFlag.NotEqual, falseLabel); + + // The one-byte tail compare is only required for boolean and byte arrays. + if (kind.getByteCount() <= 1) { + // Move array pointers forward before we compare the last trailing byte. + masm.leaq(array1, new AMD64Address(array1, 2)); + masm.leaq(array2, new AMD64Address(array2, 2)); + + // Compare trailing byte, if any. + masm.bind(compare1Byte); + masm.testl(result, 1); + masm.jccb(ConditionFlag.Zero, trueLabel); + masm.movzbl(temp, new AMD64Address(array1, 0)); + masm.movzbl(length, new AMD64Address(array2, 0)); + masm.cmpl(temp, length); + masm.jccb(ConditionFlag.NotEqual, falseLabel); + } else { + masm.bind(compare1Byte); + } + } else { + masm.bind(compare2Bytes); + } + } + } +} diff -r 28f560605e77 -r faa6fda7ee36 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CharArrayEqualsOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CharArrayEqualsOp.java Tue Feb 18 15:04:47 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,216 +0,0 @@ -/* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.amd64; - -import static com.oracle.graal.api.code.ValueUtil.*; -import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; -import sun.misc.*; - -import com.oracle.graal.amd64.*; -import com.oracle.graal.amd64.AMD64.*; -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.*; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.asm.amd64.AMD64Address.Scale; -import com.oracle.graal.asm.amd64.AMD64Assembler.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.asm.*; -import com.oracle.graal.nodes.spi.*; - -/** - * Emits code which compares two {@code char[]}. If the CPU supports any vector instructions - * specialized code is emitted to leverage these instructions. - */ -@Opcode("CHAR_ARRAY_EQUALS") -public class AMD64CharArrayEqualsOp extends AMD64LIRInstruction { - - @Def({REG}) protected Value resultValue; - @Alive({REG}) protected Value array1Value; - @Alive({REG}) protected Value array2Value; - @Alive({REG}) protected Value lengthValue; - @Temp({REG}) protected Value temp1; - @Temp({REG}) protected Value temp2; - @Temp({REG}) protected Value temp3; - @Temp({REG}) protected Value temp4; - @Temp({REG}) protected Value vectorTemp1; - @Temp({REG}) protected Value vectorTemp2; - - public AMD64CharArrayEqualsOp(LIRGeneratorTool tool, Value result, Value array1, Value array2, Value length) { - this.resultValue = result; - this.array1Value = array1; - this.array2Value = array2; - this.lengthValue = length; - - // Allocate some temporaries. - this.temp1 = tool.newVariable(tool.target().wordKind); - this.temp2 = tool.newVariable(tool.target().wordKind); - this.temp3 = tool.newVariable(tool.target().wordKind); - this.temp4 = tool.newVariable(tool.target().wordKind); - - // We only need the vector temporaries if we generate SSE code. - if (supportsSSE41(tool.target())) { - this.vectorTemp1 = tool.newVariable(Kind.Double); - this.vectorTemp2 = tool.newVariable(Kind.Double); - } - } - - /** - * Returns if the underlying AMD64 architecture supports SSE 4.1 instructions. - * - * @param target target description of the underlying architecture - * @return true if the underlying architecture supports SSE 4.1 - */ - private static boolean supportsSSE41(TargetDescription target) { - AMD64 arch = (AMD64) target.arch; - return arch.getFeatures().contains(CPUFeature.SSE4_1); - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - Register result = asRegister(resultValue); - Register array1 = asRegister(temp1); - Register array2 = asRegister(temp2); - Register length = asRegister(temp3); - - Label trueLabel = new Label(); - Label falseLabel = new Label(); - - // Load array base addresses. - masm.leaq(array1, new AMD64Address(asRegister(array1Value), Unsafe.ARRAY_CHAR_BASE_OFFSET)); - masm.leaq(array2, new AMD64Address(asRegister(array2Value), Unsafe.ARRAY_CHAR_BASE_OFFSET)); - - masm.movq(length, asRegister(lengthValue)); - masm.shll(length, 1); // get length in bytes - masm.movl(result, length); // copy - - if (supportsSSE41(crb.target)) { - emitSSE41Compare(crb, masm, result, array1, array2, length, falseLabel, trueLabel); - // Fall-through to tail compare. - } - emit4ByteCompare(crb, masm, result, array1, array2, length, falseLabel, trueLabel); - } - - /** - * Vector size used in {@link #emit4ByteCompare}. - */ - private static final int VECTOR_SIZE = 4; - - /** - * Emits code that uses 4-byte vector compares. - */ - private void emit4ByteCompare(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label falseLabel, Label trueLabel) { - Label compareVectors = new Label(); - Label compareChar = new Label(); - Label done = new Label(); - Register temp = asRegister(temp4); - - masm.andl(length, 0xfffffffc); // vector count (in bytes) - masm.jccb(ConditionFlag.Zero, compareChar); - - masm.leaq(array1, new AMD64Address(array1, length, Scale.Times1, 0)); - masm.leaq(array2, new AMD64Address(array2, length, Scale.Times1, 0)); - masm.negq(length); - - // Align the main loop - masm.align(crb.target.wordSize * 2); - masm.bind(compareVectors); - masm.movl(temp, new AMD64Address(array1, length, Scale.Times1, 0)); - masm.cmpl(temp, new AMD64Address(array2, length, Scale.Times1, 0)); - masm.jccb(ConditionFlag.NotEqual, falseLabel); - masm.addq(length, VECTOR_SIZE); - masm.jcc(ConditionFlag.NotZero, compareVectors); - - // Compare trailing char (final 2 bytes), if any - masm.bind(compareChar); - masm.testl(result, 0x2); // tail char - masm.jccb(ConditionFlag.Zero, trueLabel); - masm.movzwl(temp, new AMD64Address(array1, 0)); - masm.movzwl(length, new AMD64Address(array2, 0)); - masm.cmpl(temp, length); - masm.jccb(ConditionFlag.NotEqual, falseLabel); - - masm.bind(trueLabel); - masm.movl(result, 1); // return true - masm.jmpb(done); - - masm.bind(falseLabel); - masm.xorl(result, result); // return false - - // That's it - masm.bind(done); - } - - /** - * Vector size used in {@link #emitSSE41Compare}. - */ - private static final int SSE4_1_VECTOR_SIZE = 16; - - /** - * Emits code that uses SSE4.1 128-bit (16-byte) vector compares. - */ - private void emitSSE41Compare(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label falseLabel, Label trueLabel) { - assert supportsSSE41(crb.target); - - Register vector1 = asDoubleReg(vectorTemp1); - Register vector2 = asDoubleReg(vectorTemp2); - - Label compareWideVectors = new Label(); - Label compareTail = new Label(); - - // Compare 16-byte vectors - masm.andl(result, 0x0000000e); // tail count (in bytes) - masm.andl(length, 0xfffffff0); // vector count (in bytes) - masm.jccb(ConditionFlag.Zero, compareTail); - - masm.leaq(array1, new AMD64Address(array1, length, Scale.Times1, 0)); - masm.leaq(array2, new AMD64Address(array2, length, Scale.Times1, 0)); - masm.negq(length); - - // Align the main loop - masm.align(crb.target.wordSize * 2); - masm.bind(compareWideVectors); - masm.movdqu(vector1, new AMD64Address(array1, length, Scale.Times1, 0)); - masm.movdqu(vector2, new AMD64Address(array2, length, Scale.Times1, 0)); - masm.pxor(vector1, vector2); - - masm.ptest(vector1, vector1); - masm.jccb(ConditionFlag.NotZero, falseLabel); - masm.addq(length, SSE4_1_VECTOR_SIZE); - masm.jcc(ConditionFlag.NotZero, compareWideVectors); - - masm.testl(result, result); - masm.jccb(ConditionFlag.Zero, trueLabel); - - masm.movdqu(vector1, new AMD64Address(array1, result, Scale.Times1, -SSE4_1_VECTOR_SIZE)); - masm.movdqu(vector2, new AMD64Address(array2, result, Scale.Times1, -SSE4_1_VECTOR_SIZE)); - masm.pxor(vector1, vector2); - - masm.ptest(vector1, vector1); - masm.jccb(ConditionFlag.NotZero, falseLabel); - masm.jmpb(trueLabel); - - masm.bind(compareTail); // length is zero - masm.movl(length, result); - } -} diff -r 28f560605e77 -r faa6fda7ee36 graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64Substitutions.java --- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64Substitutions.java Tue Feb 18 15:04:47 2014 -0800 +++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64Substitutions.java Tue Feb 18 21:55:26 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,6 +39,7 @@ public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider lowerer, Replacements replacements, TargetDescription target) { if (Intrinsify.getValue()) { + replacements.registerSubstitutions(ArraysSubstitutions.class); replacements.registerSubstitutions(StringSubstitutions.class); } } diff -r 28f560605e77 -r faa6fda7ee36 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java Tue Feb 18 21:55:26 2014 -0800 @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements.test; + +import java.lang.reflect.*; +import java.util.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.nodes.*; + +/** + * Tests {@link ArraysSubstitutions}. + */ +public class ArraysSubstitutionsTest extends MethodSubstitutionTest { + + private static Object executeVarargsSafe(InstalledCode code, Object... args) { + try { + return code.executeVarargs(args); + } catch (InvalidInstalledCodeException e) { + throw new RuntimeException(e); + } + } + + private static Object invokeSafe(Method method, Object receiver, Object... args) { + method.setAccessible(true); + try { + Object result = method.invoke(receiver, args); + return result; + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + public void testSubstitution(String testMethodName, Class intrinsicClass, Class holder, String methodName, Class[] parameterTypes, boolean optional, Object[] args1, Object[] args2) { + Method realMethod = getMethod(holder, methodName, parameterTypes); + Method testMethod = getMethod(testMethodName); + StructuredGraph graph = test(testMethodName); + + // Check to see if the resulting graph contains the expected node + StructuredGraph replacement = getReplacements().getMethodSubstitution(getMetaAccess().lookupJavaMethod(realMethod)); + if (replacement == null && !optional) { + assertInGraph(graph, intrinsicClass); + } + + // Force compilation + InstalledCode code = getCode(getMetaAccess().lookupJavaMethod(testMethod), parse(testMethod)); + assert optional || code != null; + + for (int i = 0; i < args1.length; i++) { + Object arg1 = args1[i]; + Object arg2 = args2[i]; + // Verify that the original method and the substitution produce the same value + assertEquals(invokeSafe(testMethod, null, arg1, arg2), invokeSafe(realMethod, null, arg1, arg2)); + // Verify that the generated code and the original produce the same value + assertEquals(executeVarargsSafe(code, arg1, arg2), invokeSafe(realMethod, null, arg1, arg2)); + } + } + + private static final int N = 10; + + @Test + public void testEqualsBoolean() { + Object[] args1 = new Object[N]; + Object[] args2 = new Object[N]; + int n = 0; + + // equal arrays + for (int i = 0; i < N / 2; i++, n++) { + args1[n] = new boolean[i]; + args2[n] = new boolean[i]; + } + + // non-equal arrays + for (int i = 0; i < N / 2; i++, n++) { + boolean[] a2 = new boolean[i]; + if (i > 0) { + a2[i - 1] = true; + } + args1[n] = new boolean[i]; + args2[n] = a2; + } + Class[] parameterTypes = new Class[]{boolean[].class, boolean[].class}; + testSubstitution("arraysEqualsBoolean", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); + } + + @SuppressWarnings("all") + public static boolean arraysEqualsBoolean(boolean[] a, boolean[] b) { + return Arrays.equals(a, b); + } + + @Test + public void testEqualsByte() { + Object[] args1 = new Object[N]; + Object[] args2 = new Object[N]; + int n = 0; + + // equal arrays + for (int i = 0; i < N / 2; i++, n++) { + args1[n] = new byte[i]; + args2[n] = new byte[i]; + } + + // non-equal arrays + for (int i = 0; i < N / 2; i++, n++) { + byte[] a2 = new byte[i]; + if (i > 0) { + a2[i - 1] = 1; + } + args1[n] = new byte[i]; + args2[n] = a2; + } + + Class[] parameterTypes = new Class[]{byte[].class, byte[].class}; + testSubstitution("arraysEqualsByte", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); + } + + @SuppressWarnings("all") + public static boolean arraysEqualsByte(byte[] a, byte[] b) { + return Arrays.equals(a, b); + } + + @Test + public void testEqualsChar() { + Object[] args1 = new Object[N]; + Object[] args2 = new Object[N]; + int n = 0; + + // equal arrays + for (int i = 0; i < N / 2; i++, n++) { + args1[n] = new char[i]; + args2[n] = new char[i]; + } + + // non-equal arrays + for (int i = 0; i < N / 2; i++, n++) { + char[] a2 = new char[i]; + if (i > 0) { + a2[i - 1] = 1; + } + args1[n] = new char[i]; + args2[n] = a2; + } + + Class[] parameterTypes = new Class[]{char[].class, char[].class}; + testSubstitution("arraysEqualsChar", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); + } + + @SuppressWarnings("all") + public static boolean arraysEqualsChar(char[] a, char[] b) { + return Arrays.equals(a, b); + } + + @Test + public void testEqualsShort() { + Object[] args1 = new Object[N]; + Object[] args2 = new Object[N]; + int n = 0; + + // equal arrays + for (int i = 0; i < N / 2; i++, n++) { + args1[n] = new short[i]; + args2[n] = new short[i]; + } + + // non-equal arrays + for (int i = 0; i < N / 2; i++, n++) { + short[] a2 = new short[i]; + if (i > 0) { + a2[i - 1] = 1; + } + args1[n] = new short[i]; + args2[n] = a2; + } + + Class[] parameterTypes = new Class[]{short[].class, short[].class}; + testSubstitution("arraysEqualsShort", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); + } + + @SuppressWarnings("all") + public static boolean arraysEqualsShort(short[] a, short[] b) { + return Arrays.equals(a, b); + } + + @Test + public void testEqualsInt() { + Object[] args1 = new Object[N]; + Object[] args2 = new Object[N]; + int n = 0; + + // equal arrays + for (int i = 0; i < N / 2; i++, n++) { + args1[n] = new int[i]; + args2[n] = new int[i]; + } + + // non-equal arrays + for (int i = 0; i < N / 2; i++, n++) { + int[] a2 = new int[i]; + if (i > 0) { + a2[i - 1] = 1; + } + args1[n] = new int[i]; + args2[n] = a2; + } + + Class[] parameterTypes = new Class[]{int[].class, int[].class}; + testSubstitution("arraysEqualsInt", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); + } + + @SuppressWarnings("all") + public static boolean arraysEqualsInt(int[] a, int[] b) { + return Arrays.equals(a, b); + } + + @Test + public void testEqualsLong() { + Object[] args1 = new Object[N]; + Object[] args2 = new Object[N]; + int n = 0; + + // equal arrays + for (int i = 0; i < N / 2; i++, n++) { + args1[n] = new long[i]; + args2[n] = new long[i]; + } + + // non-equal arrays + for (int i = 0; i < N / 2; i++, n++) { + long[] a2 = new long[i]; + if (i > 0) { + a2[i - 1] = 1; + } + args1[n] = new long[i]; + args2[n] = a2; + } + + Class[] parameterTypes = new Class[]{long[].class, long[].class}; + testSubstitution("arraysEqualsLong", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); + } + + @SuppressWarnings("all") + public static boolean arraysEqualsLong(long[] a, long[] b) { + return Arrays.equals(a, b); + } + + @Test + public void testEqualsFloat() { + Object[] args1 = new Object[N]; + Object[] args2 = new Object[N]; + int n = 0; + + // equal arrays + for (int i = 0; i < N / 2; i++, n++) { + args1[n] = new float[i]; + args2[n] = new float[i]; + } + + // non-equal arrays + for (int i = 0; i < N / 2; i++, n++) { + float[] a2 = new float[i]; + if (i > 0) { + a2[i - 1] = 1; + } + args1[n] = new float[i]; + args2[n] = a2; + } + + Class[] parameterTypes = new Class[]{float[].class, float[].class}; + testSubstitution("arraysEqualsFloat", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); + } + + @SuppressWarnings("all") + public static boolean arraysEqualsFloat(float[] a, float[] b) { + return Arrays.equals(a, b); + } + + @Test + public void testEqualsDouble() { + Object[] args1 = new Object[N]; + Object[] args2 = new Object[N]; + int n = 0; + + // equal arrays + for (int i = 0; i < N / 2; i++, n++) { + args1[n] = new double[i]; + args2[n] = new double[i]; + } + + // non-equal arrays + for (int i = 0; i < N / 2; i++, n++) { + double[] a2 = new double[i]; + if (i > 0) { + a2[i - 1] = 1; + } + args1[n] = new double[i]; + args2[n] = a2; + } + + Class[] parameterTypes = new Class[]{double[].class, double[].class}; + testSubstitution("arraysEqualsDouble", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); + } + + @SuppressWarnings("all") + public static boolean arraysEqualsDouble(double[] a, double[] b) { + return Arrays.equals(a, b); + } + +} diff -r 28f560605e77 -r faa6fda7ee36 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StringSubstitutionsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StringSubstitutionsTest.java Tue Feb 18 21:55:26 2014 -0800 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements.test; + +import java.lang.reflect.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.nodes.*; + +/** + * Tests {@link StringSubstitutions}. + */ +public class StringSubstitutionsTest extends MethodSubstitutionTest { + + private static Object executeVarargsSafe(InstalledCode code, Object... args) { + try { + return code.executeVarargs(args); + } catch (InvalidInstalledCodeException e) { + throw new RuntimeException(e); + } + } + + private static Object invokeSafe(Method method, Object receiver, Object... args) { + method.setAccessible(true); + try { + Object result = method.invoke(receiver, args); + return result; + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + public void testSubstitution(String testMethodName, Class intrinsicClass, Class holder, String methodName, boolean optional, Object[] args1, Object[] args2) { + Method realMethod = getMethod(holder, methodName); + Method testMethod = getMethod(testMethodName); + StructuredGraph graph = test(testMethodName); + + // Check to see if the resulting graph contains the expected node + StructuredGraph replacement = getReplacements().getMethodSubstitution(getMetaAccess().lookupJavaMethod(realMethod)); + if (replacement == null && !optional) { + assertInGraph(graph, intrinsicClass); + } + + // Force compilation + InstalledCode code = getCode(getMetaAccess().lookupJavaMethod(testMethod), parse(testMethod)); + assert optional || code != null; + + for (int i = 0; i < args1.length; i++) { + Object arg1 = args1[i]; + Object arg2 = args2[i]; + // Verify that the original method and the substitution produce the same value + assertEquals(invokeSafe(testMethod, null, arg1, arg2), invokeSafe(realMethod, arg1, arg2)); + // Verify that the generated code and the original produce the same value + assertEquals(executeVarargsSafe(code, arg1, arg2), invokeSafe(realMethod, arg1, arg2)); + } + } + + @Test + public void testEquals() { + final int n = 1000; + Object[] args1 = new Object[n]; + Object[] args2 = new Object[n]; + + // equal strings + String s1 = ""; + String s2 = ""; + for (int i = 0; i < n / 2; i++) { + args1[i] = s1; + args2[i] = s2; + s1 = s1 + "0"; + s2 = s2 + "0"; + } + + // non-equal strings + s1 = ""; + s2 = ""; + for (int i = n / 2; i < n; i++) { + args1[i] = s1; + args2[i] = s2; + s2 = s1 + "1"; + s1 = s1 + "0"; + } + + testSubstitution("stringEquals", ArrayEqualsNode.class, String.class, "equals", false, args1, args2); + } + + @SuppressWarnings("all") + public static boolean stringEquals(String a, String b) { + return a.equals(b); + } + +} diff -r 28f560605e77 -r faa6fda7ee36 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ArraysSubstitutions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ArraysSubstitutions.java Tue Feb 18 21:55:26 2014 -0800 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.replacements.nodes.*; + +/** + * Substitutions for {@link java.util.Arrays} methods. + */ +@ClassSubstitution(java.util.Arrays.class) +public class ArraysSubstitutions { + + @MethodSubstitution + public static boolean equals(boolean[] a, boolean[] a2) { + if (a == a2) { + return true; + } + if (a == null || a2 == null || a.length != a2.length) { + return false; + } + return ArrayEqualsNode.equals(a, a2, a.length); + } + + @MethodSubstitution + public static boolean equals(byte[] a, byte[] a2) { + if (a == a2) { + return true; + } + if (a == null || a2 == null || a.length != a2.length) { + return false; + } + return ArrayEqualsNode.equals(a, a2, a.length); + } + + @MethodSubstitution + public static boolean equals(char[] a, char[] a2) { + if (a == a2) { + return true; + } + if (a == null || a2 == null || a.length != a2.length) { + return false; + } + return ArrayEqualsNode.equals(a, a2, a.length); + } + + @MethodSubstitution + public static boolean equals(short[] a, short[] a2) { + if (a == a2) { + return true; + } + if (a == null || a2 == null || a.length != a2.length) { + return false; + } + return ArrayEqualsNode.equals(a, a2, a.length); + } + + @MethodSubstitution + public static boolean equals(int[] a, int[] a2) { + if (a == a2) { + return true; + } + if (a == null || a2 == null || a.length != a2.length) { + return false; + } + return ArrayEqualsNode.equals(a, a2, a.length); + } + + @MethodSubstitution + public static boolean equals(long[] a, long[] a2) { + if (a == a2) { + return true; + } + if (a == null || a2 == null || a.length != a2.length) { + return false; + } + return ArrayEqualsNode.equals(a, a2, a.length); + } + + @MethodSubstitution + public static boolean equals(float[] a, float[] a2) { + if (a == a2) { + return true; + } + if (a == null || a2 == null || a.length != a2.length) { + return false; + } + return ArrayEqualsNode.equals(a, a2, a.length); + } + + @MethodSubstitution + public static boolean equals(double[] a, double[] a2) { + if (a == a2) { + return true; + } + if (a == null || a2 == null || a.length != a2.length) { + return false; + } + return ArrayEqualsNode.equals(a, a2, a.length); + } +} diff -r 28f560605e77 -r faa6fda7ee36 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StringSubstitutions.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StringSubstitutions.java Tue Feb 18 15:04:47 2014 -0800 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StringSubstitutions.java Tue Feb 18 21:55:26 2014 -0800 @@ -66,9 +66,9 @@ return true; } - final char[] thisArray = (char[]) unsafe.getObject(thisString, valueOffset); - final char[] thatArray = (char[]) unsafe.getObject(thatString, valueOffset); + final char[] array1 = (char[]) unsafe.getObject(thisString, valueOffset); + final char[] array2 = (char[]) unsafe.getObject(thatString, valueOffset); - return CharArrayEqualsNode.equals(thisArray, thatArray, thisArray.length); + return ArrayEqualsNode.equals(array1, array2, array1.length); } } diff -r 28f560605e77 -r faa6fda7ee36 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java Tue Feb 18 21:55:26 2014 -0800 @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements.nodes; + +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.spi.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.type.*; + +/** + * Compares two arrays with the same length. + */ +public class ArrayEqualsNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { + + /** {@link Kind} of the arrays to compare. */ + private final Kind kind; + + /** One array to be tested for equality. */ + @Input private ValueNode array1; + + /** The other array to be tested for equality. */ + @Input private ValueNode array2; + + /** Length of both arrays. */ + @Input private ValueNode length; + + public ArrayEqualsNode(ValueNode array1, ValueNode array2, ValueNode length) { + super(StampFactory.forKind(Kind.Boolean)); + + assert array1.stamp().equals(array2.stamp()); + ObjectStamp stamp = (ObjectStamp) array1.stamp(); + ResolvedJavaType componentType = stamp.type().getComponentType(); + this.kind = componentType.getKind(); + + this.array1 = array1; + this.array2 = array2; + this.length = length; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (!array1.isConstant() || !array2.isConstant()) { + return this; + } + + Object a1 = array1.asConstant().asObject(); + Object a2 = array2.asConstant().asObject(); + boolean x; + switch (kind) { + case Boolean: + x = Arrays.equals((boolean[]) a1, (boolean[]) a2); + break; + case Byte: + x = Arrays.equals((byte[]) a1, (byte[]) a2); + break; + case Char: + x = Arrays.equals((char[]) a1, (char[]) a2); + break; + case Short: + x = Arrays.equals((short[]) a1, (short[]) a2); + break; + case Int: + x = Arrays.equals((int[]) a1, (int[]) a2); + break; + case Long: + x = Arrays.equals((long[]) a1, (long[]) a2); + break; + case Float: + x = Arrays.equals((float[]) a1, (float[]) a2); + break; + case Double: + x = Arrays.equals((double[]) a1, (double[]) a2); + break; + default: + throw GraalInternalError.shouldNotReachHere("unknown kind " + kind); + } + return ConstantNode.forBoolean(x, graph()); + } + + @NodeIntrinsic + public static native boolean equals(boolean[] array1, boolean[] array2, int length); + + @NodeIntrinsic + public static native boolean equals(byte[] array1, byte[] array2, int length); + + @NodeIntrinsic + public static native boolean equals(char[] array1, char[] array2, int length); + + @NodeIntrinsic + public static native boolean equals(short[] array1, short[] array2, int length); + + @NodeIntrinsic + public static native boolean equals(int[] array1, int[] array2, int length); + + @NodeIntrinsic + public static native boolean equals(long[] array1, long[] array2, int length); + + @NodeIntrinsic + public static native boolean equals(float[] array1, float[] array2, int length); + + @NodeIntrinsic + public static native boolean equals(double[] array1, double[] array2, int length); + + @Override + public void generate(LIRGenerator gen) { + Variable result = gen.newVariable(Kind.Boolean); + gen.emitArrayEquals(kind, result, gen.operand(array1), gen.operand(array2), gen.operand(length)); + gen.setResult(this, result); + } +} diff -r 28f560605e77 -r faa6fda7ee36 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/CharArrayEqualsNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/CharArrayEqualsNode.java Tue Feb 18 15:04:47 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.replacements.nodes; - -import java.util.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.spi.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.type.*; - -/** - * Compares two {@code char} arrays with the same length. - */ -public class CharArrayEqualsNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { - - @Input private ValueNode thisArray; - @Input private ValueNode thatArray; - @Input private ValueNode length; - - public CharArrayEqualsNode(ValueNode thisArray, ValueNode thatArray, ValueNode length) { - super(StampFactory.forKind(Kind.Boolean)); - this.thisArray = thisArray; - this.thatArray = thatArray; - this.length = length; - } - - @Override - public Node canonical(CanonicalizerTool tool) { - if (thisArray.isConstant() && thatArray.isConstant()) { - char[] array1 = (char[]) thisArray.asConstant().asObject(); - char[] array2 = (char[]) thatArray.asConstant().asObject(); - final boolean result = Arrays.equals(array1, array2); - return ConstantNode.forBoolean(result, graph()); - } - return this; - } - - @NodeIntrinsic - public static native boolean equals(char[] thisArray, char[] thatArray, int length); - - @Override - public void generate(LIRGenerator gen) { - Variable result = gen.newVariable(Kind.Boolean); - gen.emitCharArrayEquals(result, gen.operand(thisArray), gen.operand(thatArray), gen.operand(length)); - gen.setResult(this, result); - } -} diff -r 28f560605e77 -r faa6fda7ee36 graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java --- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java Tue Feb 18 15:04:47 2014 -0800 +++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java Tue Feb 18 21:55:26 2014 -0800 @@ -23,6 +23,7 @@ package com.oracle.graal.test; import java.lang.reflect.*; +import java.util.*; import org.junit.*; import org.junit.runner.*; @@ -53,4 +54,12 @@ throw new RuntimeException("method not found: " + methodName); } } + + protected Method getMethod(Class clazz, String methodName, Class[] parameterTypes) { + try { + return clazz.getMethod(methodName, parameterTypes); + } catch (NoSuchMethodException | SecurityException e) { + throw new RuntimeException("method not found: " + methodName + "" + Arrays.toString(parameterTypes)); + } + } }