# HG changeset patch # User Christos Kotselidis # Date 1370437918 -7200 # Node ID 5945a36ccba4c701c787221314f2cfee8db52552 # Parent ab85c49630e2e0eff5d92eb19f77028e1162137d# Parent 7779b1d5ba37beb5262dff185bc558fb1b90bd50 Merge diff -r 7779b1d5ba37 -r 5945a36ccba4 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 Wed Jun 05 14:18:35 2013 +0200 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Wed Jun 05 15:11:58 2013 +0200 @@ -59,18 +59,13 @@ import com.oracle.graal.lir.amd64.AMD64ControlFlow.SequentialSwitchOp; import com.oracle.graal.lir.amd64.AMD64ControlFlow.SwitchRangesOp; import com.oracle.graal.lir.amd64.AMD64ControlFlow.TableSwitchOp; -import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp; import com.oracle.graal.lir.amd64.AMD64Move.LeaOp; -import com.oracle.graal.lir.amd64.AMD64Move.LoadOp; import com.oracle.graal.lir.amd64.AMD64Move.MembarOp; import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp; import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp; import com.oracle.graal.lir.amd64.AMD64Move.StackLeaOp; -import com.oracle.graal.lir.amd64.AMD64Move.StoreConstantOp; -import com.oracle.graal.lir.amd64.AMD64Move.StoreOp; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.java.*; import com.oracle.graal.phases.util.*; /** @@ -215,31 +210,6 @@ } @Override - public Variable emitLoad(Kind kind, Value address, DeoptimizingNode deopting) { - AMD64AddressValue loadAddress = asAddressValue(address); - Variable result = newVariable(kind); - append(new LoadOp(kind, result, loadAddress, deopting != null ? state(deopting) : null)); - return result; - } - - @Override - public void emitStore(Kind kind, Value address, Value inputVal, DeoptimizingNode deopting) { - AMD64AddressValue storeAddress = asAddressValue(address); - LIRFrameState state = deopting != null ? state(deopting) : null; - - if (isConstant(inputVal)) { - Constant c = asConstant(inputVal); - if (canStoreConstant(c)) { - append(new StoreConstantOp(kind, storeAddress, c, state)); - return; - } - } - - Variable input = load(inputVal); - append(new StoreOp(kind, storeAddress, input, state)); - } - - @Override public Variable emitAddress(StackSlot address) { Variable result = newVariable(target().wordKind); append(new StackLeaOp(result, address)); @@ -882,34 +852,6 @@ } @Override - public void visitCompareAndSwap(CompareAndSwapNode node) { - Kind kind = node.newValue().kind(); - assert kind == node.expected().kind(); - - Value expected = loadNonConst(operand(node.expected())); - Variable newValue = load(operand(node.newValue())); - - AMD64AddressValue address; - int displacement = node.displacement(); - Value index = operand(node.offset()); - if (isConstant(index) && NumUtil.isInt(asConstant(index).asLong() + displacement)) { - assert !runtime.needsDataPatch(asConstant(index)); - displacement += (int) asConstant(index).asLong(); - address = new AMD64AddressValue(kind, load(operand(node.object())), displacement); - } else { - address = new AMD64AddressValue(kind, load(operand(node.object())), load(index), Scale.Times1, displacement); - } - - RegisterValue rax = AMD64.rax.asValue(kind); - emitMove(rax, expected); - append(new CompareAndSwapOp(rax, address, rax, newValue)); - - Variable result = newVariable(node.kind()); - append(new CondMoveOp(result, Condition.EQ, load(Constant.TRUE), Constant.FALSE)); - setResult(node, result); - } - - @Override public void visitBreakpointNode(BreakpointNode node) { JavaType[] sig = new JavaType[node.arguments().size()]; for (int i = 0; i < sig.length; i++) { diff -r 7779b1d5ba37 -r 5945a36ccba4 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Wed Jun 05 14:18:35 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Wed Jun 05 15:11:58 2013 +0200 @@ -45,9 +45,18 @@ import com.oracle.graal.lir.StandardOp.ParametersOp; import com.oracle.graal.lir.StandardOp.PlaceholderOp; import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp; +import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapCompressedOp; import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp; +import com.oracle.graal.lir.amd64.AMD64Move.LoadCompressedOop; +import com.oracle.graal.lir.amd64.AMD64Move.LoadOp; import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp; +import com.oracle.graal.lir.amd64.AMD64Move.StoreCompressedOop; +import com.oracle.graal.lir.amd64.AMD64Move.StoreConstantOp; +import com.oracle.graal.lir.amd64.AMD64Move.StoreOp; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; /** @@ -390,4 +399,78 @@ op.savedRbp = savedRbp; } } + + private static boolean isCompressCandidate(DeoptimizingNode access) { + return access != null && ((HeapAccess) access).compress(); + } + + @Override + public Variable emitLoad(Kind kind, Value address, DeoptimizingNode access) { + AMD64AddressValue loadAddress = asAddressValue(address); + Variable result = newVariable(kind); + assert access == null || access instanceof HeapAccess; + if (runtime().config.useCompressedOops && isCompressCandidate(access)) { + assert kind == Kind.Object; + Variable scratch = newVariable(Kind.Long); + append(new LoadCompressedOop(kind, result, scratch, loadAddress, access != null ? state(access) : null, runtime().config.narrowOopBase, runtime().config.narrowOopShift, + runtime().config.logMinObjAlignment)); + } else { + append(new LoadOp(kind, result, loadAddress, access != null ? state(access) : null)); + } + return result; + } + + @Override + public void emitStore(Kind kind, Value address, Value inputVal, DeoptimizingNode access) { + AMD64AddressValue storeAddress = asAddressValue(address); + LIRFrameState state = access != null ? state(access) : null; + if (isConstant(inputVal)) { + Constant c = asConstant(inputVal); + if (canStoreConstant(c)) { + append(new StoreConstantOp(kind, storeAddress, c, state, runtime().config.useCompressedOops && isCompressCandidate(access))); + return; + } + } + Variable input = load(inputVal); + if (runtime().config.useCompressedOops && isCompressCandidate(access)) { + assert kind == Kind.Object; + Variable scratch = newVariable(Kind.Long); + append(new StoreCompressedOop(kind, storeAddress, input, scratch, state, runtime().config.narrowOopBase, runtime().config.narrowOopShift, runtime().config.logMinObjAlignment)); + } else { + append(new StoreOp(kind, storeAddress, input, state)); + } + } + + @Override + public void visitCompareAndSwap(CompareAndSwapNode node) { + Kind kind = node.newValue().kind(); + assert kind == node.expected().kind(); + + Value expected = loadNonConst(operand(node.expected())); + Variable newValue = load(operand(node.newValue())); + + AMD64AddressValue address; + int displacement = node.displacement(); + Value index = operand(node.offset()); + if (isConstant(index) && NumUtil.isInt(asConstant(index).asLong() + displacement)) { + assert !runtime.needsDataPatch(asConstant(index)); + displacement += (int) asConstant(index).asLong(); + address = new AMD64AddressValue(kind, load(operand(node.object())), displacement); + } else { + address = new AMD64AddressValue(kind, load(operand(node.object())), load(index), Scale.Times1, displacement); + } + + RegisterValue raxRes = AMD64.rax.asValue(kind); + emitMove(raxRes, expected); + if (runtime().config.useCompressedOops && node.compress()) { + assert kind == Kind.Object; + Variable scratch = newVariable(Kind.Long); + append(new CompareAndSwapCompressedOp(raxRes, address, raxRes, newValue, scratch, runtime().config.narrowOopBase, runtime().config.narrowOopShift, runtime().config.logMinObjAlignment)); + } else { + append(new CompareAndSwapOp(raxRes, address, raxRes, newValue)); + } + Variable result = newVariable(node.kind()); + append(new CondMoveOp(result, Condition.EQ, load(Constant.TRUE), Constant.FALSE)); + setResult(node, result); + } } diff -r 7779b1d5ba37 -r 5945a36ccba4 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java Wed Jun 05 14:18:35 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java Wed Jun 05 15:11:58 2013 +0200 @@ -38,7 +38,7 @@ private final Architecture architecture; - private final Register[] allocatable = initAllocatable(); + private final Register[] allocatable; private final HashMap categorized = new HashMap<>(); @@ -86,25 +86,34 @@ throw new IllegalArgumentException("register " + name + " is not allocatable"); } - private static Register[] initAllocatable() { + private static Register[] initAllocatable(boolean reserveForHeapBase) { + Register[] registers = null; // @formatter:off - Register[] allocatable = { + if (reserveForHeapBase) { + registers = new Register[] { + rax, rbx, rcx, rdx, /*rsp,*/ rbp, rsi, rdi, r8, r9, r10, r11, /*r12,*/ r13, r14, /*r15, */ + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, + xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 + }; + } else { + registers = new Register[] { rax, rbx, rcx, rdx, /*rsp,*/ rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, /*r15, */ xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 - }; - // @formatter:on + }; + } + // @formatter:on if (RegisterPressure.getValue() != null) { String[] names = RegisterPressure.getValue().split(","); Register[] regs = new Register[names.length]; for (int i = 0; i < names.length; i++) { - regs[i] = findRegister(names[i], allocatable); + regs[i] = findRegister(names[i], registers); } return regs; } - return allocatable; + return registers; } public AMD64HotSpotRegisterConfig(Architecture architecture, HotSpotVMConfig config) { @@ -119,6 +128,7 @@ } csl = null; + allocatable = initAllocatable(config.useCompressedOops); attributesMap = RegisterAttributes.createMap(this, AMD64.allRegisters); } diff -r 7779b1d5ba37 -r 5945a36ccba4 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompressedOopTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompressedOopTest.java Wed Jun 05 15:11:58 2013 +0200 @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2013, 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.hotspot.test; + +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.atomic.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.hotspot.meta.*; + +/** + * The following tests perform object/array equality and assignments in various ways. The selected + * cases have been the problematic ones while implementing the Compressed Oops support. + */ + +public class CompressedOopTest extends GraalCompilerTest { + + private final MetaAccessProvider metaAccessProvider; + Object[] argsToBind; + + public CompressedOopTest() { + this.metaAccessProvider = Graal.getRequiredCapability(MetaAccessProvider.class); + } + + @Test + public void test() throws NoSuchMethodException, SecurityException, InvalidInstalledCodeException { + final Method fooMethod = CompressedOopTest.class.getMethod("fieldTest", Object.class, Object.class, Object.class); + final HotSpotResolvedJavaMethod fooJavaMethod = (HotSpotResolvedJavaMethod) metaAccessProvider.lookupJavaMethod(fooMethod); + final HotSpotInstalledCode fooCode = (HotSpotInstalledCode) getCode(fooJavaMethod, parse(fooMethod)); + argsToBind = new Object[]{fooCode}; + final Method benchmarkMethod = CompressedOopTest.class.getMethod("benchmark", HotSpotInstalledCode.class, Object.class, Object.class, Object.class); + final ResolvedJavaMethod benchmarkJavaMethod = metaAccessProvider.lookupJavaMethod(benchmarkMethod); + final HotSpotInstalledCode installedBenchmarkCode = (HotSpotInstalledCode) getCode(benchmarkJavaMethod, parse(benchmarkMethod)); + Container c1 = new Container(); + Assert.assertEquals(c1.b, installedBenchmarkCode.executeVarargs(argsToBind[0], c1, c1, c1)); + } + + @Test + public void test1() throws NoSuchMethodException, SecurityException, InvalidInstalledCodeException { + final Method fooMethod = CompressedOopTest.class.getMethod("arrayTest", Object.class, Object.class, Object.class); + final HotSpotResolvedJavaMethod fooJavaMethod = (HotSpotResolvedJavaMethod) metaAccessProvider.lookupJavaMethod(fooMethod); + final HotSpotInstalledCode fooCode = (HotSpotInstalledCode) getCode(fooJavaMethod, parse(fooMethod)); + argsToBind = new Object[]{fooCode}; + final Method benchmarkMethod = CompressedOopTest.class.getMethod("benchmark", HotSpotInstalledCode.class, Object.class, Object.class, Object.class); + final ResolvedJavaMethod benchmarkJavaMethod = metaAccessProvider.lookupJavaMethod(benchmarkMethod); + final HotSpotInstalledCode installedBenchmarkCode = (HotSpotInstalledCode) getCode(benchmarkJavaMethod, parse(benchmarkMethod)); + ArrayContainer ac = new ArrayContainer(); + Assert.assertEquals(ac.a[9], installedBenchmarkCode.executeVarargs(argsToBind[0], ac.a, 0, 9)); + Assert.assertEquals(ac.a[8], installedBenchmarkCode.executeVarargs(argsToBind[0], ac.a, 1, 8)); + Assert.assertEquals(ac.a[7], installedBenchmarkCode.executeVarargs(argsToBind[0], ac.a, 2, 7)); + Assert.assertEquals(ac.a[6], installedBenchmarkCode.executeVarargs(argsToBind[0], ac.a, 3, 6)); + Assert.assertEquals(ac.a[5], installedBenchmarkCode.executeVarargs(argsToBind[0], ac.a, 4, 5)); + Assert.assertEquals(ac.a[4], installedBenchmarkCode.executeVarargs(argsToBind[0], ac.a, 5, 4)); + Assert.assertEquals(ac.a[3], installedBenchmarkCode.executeVarargs(argsToBind[0], ac.a, 6, 3)); + Assert.assertEquals(ac.a[2], installedBenchmarkCode.executeVarargs(argsToBind[0], ac.a, 7, 2)); + Assert.assertEquals(ac.a[1], installedBenchmarkCode.executeVarargs(argsToBind[0], ac.a, 8, 1)); + Assert.assertEquals(ac.a[0], installedBenchmarkCode.executeVarargs(argsToBind[0], ac.a, 9, 0)); + } + + @Test + public void test2() throws NoSuchMethodException, SecurityException, InvalidInstalledCodeException { + final Method fooMethod = CompressedOopTest.class.getMethod("arrayCopyTest", Object.class, Object.class, Object.class); + final HotSpotResolvedJavaMethod fooJavaMethod = (HotSpotResolvedJavaMethod) metaAccessProvider.lookupJavaMethod(fooMethod); + final HotSpotInstalledCode fooCode = (HotSpotInstalledCode) getCode(fooJavaMethod, parse(fooMethod)); + argsToBind = new Object[]{fooCode}; + ArrayContainer source = new ArrayContainer(); + ArrayContainer destination = new ArrayContainer(); + Assert.assertEquals(source.a.length, destination.a.length); + Assert.assertFalse(Arrays.equals(source.a, destination.a)); + fooCode.execute(source.a, destination.a, source.a); + Assert.assertArrayEquals(source.a, destination.a); + } + + @Test + public void test3() throws NoSuchMethodException, SecurityException, InvalidInstalledCodeException { + final Method fooMethod = CompressedOopTest.class.getMethod("compareAndSwapTest", Object.class, Object.class, Object.class); + final HotSpotResolvedJavaMethod fooJavaMethod = (HotSpotResolvedJavaMethod) metaAccessProvider.lookupJavaMethod(fooMethod); + final HotSpotInstalledCode fooCode = (HotSpotInstalledCode) getCode(fooJavaMethod, parse(fooMethod)); + argsToBind = new Object[]{fooCode}; + Object initial = new Object(); + Object replacement = new Object(); + AtomicReference cas = new AtomicReference<>(); + Assert.assertEquals(cas.get(), null); + fooCode.execute(cas, null, initial); + Assert.assertEquals(cas.get(), initial); + fooCode.execute(cas, initial, replacement); + Assert.assertEquals(cas.get(), replacement); + } + + @Test + public void test4() throws NoSuchMethodException, SecurityException, InvalidInstalledCodeException { + final Method fooMethod = CompressedOopTest.class.getMethod("charArrayCopyTest", Object.class, Object.class, Object.class); + final HotSpotResolvedJavaMethod fooJavaMethod = (HotSpotResolvedJavaMethod) metaAccessProvider.lookupJavaMethod(fooMethod); + final HotSpotInstalledCode fooCode = (HotSpotInstalledCode) getCode(fooJavaMethod, parse(fooMethod)); + argsToBind = new Object[]{fooCode}; + StringContainer1 source1 = new StringContainer1(); + StringContainer2 source2 = new StringContainer2(); + char[] result = new char[source1.value.length + source2.value.length]; + fooCode.execute(source1.value, source2.value, result); + Assert.assertArrayEquals(new char[]{'T', 'e', 's', 't', ' ', 'S', 't', 'r', 'i', 'n', 'g'}, result); + } + + @Test + public void test5() throws NoSuchMethodException, SecurityException, InvalidInstalledCodeException { + final Method fooMethod = CompressedOopTest.class.getMethod("charContainerArrayCopyTest", Object.class, Object.class, Object.class); + final HotSpotResolvedJavaMethod fooJavaMethod = (HotSpotResolvedJavaMethod) metaAccessProvider.lookupJavaMethod(fooMethod); + final HotSpotInstalledCode fooCode = (HotSpotInstalledCode) getCode(fooJavaMethod, parse(fooMethod)); + argsToBind = new Object[]{fooCode}; + StringContainer1 source1 = new StringContainer1(); + StringContainer2 source2 = new StringContainer2(); + char[] result = new char[source1.value.length + source2.value.length]; + fooCode.execute(source1, source2, result); + Assert.assertArrayEquals(new char[]{'T', 'e', 's', 't', ' ', 'S', 't', 'r', 'i', 'n', 'g'}, result); + } + + @Test + public void test6() throws NoSuchMethodException, SecurityException, InvalidInstalledCodeException { + final Method fooMethod = CompressedOopTest.class.getMethod("stringCopyTest", Object.class, Object.class, Object.class); + final HotSpotResolvedJavaMethod fooJavaMethod = (HotSpotResolvedJavaMethod) metaAccessProvider.lookupJavaMethod(fooMethod); + final HotSpotInstalledCode fooCode = (HotSpotInstalledCode) getCode(fooJavaMethod, parse(fooMethod)); + argsToBind = new Object[]{fooCode}; + String a = new String("Test "); + String b = new String("String"); + String c = (String) fooCode.execute(a, b, null); + Assert.assertTrue(c.equals("Test String")); + } + + @Test + public void test7() throws NoSuchMethodException, SecurityException, InvalidInstalledCodeException { + final Method fooMethod = CompressedOopTest.class.getMethod("queueTest", Object.class, Object.class, Object.class); + final HotSpotResolvedJavaMethod fooJavaMethod = (HotSpotResolvedJavaMethod) metaAccessProvider.lookupJavaMethod(fooMethod); + final HotSpotInstalledCode fooCode = (HotSpotInstalledCode) getCode(fooJavaMethod, parse(fooMethod)); + argsToBind = new Object[]{fooCode}; + ArrayDeque q = new ArrayDeque<>(); + Object[] objects = new Object[512]; + for (int i = 0; i < objects.length; i++) { + objects[i] = new Object(); + } + + int j = 0; + while (j < objects.length) { + fooCode.execute(q, objects[j], null); + j++; + } + + System.gc(); + Assert.assertTrue(q.size() == objects.length); + Assert.assertTrue(!q.isEmpty()); + + j = 0; + while (j < objects.length) { + Assert.assertTrue(objects[j] == q.remove()); + j++; + } + + Assert.assertTrue(q.size() == 0); + Assert.assertTrue(q.isEmpty()); + } + + @Test + public void test8() throws NoSuchMethodException, SecurityException, InvalidInstalledCodeException { + final Method fooMethod = CompressedOopTest.class.getMethod("unmodListTest", Object.class, Object.class, Object.class); + final HotSpotResolvedJavaMethod fooJavaMethod = (HotSpotResolvedJavaMethod) metaAccessProvider.lookupJavaMethod(fooMethod); + final HotSpotInstalledCode fooCode = (HotSpotInstalledCode) getCode(fooJavaMethod, parse(fooMethod)); + argsToBind = new Object[]{fooCode}; + List list = new ArrayList<>(); + for (int i = 0; i < 512; i++) { + list.add(new Object()); + } + + Object[] array = (Object[]) fooCode.execute(list, null, null); + Assert.assertTrue(list.size() == array.length); + int i = 0; + for (Object obj : list) { + Assert.assertTrue(obj == array[i]); + i++; + } + } + + @Test + public void test9() throws NoSuchMethodException, SecurityException, InvalidInstalledCodeException { + final Method fooMethod = CompressedOopTest.class.getMethod("unmodListTest", Object.class, Object.class, Object.class); + final HotSpotResolvedJavaMethod fooJavaMethod = (HotSpotResolvedJavaMethod) metaAccessProvider.lookupJavaMethod(fooMethod); + final HotSpotInstalledCode fooCode = (HotSpotInstalledCode) getCode(fooJavaMethod, parse(fooMethod)); + argsToBind = new Object[]{fooCode}; + List list = new ArrayList<>(); + Object[] array = (Object[]) fooCode.execute(list, null, null); + Assert.assertTrue(list.size() == array.length); + } + + public void test10() throws NoSuchMethodException, SecurityException, InvalidInstalledCodeException { + final Method fooMethod = CompressedOopTest.class.getMethod("constantTest", Object.class, Object.class, Object.class); + final HotSpotResolvedJavaMethod fooJavaMethod = (HotSpotResolvedJavaMethod) metaAccessProvider.lookupJavaMethod(fooMethod); + final HotSpotInstalledCode fooCode = (HotSpotInstalledCode) getCode(fooJavaMethod, parse(fooMethod)); + argsToBind = new Object[]{fooCode}; + Container c = new Container(); + Assert.assertFalse((boolean) fooCode.execute(c, null, null)); + } + + @Test + public void test11() throws NoSuchMethodException, SecurityException, InvalidInstalledCodeException { + final Method fooMethod = CompressedOopTest.class.getMethod("stringEqualsTest", String.class, String.class, Object.class); + final HotSpotResolvedJavaMethod fooJavaMethod = (HotSpotResolvedJavaMethod) metaAccessProvider.lookupJavaMethod(fooMethod); + final HotSpotInstalledCode fooCode = (HotSpotInstalledCode) getCode(fooJavaMethod, parse(fooMethod)); + argsToBind = new Object[]{fooCode}; + String s1 = new String("Test"); + String s2 = new String("Test"); + boolean result = ((Boolean) (fooCode.execute(s1, s2, null))).booleanValue(); + Assert.assertTrue(result); + } + + @Test + public void test12() throws NoSuchMethodException, SecurityException, InvalidInstalledCodeException { + final Method fooMethod = CompressedOopTest.class.getMethod("stringConstantEqualsTest", String.class, String.class, Object.class); + final HotSpotResolvedJavaMethod fooJavaMethod = (HotSpotResolvedJavaMethod) metaAccessProvider.lookupJavaMethod(fooMethod); + final HotSpotInstalledCode fooCode = (HotSpotInstalledCode) getCode(fooJavaMethod, parse(fooMethod)); + argsToBind = new Object[]{fooCode}; + String s1 = new String("Test"); + boolean result = ((Boolean) (fooCode.execute(s1, null, null))).booleanValue(); + Assert.assertTrue(result); + } + + public static Object benchmark(HotSpotInstalledCode code, Object o1, Object o2, Object o3) throws InvalidInstalledCodeException { + return code.execute(o1, o2, o3); + } + + public static Object fieldTest(Object c1, @SuppressWarnings("unused") Object c2, @SuppressWarnings("unused") Object c3) { + ((Container) c1).a = ((Container) c1).b; + return ((Container) c1).a; + } + + public static Object arrayTest(Object c1, Object c2, Object c3) { + Object[] array = (Object[]) c1; + int initialIndex = ((Integer) c2).intValue(); + int replacingIndex = ((Integer) c3).intValue(); + array[initialIndex] = array[replacingIndex]; + return array[initialIndex]; + } + + public static void arrayCopyTest(Object c1, Object c2, @SuppressWarnings("unused") Object c3) { + Object[] source = (Object[]) c1; + Object[] destination = (Object[]) c2; + System.arraycopy(source, 0, destination, 0, source.length); + } + + public static String stringCopyTest(Object c1, Object c2, @SuppressWarnings("unused") Object c3) { + String source = (String) c1; + String destination = (String) c2; + return source + destination; + } + + public static char[] charArrayCopyTest(Object c1, Object c2, Object c3) { + char[] source1 = (char[]) c1; + char[] source2 = (char[]) c2; + char[] result = (char[]) c3; + + for (int i = 0; i < source1.length; i++) { + result[i] = source1[i]; + } + + for (int i = 0; i < source2.length; i++) { + result[source1.length + i] = source2[i]; + } + return result; + } + + public static char[] charContainerArrayCopyTest(Object c1, Object c2, Object c3) { + char[] source1 = ((StringContainer1) c1).value; + char[] source2 = ((StringContainer2) c2).value; + char[] result = (char[]) c3; + + for (int i = 0; i < source1.length; i++) { + result[i] = source1[i]; + } + + for (int i = 0; i < source2.length; i++) { + result[source1.length + i] = source2[i]; + } + return result; + } + + public static void compareAndSwapTest(Object c1, Object c2, Object c3) { + @SuppressWarnings("unchecked") + AtomicReference cas = (AtomicReference) c1; + cas.compareAndSet(c2, c3); + } + + @SuppressWarnings("unchecked") + public static HashMap hashMapCloneTest(Object c1, @SuppressWarnings("unused") Object c2, @SuppressWarnings("unused") Object c3) { + HashMap map = (HashMap) c1; + return (HashMap) map.clone(); + } + + @SuppressWarnings("unchecked") + public static void hashMapCopyTest(Object c1, Object c2, @SuppressWarnings("unused") Object c3) { + HashMap map = (HashMap) c1; + HashMap map1 = (HashMap) c2; + map.clear(); + map.putAll(map1); + } + + @SuppressWarnings("unchecked") + public static void queueTest(Object c1, Object c2, @SuppressWarnings("unused") Object c3) { + ArrayDeque queue = (ArrayDeque) c1; + queue.add(c2); + } + + @SuppressWarnings("unchecked") + public static Object[] unmodListTest(Object c1, @SuppressWarnings("unused") Object c2, @SuppressWarnings("unused") Object c3) { + List queue = (ArrayList) c1; + Object[] result = Collections.unmodifiableCollection(queue).toArray(new Object[queue.size()]); + return result; + } + + public static Boolean constantTest(Object c1, @SuppressWarnings("unused") Object c2, @SuppressWarnings("unused") Object c3) { + ConstantContainer container = (ConstantContainer) c1; + return container.a.equals(container.b); + } + + public static Boolean stringEqualsTest(String c1, String c2, @SuppressWarnings("unused") Object c3) { + return c1.equals(c2); + } + + public static Boolean stringConstantEqualsTest(String c1, @SuppressWarnings("unused") String c2, @SuppressWarnings("unused") Object c3) { + return "Test".equals(c1); + } + +} + +class Container { + + public Object a = new Object(); + public Object b = new Object(); +} + +class ArrayContainer { + + public Object[] a = new Object[10]; + + public ArrayContainer() { + for (int i = 0; i < 10; i++) { + a[i] = new Object(); + } + } +} + +class HashMapContainer { + + public HashMap a = new HashMap<>(); + + public HashMapContainer() { + for (int i = 0; i < 10; i++) { + a.put(new Object(), new Object()); + } + } +} + +class StringContainer1 { + + public char[] value = new char[5]; + + public StringContainer1() { + value[0] = 'T'; + value[1] = 'e'; + value[2] = 's'; + value[3] = 't'; + value[4] = ' '; + + } +} + +class StringContainer2 { + + public char[] value = new char[6]; + + public StringContainer2() { + value[0] = 'S'; + value[1] = 't'; + value[2] = 'r'; + value[3] = 'i'; + value[4] = 'n'; + value[5] = 'g'; + } +} + +class ConstantContainer { + + public final Object a = new Object(); + public final Object b = new Object(); + + public ConstantContainer() { + + } +} diff -r 7779b1d5ba37 -r 5945a36ccba4 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Wed Jun 05 14:18:35 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Wed Jun 05 15:11:58 2013 +0200 @@ -50,6 +50,13 @@ public boolean useAESIntrinsics; public boolean useG1GC; + // Compressed Oops related values. + public boolean useCompressedOops; + public boolean useCompressedKlassPointers; + public long narrowOopBase; + public int narrowOopShift; + public int logMinObjAlignment; + // CPU capabilities public int useSSE; public int useAVX; diff -r 7779b1d5ba37 -r 5945a36ccba4 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Wed Jun 05 14:18:35 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Wed Jun 05 15:11:58 2013 +0200 @@ -529,7 +529,8 @@ HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field(); ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : loadField.object(); assert loadField.kind() != Kind.Illegal; - ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field), loadField.stamp(), WriteBarrierType.NONE, false)); + ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field), loadField.stamp(), WriteBarrierType.NONE, + (loadField.kind() == Kind.Object && !field.getName().equals("classMirrorOffset")))); tool.createNullCheckGuard(memoryRead, object); graph.replaceFixedWithFixed(loadField, memoryRead); @@ -545,7 +546,7 @@ HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field(); ValueNode object = storeField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : storeField.object(); WriteBarrierType barrierType = getFieldStoreBarrierType(storeField); - WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), createFieldLocation(graph, field), barrierType, false)); + WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), createFieldLocation(graph, field), barrierType, storeField.field().getKind() == Kind.Object)); tool.createNullCheckGuard(memoryWrite, object); memoryWrite.setStateAfter(storeField.stateAfter()); graph.replaceFixedWithFixed(storeField, memoryWrite); @@ -564,12 +565,15 @@ LocationNode location = IndexedLocationNode.create(ANY_LOCATION, cas.expected().kind(), cas.displacement(), cas.offset(), graph, 1); cas.setLocation(location); cas.setWriteBarrierType(getCompareAndSwapBarrier(cas)); + if (cas.expected().kind() == Kind.Object) { + cas.setCompress(); + } } else if (n instanceof LoadIndexedNode) { LoadIndexedNode loadIndexed = (LoadIndexedNode) n; GuardingNode boundsCheck = createBoundsCheck(loadIndexed, tool); Kind elementKind = loadIndexed.elementKind(); LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index()); - ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadIndexed.stamp(), WriteBarrierType.NONE, false)); + ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadIndexed.stamp(), WriteBarrierType.NONE, elementKind == Kind.Object)); memoryRead.setGuard(boundsCheck); graph.replaceFixedWithFixed(loadIndexed, memoryRead); } else if (n instanceof StoreIndexedNode) { @@ -600,7 +604,7 @@ } } WriteBarrierType barrierType = getArrayStoreBarrierType(storeIndexed); - WriteNode memoryWrite = graph.add(new WriteNode(array, value, arrayLocation, barrierType, false)); + WriteNode memoryWrite = graph.add(new WriteNode(array, value, arrayLocation, barrierType, elementKind == Kind.Object)); memoryWrite.setGuard(boundsCheck); memoryWrite.setStateAfter(storeIndexed.stateAfter()); graph.replaceFixedWithFixed(storeIndexed, memoryWrite); @@ -609,7 +613,7 @@ UnsafeLoadNode load = (UnsafeLoadNode) n; assert load.kind() != Kind.Illegal; IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, load.accessKind(), load.displacement(), load.offset(), graph, 1); - ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp(), WriteBarrierType.NONE, false)); + ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp(), WriteBarrierType.NONE, (!load.object().isNullConstant() && load.accessKind() == Kind.Object))); // An unsafe read must not floating outside its block as may float above an explicit // null check on its object. memoryRead.setGuard(AbstractBeginNode.prevBegin(load)); @@ -619,7 +623,7 @@ IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, store.accessKind(), store.displacement(), store.offset(), graph, 1); ValueNode object = store.object(); WriteBarrierType barrierType = getUnsafeStoreBarrierType(store); - WriteNode write = graph.add(new WriteNode(object, store.value(), location, barrierType, false)); + WriteNode write = graph.add(new WriteNode(object, store.value(), location, barrierType, store.value().kind() == Kind.Object)); write.setStateAfter(store.stateAfter()); graph.replaceFixedWithFixed(store, write); } else if (n instanceof LoadHubNode) { @@ -672,10 +676,13 @@ value = allocations[commit.getVirtualObjects().indexOf(value)]; } if (!(value.isConstant() && value.asConstant().isDefaultForKind())) { - graph.addBeforeFixed(commit, - graph.add(new WriteNode(newObject, value, createFieldLocation(graph, (HotSpotResolvedJavaField) instance.field(i)), WriteBarrierType.NONE, false))); + WriteNode write = new WriteNode(newObject, value, createFieldLocation(graph, (HotSpotResolvedJavaField) instance.field(i)), WriteBarrierType.NONE, + instance.field(i).getKind() == Kind.Object); + + graph.addBeforeFixed(commit, graph.add(write)); } } + } else { VirtualArrayNode array = (VirtualArrayNode) virtual; ResolvedJavaType element = array.componentType(); @@ -687,8 +694,9 @@ value = allocations[indexOf]; } if (!(value.isConstant() && value.asConstant().isDefaultForKind())) { - graph.addBeforeFixed(commit, - graph.add(new WriteNode(newObject, value, createArrayLocation(graph, element.getKind(), ConstantNode.forInt(i, graph)), WriteBarrierType.NONE, false))); + WriteNode write = new WriteNode(newObject, value, createArrayLocation(graph, element.getKind(), ConstantNode.forInt(i, graph)), WriteBarrierType.NONE, + value.kind() == Kind.Object); + graph.addBeforeFixed(commit, graph.add(write)); } } } @@ -732,7 +740,8 @@ for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.class)) { int size = FrameStateBuilder.stackSlots(osrLocal.kind()); int offset = localsOffset - (osrLocal.index() + size - 1) * 8; - UnsafeLoadNode load = graph.add(new UnsafeLoadNode(buffer, offset, ConstantNode.forInt(0, graph), osrLocal.kind())); + IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, osrLocal.kind(), offset, ConstantNode.forLong(0, graph), graph, 1); + ReadNode load = graph.add(new ReadNode(buffer, location, osrLocal.stamp(), WriteBarrierType.NONE, false)); osrLocal.replaceAndDelete(load); graph.addBeforeFixed(migrationEnd, load); } @@ -854,8 +863,16 @@ return ConstantLocationNode.create(field, field.getKind(), field.offset(), graph); } + public int getScalingFactor(Kind kind) { + if (config.useCompressedOops && kind == Kind.Object) { + return this.graalRuntime.getTarget().arch.getSizeInBytes(Kind.Int); + } else { + return this.graalRuntime.getTarget().arch.getSizeInBytes(kind); + } + } + protected IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index) { - int scale = this.graalRuntime.getTarget().arch.getSizeInBytes(elementKind); + int scale = getScalingFactor(elementKind); return IndexedLocationNode.create(NamedLocationIdentity.getArrayLocation(elementKind), elementKind, getArrayBaseOffset(elementKind), index, graph, scale); } diff -r 7779b1d5ba37 -r 5945a36ccba4 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java Wed Jun 05 14:18:35 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java Wed Jun 05 15:11:58 2013 +0200 @@ -22,7 +22,6 @@ */ package com.oracle.graal.hotspot.replacements; -import static com.oracle.graal.api.meta.LocationIdentity.*; import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import sun.misc.*; @@ -67,7 +66,8 @@ } private static void crypt(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset, boolean encrypt) { - Word kAddr = Word.fromObject(rcvr).readWord(Word.unsigned(kOffset), ANY_LOCATION).add(arrayBaseOffset(Kind.Byte)); + Object kObject = UnsafeLoadNode.load(rcvr, 0, kOffset, Kind.Object); + Word kAddr = (Word) Word.fromObject(kObject).add(arrayBaseOffset(Kind.Byte)); Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset); Word outAddr = Word.unsigned(GetObjectAddressNode.get(out) + arrayBaseOffset(Kind.Byte) + outOffset); if (encrypt) { diff -r 7779b1d5ba37 -r 5945a36ccba4 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java Wed Jun 05 14:18:35 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java Wed Jun 05 15:11:58 2013 +0200 @@ -22,7 +22,6 @@ */ package com.oracle.graal.hotspot.replacements; -import static com.oracle.graal.api.meta.LocationIdentity.*; import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import sun.misc.*; @@ -63,7 +62,7 @@ @MethodSubstitution(isStatic = false) static void encrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { - Object embeddedCipher = Word.fromObject(rcvr).readObject(Word.unsigned(embeddedCipherOffset), ANY_LOCATION); + Object embeddedCipher = UnsafeLoadNode.load(rcvr, 0, embeddedCipherOffset, Kind.Object); if (getAESCryptClass().isInstance(embeddedCipher)) { crypt(rcvr, in, inOffset, inLength, out, outOffset, embeddedCipher, true); } else { @@ -73,7 +72,7 @@ @MethodSubstitution(isStatic = false) static void decrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { - Object embeddedCipher = Word.fromObject(rcvr).readObject(Word.unsigned(embeddedCipherOffset), ANY_LOCATION); + Object embeddedCipher = UnsafeLoadNode.load(rcvr, 0, embeddedCipherOffset, Kind.Object); if (in != out && getAESCryptClass().isInstance(embeddedCipher)) { crypt(rcvr, in, inOffset, inLength, out, outOffset, embeddedCipher, false); } else { @@ -82,8 +81,10 @@ } private static void crypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset, Object embeddedCipher, boolean encrypt) { - Word kAddr = Word.fromObject(embeddedCipher).readWord(Word.unsigned(AESCryptSubstitutions.kOffset), ANY_LOCATION).add(arrayBaseOffset(Kind.Byte)); - Word rAddr = Word.unsigned(GetObjectAddressNode.get(rcvr)).readWord(Word.unsigned(rOffset), ANY_LOCATION).add(arrayBaseOffset(Kind.Byte)); + Object kObject = UnsafeLoadNode.load(embeddedCipher, 0, AESCryptSubstitutions.kOffset, Kind.Object); + Object rObject = UnsafeLoadNode.load(rcvr, 0, rOffset, Kind.Object); + Word kAddr = (Word) Word.fromObject(kObject).add(arrayBaseOffset(Kind.Byte)); + Word rAddr = (Word) Word.fromObject(rObject).add(arrayBaseOffset(Kind.Byte)); Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset); Word outAddr = Word.unsigned(GetObjectAddressNode.get(out) + arrayBaseOffset(Kind.Byte) + outOffset); if (encrypt) { diff -r 7779b1d5ba37 -r 5945a36ccba4 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Wed Jun 05 14:18:35 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Wed Jun 05 15:11:58 2013 +0200 @@ -238,7 +238,7 @@ Kind elementKind = elementType.getKind(); ConstantNode hub = ConstantNode.forConstant(arrayType.klass(), runtime, graph); final int headerSize = HotSpotRuntime.getArrayBaseOffset(elementKind); - int log2ElementSize = CodeUtil.log2(target.arch.getSizeInBytes(elementKind)); + int log2ElementSize = CodeUtil.log2(((HotSpotRuntime) runtime).getScalingFactor(elementKind)); Arguments args = new Arguments(allocateArray); args.add("hub", hub); diff -r 7779b1d5ba37 -r 5945a36ccba4 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java Wed Jun 05 14:18:35 2013 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java Wed Jun 05 15:11:58 2013 +0200 @@ -117,6 +117,36 @@ } } + public static class LoadCompressedOop extends LoadOp { + + private long narrowOopBase; + private int narrowOopShift; + private int logMinObjAlignment; + @Temp({REG}) private AllocatableValue scratch; + + public LoadCompressedOop(Kind kind, AllocatableValue result, AllocatableValue scratch, AMD64AddressValue address, LIRFrameState state, long narrowOopBase, int narrowOopShift, + int logMinObjAlignment) { + super(kind, result, address, state); + this.narrowOopBase = narrowOopBase; + this.narrowOopShift = narrowOopShift; + this.logMinObjAlignment = logMinObjAlignment; + this.scratch = scratch; + } + + @Override + public void emitMemAccess(AMD64MacroAssembler masm) { + switch (kind) { + case Object: + Register resRegister = asRegister(result); + masm.movl(resRegister, address.toAddress()); + decodeOop(masm, resRegister, narrowOopBase, narrowOopShift, logMinObjAlignment); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + } + public static class LoadOp extends MemOp { @Def({REG}) protected AllocatableValue result; @@ -160,6 +190,51 @@ } } + public static class StoreCompressedOop extends AMD64LIRInstruction { + + protected final Kind kind; + private long narrowOopBase; + private int narrowOopShift; + private int logMinObjAlignment; + @Temp({REG}) private AllocatableValue scratch; + @Alive({REG}) protected AllocatableValue input; + @Alive({COMPOSITE}) protected AMD64AddressValue address; + @State protected LIRFrameState state; + + public StoreCompressedOop(Kind kind, AMD64AddressValue address, AllocatableValue input, AllocatableValue scratch, LIRFrameState state, long narrowOopBase, int narrowOopShift, + int logMinObjAlignment) { + this.narrowOopBase = narrowOopBase; + this.narrowOopShift = narrowOopShift; + this.logMinObjAlignment = logMinObjAlignment; + this.scratch = scratch; + this.kind = kind; + this.address = address; + this.state = state; + this.input = input; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + emitMemAccess(tasm, masm); + } + + public void emitMemAccess(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + switch (kind) { + case Object: + masm.movq(asRegister(scratch), asRegister(input)); + encodeOop(masm, asRegister(scratch), narrowOopBase, narrowOopShift, logMinObjAlignment); + if (state != null) { + tasm.recordImplicitException(masm.codeBuffer.position(), state); + } + masm.movl(address.toAddress(), asRegister(scratch)); + // masm.movq(asRegister(scratch), 0xDEADBEEF); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + } + public static class StoreOp extends MemOp { @Use({REG}) protected AllocatableValue input; @@ -205,10 +280,12 @@ public static class StoreConstantOp extends MemOp { protected final Constant input; + private final boolean compress; - public StoreConstantOp(Kind kind, AMD64AddressValue address, Constant input, LIRFrameState state) { + public StoreConstantOp(Kind kind, AMD64AddressValue address, Constant input, LIRFrameState state, boolean compress) { super(kind, address, state); this.input = input; + this.compress = compress; } @Override @@ -239,7 +316,11 @@ throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); case Object: if (input.isNull()) { - masm.movptr(address.toAddress(), 0); + if (compress) { + masm.movl(address.toAddress(), 0); + } else { + masm.movptr(address.toAddress(), 0); + } } else { throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); } @@ -334,6 +415,37 @@ } } + @Opcode("CAS") + public static class CompareAndSwapCompressedOp extends AMD64LIRInstruction { + + @Def protected AllocatableValue result; + @Alive({COMPOSITE}) protected AMD64AddressValue address; + @Alive protected AllocatableValue cmpValue; + @Alive protected AllocatableValue newValue; + @Temp({REG}) protected AllocatableValue scratch; + + private long narrowOopBase; + private int narrowOopShift; + private int logMinObjAlignment; + + public CompareAndSwapCompressedOp(AllocatableValue result, AMD64AddressValue address, AllocatableValue cmpValue, AllocatableValue newValue, AllocatableValue scratch, long narrowOopBase, + int narrowOopShift, int logMinObjAlignment) { + this.narrowOopBase = narrowOopBase; + this.narrowOopShift = narrowOopShift; + this.logMinObjAlignment = logMinObjAlignment; + this.scratch = scratch; + this.result = result; + this.address = address; + this.cmpValue = cmpValue; + this.newValue = newValue; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + compareAndSwapCompressed(tasm, masm, result, address, cmpValue, newValue, scratch, narrowOopBase, narrowOopShift, logMinObjAlignment); + } + } + public static void move(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, Value input) { if (isRegister(input)) { if (isRegister(result)) { @@ -542,4 +654,51 @@ throw GraalInternalError.shouldNotReachHere(); } } + + protected static void compareAndSwapCompressed(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AllocatableValue result, AMD64AddressValue address, AllocatableValue cmpValue, + AllocatableValue newValue, AllocatableValue scratch, long narrowOopBase, int narrowOopShift, int logMinObjAlignment) { + assert asRegister(cmpValue) == AMD64.rax && asRegister(result) == AMD64.rax; + + switch (cmpValue.getKind()) { + case Object: + final Register scratchRegister = asRegister(scratch); + final Register cmpRegister = asRegister(cmpValue); + final Register newRegister = asRegister(newValue); + encodeOop(masm, cmpRegister, narrowOopBase, narrowOopShift, logMinObjAlignment); + masm.movq(scratchRegister, newRegister); + encodeOop(masm, scratchRegister, narrowOopBase, narrowOopShift, logMinObjAlignment); + if (tasm.target.isMP) { + masm.lock(); + } + masm.cmpxchgl(scratchRegister, address.toAddress()); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + private static void encodeOop(AMD64MacroAssembler masm, Register scratchRegister, long narrowOopBase, int narrowOopShift, int logMinObjAlignment) { + if (narrowOopBase == 0) { + if (narrowOopShift != 0) { + assert logMinObjAlignment == narrowOopShift : "Encode algorithm is wrong"; + masm.shrq(scratchRegister, logMinObjAlignment); + } + } else { + masm.subq(scratchRegister, AMD64.r12); + masm.shrq(scratchRegister, logMinObjAlignment); + } + } + + private static void decodeOop(AMD64MacroAssembler masm, Register resRegister, long narrowOopBase, int narrowOopShift, int logMinObjAlignment) { + if (narrowOopBase == 0) { + if (narrowOopShift != 0) { + assert logMinObjAlignment == narrowOopShift : "Decode algorithm is wrong"; + masm.shlq(resRegister, logMinObjAlignment); + } + } else { + masm.shlq(resRegister, logMinObjAlignment); + masm.addq(resRegister, AMD64.r12); + } + } + } diff -r 7779b1d5ba37 -r 5945a36ccba4 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java Wed Jun 05 14:18:35 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java Wed Jun 05 15:11:58 2013 +0200 @@ -24,6 +24,7 @@ import static com.oracle.graal.api.meta.LocationIdentity.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.HeapAccess.WriteBarrierType; import com.oracle.graal.nodes.extended.*; @@ -65,7 +66,7 @@ @Override public void lower(LoweringTool tool, LoweringType loweringType) { IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, value.kind(), displacement, offset, graph(), 1); - WriteNode write = graph().add(new WriteNode(object, value, location, WriteBarrierType.NONE, false)); + WriteNode write = graph().add(new WriteNode(object, value, location, WriteBarrierType.NONE, value.kind() == Kind.Object)); graph().replaceFixedWithFixed(this, write); } } diff -r 7779b1d5ba37 -r 5945a36ccba4 make/build-graal.xml diff -r 7779b1d5ba37 -r 5945a36ccba4 src/share/vm/graal/graalCodeInstaller.cpp --- a/src/share/vm/graal/graalCodeInstaller.cpp Wed Jun 05 14:18:35 2013 +0200 +++ b/src/share/vm/graal/graalCodeInstaller.cpp Wed Jun 05 15:11:58 2013 +0200 @@ -256,7 +256,13 @@ arrayOop values = (arrayOop) VirtualObject::values(value); for (jint i = 0; i < values->length(); i++) { ScopeValue* cur_second = NULL; - ScopeValue* value = get_hotspot_value(((oop*) values->base(T_OBJECT))[i], total_frame_size, objects, cur_second, oop_recorder); + oop object; + if(UseCompressedOops) { + object=oopDesc::decode_heap_oop(((narrowOop*) values->base(T_OBJECT))[i]); + } else { + object=((oop*) (values->base(T_OBJECT)))[i]; + } + ScopeValue* value = get_hotspot_value(object, total_frame_size, objects, cur_second, oop_recorder); if (isLongArray && cur_second == NULL) { // we're trying to put ints into a long array... this isn't really valid, but it's used for some optimizations. @@ -437,9 +443,13 @@ memcpy(_instructions->start(), _code->base(T_BYTE), _code_size); _instructions->set_end(_instructions->start() + _code_size); - oop* sites = (oop*) _sites->base(T_OBJECT); + oop site; for (int i = 0; i < _sites->length(); i++) { - oop site = sites[i]; + if(UseCompressedOops) { + site=oopDesc::decode_heap_oop(((narrowOop*) _sites->base(T_OBJECT))[i]); + } else { + site=((oop*) (_sites->base(T_OBJECT)))[i]; + } jint pc_offset = CompilationResult_Site::pcOffset(site); if (site->is_a(CompilationResult_Call::klass())) { @@ -469,9 +479,13 @@ #ifndef PRODUCT if (_comments != NULL) { - oop* comments = (oop*) _comments->base(T_OBJECT); + oop comment; for (int i = 0; i < _comments->length(); i++) { - oop comment = comments[i]; + if(UseCompressedOops) { + comment=oopDesc::decode_heap_oop(((narrowOop*) _comments->base(T_OBJECT))[i]); + } else { + comment=((oop*) (_comments->base(T_OBJECT)))[i]; + } assert(comment->is_a(HotSpotCompiledCode_Comment::klass()), "cce"); jint offset = HotSpotCompiledCode_Comment::pcOffset(comment); char* text = java_lang_String::as_utf8_string(HotSpotCompiledCode_Comment::text(comment)); @@ -533,7 +547,12 @@ if (_exception_handlers != NULL) { oop* exception_handlers = (oop*) _exception_handlers->base(T_OBJECT); for (int i = 0; i < _exception_handlers->length(); i++) { - oop exc = exception_handlers[i]; + oop exc; + if(UseCompressedOops) { + exc=oopDesc::decode_heap_oop(((narrowOop*) _exception_handlers->base(T_OBJECT))[i]); + } else { + exc=((oop*) (_exception_handlers->base(T_OBJECT)))[i]; + } jint pc_offset = CompilationResult_Site::pcOffset(exc); jint handler_offset = CompilationResult_ExceptionHandler::handlerPos(exc); @@ -605,8 +624,12 @@ for (jint i = 0; i < values->length(); i++) { ScopeValue* second = NULL; - oop value = ((oop*) values->base(T_OBJECT))[i]; - + oop value; + if(UseCompressedOops) { + value=oopDesc::decode_heap_oop(((narrowOop*) values->base(T_OBJECT))[i]); + } else { + value = ((oop*) values->base(T_OBJECT))[i]; + } if (i < local_count) { ScopeValue* first = get_hotspot_value(value, _total_frame_size, objects, second, _oop_recorder); if (second != NULL) { @@ -625,10 +648,15 @@ if (second != NULL) { i++; assert(i < values->length(), "double-slot value not followed by Value.ILLEGAL"); - assert(((oop*) values->base(T_OBJECT))[i] == Value::ILLEGAL(), "double-slot value not followed by Value.ILLEGAL"); + if(UseCompressedOops) { + assert(oopDesc::decode_heap_oop(((narrowOop*) values->base(T_OBJECT))[i]) == Value::ILLEGAL(), "double-slot value not followed by Value.ILLEGAL"); + } else { + assert(((oop*) values->base(T_OBJECT))[i] == Value::ILLEGAL(), "double-slot value not followed by Value.ILLEGAL"); + } } } + _debug_recorder->dump_object_pool(objects); DebugToken* locals_token = _debug_recorder->create_scope_values(locals); diff -r 7779b1d5ba37 -r 5945a36ccba4 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Wed Jun 05 14:18:35 2013 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Wed Jun 05 15:11:58 2013 +0200 @@ -831,6 +831,12 @@ set_int("vmIntrinsicLinkToSpecial", vmIntrinsics::_linkToSpecial); set_int("vmIntrinsicLinkToInterface", vmIntrinsics::_linkToInterface); + set_boolean("useCompressedOops", UseCompressedOops); + set_boolean("useCompressedKlassPointers", UseCompressedKlassPointers); + set_address("narrowOopBase", Universe::narrow_oop_base()); + set_int("narrowOopShift", Universe::narrow_oop_shift()); + set_int("logMinObjAlignment", LogMinObjAlignmentInBytes); + set_int("g1CardQueueIndexOffset", in_bytes(JavaThread::dirty_card_queue_offset() + PtrQueue::byte_offset_of_index())); set_int("g1CardQueueBufferOffset", in_bytes(JavaThread::dirty_card_queue_offset() + PtrQueue::byte_offset_of_buf())); set_int("logOfHRGrainBytes", HeapRegion::LogOfHRGrainBytes); diff -r 7779b1d5ba37 -r 5945a36ccba4 src/share/vm/graal/graalCompilerToVM.hpp --- a/src/share/vm/graal/graalCompilerToVM.hpp Wed Jun 05 14:18:35 2013 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.hpp Wed Jun 05 15:11:58 2013 +0200 @@ -54,7 +54,12 @@ oop next_arg(BasicType expectedType) { assert(_index < _args->length(), "out of bounds"); - oop arg = ((oop*) _args->base(T_OBJECT))[_index++]; + oop arg; + if(UseCompressedOops) { + arg = oopDesc::decode_heap_oop(((narrowOop*) _args->base(T_OBJECT))[_index++]); + } else { + arg = ((oop*) _args->base(T_OBJECT))[_index++]; + } assert(expectedType == T_OBJECT || java_lang_boxing_object::is_instance(arg, expectedType), "arg type mismatch"); return arg; } diff -r 7779b1d5ba37 -r 5945a36ccba4 src/share/vm/oops/klass.hpp --- a/src/share/vm/oops/klass.hpp Wed Jun 05 14:18:35 2013 +0200 +++ b/src/share/vm/oops/klass.hpp Wed Jun 05 15:11:58 2013 +0200 @@ -148,10 +148,7 @@ Klass* _primary_supers[_primary_super_limit]; // java/lang/Class instance mirroring this class oop _java_mirror; -#ifdef GRAAL - // com/oracle/graal/hotspot/HotSpotResolvedObjectType mirroring this class - oop _graal_mirror; -#endif + // Superclass Klass* _super; // First subclass (NULL if none); _subklass->next_sibling() is next one @@ -252,12 +249,6 @@ oop java_mirror() const { return _java_mirror; } void set_java_mirror(oop m) { klass_oop_store(&_java_mirror, m); } -#ifdef GRAAL - // Graal mirror - oop graal_mirror() const { return _graal_mirror; } - void set_graal_mirror(oop m) { oop_store((oop*) &_graal_mirror, m); } -#endif - // modifier flags jint modifier_flags() const { return _modifier_flags; } void set_modifier_flags(jint flags) { _modifier_flags = flags; } @@ -317,7 +308,6 @@ static ByteSize layout_helper_offset() { return in_ByteSize(offset_of(Klass, _layout_helper)); } static ByteSize access_flags_offset() { return in_ByteSize(offset_of(Klass, _access_flags)); } #ifdef GRAAL - static ByteSize graal_mirror_offset() { return in_ByteSize(offset_of(Klass, _graal_mirror)); } static ByteSize next_sibling_offset() { return in_ByteSize(offset_of(Klass, _next_sibling)); } static ByteSize subklass_offset() { return in_ByteSize(offset_of(Klass, _subklass)); } #endif diff -r 7779b1d5ba37 -r 5945a36ccba4 src/share/vm/prims/unsafe.cpp --- a/src/share/vm/prims/unsafe.cpp Wed Jun 05 14:18:35 2013 +0200 +++ b/src/share/vm/prims/unsafe.cpp Wed Jun 05 15:11:58 2013 +0200 @@ -174,17 +174,27 @@ OrderAccess::release_store_fence((volatile type_name*)index_oop_from_field_offset_long(p, offset), x); // Macros for oops that check UseCompressedOops - +#ifndef GRAAL #define GET_OOP_FIELD(obj, offset, v) \ - oop p = JNIHandles::resolve(obj); \ - oop v; \ - if (UseCompressedOops) { \ + oop p = JNIHandles::resolve(obj); \ + oop v; \ + if (UseCompressedOops) { \ narrowOop n = *(narrowOop*)index_oop_from_field_offset_long(p, offset); \ - v = oopDesc::decode_heap_oop(n); \ - } else { \ - v = *(oop*)index_oop_from_field_offset_long(p, offset); \ + v = oopDesc::decode_heap_oop(n); \ + } else { \ + v = *(oop*)index_oop_from_field_offset_long(p, offset); \ } - +#else +#define GET_OOP_FIELD(obj, offset, v) \ + oop p = JNIHandles::resolve(obj); \ + oop v; \ + if (UseCompressedOops && p!=NULL && offset>=oopDesc::header_size()) { \ + narrowOop n = *(narrowOop*)index_oop_from_field_offset_long(p, offset); \ + v = oopDesc::decode_heap_oop(n); \ + } else { \ + v = *(oop*)index_oop_from_field_offset_long(p, offset); \ + } +#endif // Get/SetObject must be special-cased, since it works with handles.